How can I add a tag to AWS EBS when creating through EC2 with Terraform?

Viewed 2956

I'm trying to create an EC2 instance for a TEST environment, which uses an AMI of PROD. Everything is creating correctly, but I can't add figure out how to add tags to the EBS volumes that are created along with it?

The tags work on the EC2 but don't get applied to the EBS or root volume. I tried adding a tag map on those as well but that was invalid. Any ideas?

provider "aws" {
  region = "us-east-1"
}

data "aws_ami" "existing_sft_ami" {
  most_recent = true

  filter {
    name   = "name"
    values = [var.prod_name]
  }
  owners = [
    var.aws_account_id]
}

data "aws_subnet" "subnet" {
  id = var.aws_subnet_id
}

resource "aws_instance" "sftp" {
  ami           = data.aws_ami.existing_sft_ami.id
  instance_type = "t2.micro"
  availability_zone = var.availability_zone
  subnet_id = data.aws_subnet.subnet.id
  key_name = var.ssh_key_name
  vpc_security_group_ids = [var.aws_security_group_id]
  root_block_device {
    delete_on_termination = true
  }
  ebs_block_device {
    device_name = "/dev/sdb"
    delete_on_termination = true
  }
  tags = {
    Name = var.name
    Owner = var.owner
    Created = formatdate("DD MMM YYYY hh:mm ZZZ", timestamp())
    Environment = "TEST"
  }
}
2 Answers

You need to use the additional volume_tags argument to tag the volumes. Also, to make your code a little more DRY, you can do this with a locals block.

locals {
    tags = {
        Name = var.name
        Owner = var.owner
        Created = formatdate("DD MMM YYYY hh:mm ZZZ", timestamp())
        Environment = var.environment
    }
}

resource "aws_instance" "sftp" {
  ami           = data.aws_ami.existing_sft_ami.id
  instance_type = "t2.micro"
  availability_zone = var.availability_zone
  subnet_id = data.aws_subnet.subnet.id
  key_name = var.ssh_key_name
  vpc_security_group_ids = [var.aws_security_group_id]
  root_block_device {
    delete_on_termination = true
  }
  ebs_block_device {
    device_name = "/dev/sdb"
    delete_on_termination = true
  }
  tags = local.tags
  volume_tags = local.tags
}

You can add tags attributes to root_block_device and ebs_block_device as well, that will give you more control in case you don't want to apply the same set of tags to all your block devices (which volume_tags will do).

E.g.:

provider "aws" {
  region = "us-east-1"
}

data "aws_ami" "existing_sft_ami" {
  most_recent = true

  filter {
    name   = "name"
    values = [var.prod_name]
  }
  owners = [
    var.aws_account_id]
}

data "aws_subnet" "subnet" {
  id = var.aws_subnet_id
}

resource "aws_instance" "sftp" {
  ami           = data.aws_ami.existing_sft_ami.id
  instance_type = "t2.micro"
  availability_zone = var.availability_zone
  subnet_id = data.aws_subnet.subnet.id
  key_name = var.ssh_key_name
  vpc_security_group_ids = [var.aws_security_group_id]
  root_block_device {
    delete_on_termination = true
    tags = {
      Name = "${var.name}-root-volume"
      Owner = var.owner
      Created = formatdate("DD MMM YYYY hh:mm ZZZ", timestamp())
      Environment = "TEST"
    }
  }
  ebs_block_device {
    device_name = "/dev/sdb"
    delete_on_termination = true
    tags = {
      Name = "${var.name}-secondary-volume"
      Owner = var.owner
      Created = formatdate("DD MMM YYYY hh:mm ZZZ", timestamp())
      Environment = "TEST"
    }
  }
  tags = {
    Name = var.name
    Owner = var.owner
    Created = formatdate("DD MMM YYYY hh:mm ZZZ", timestamp())
    Environment = "TEST"
  }
}

Like @ben-whaley said, you can avoid some repetition by defining the common set of tags as a local variable - you can combine these with tags specific to your block device using merge, as follows:

  tags = merge(local.tags, {
    Name = "${var.name}-secondary-volume"
  })

Note that there's a bug in the AWS provider for Terraform that makes it impossible to update tags on any ebs_block_device once the instance has been created -- updating tags on the root_block_device works fine.

Related