Lifecycle ignore tags on aws_instance does not ignore root_block_device tags

Hi All,
I have created and AWS EC2 instance using the terraform aws_instance resource. We have a managed service provider in AWS that takes care of managing the instances for us (i.e patching, etc). To perform this, the MSP places tags on the resource which are used in their automated processes. I have added the following to the resource definition in TF :
lifecycle {
prevent_destroy = true
ignore_changes = [
tags,
]
}

when I run terraform plan, I see the following :

root_block_device {
~ tags = {
“Name” = “S-AX-SQL-01_C_DRIVE”
- “xx:lifeline:lastBackupDate” = “2024-05-08T09:00:46” → null
}
# (10 unchanged attributes hidden)
}

even though I told the lifecycle to ignore tags in the aws_instance resource, that does not seem to get applied to the root block EBS volume. I have created other EBS volumes for this instance and have added the ignore tags lifecycle to them (which works fine), but since I do not explicitly create the EBS volume for the root block device, it does not inherit that lifecycle from the instance resource.

This causes unwanted updates to our instance every time a terraform apply is run. Is there a way for the root block device to inherit the lifecycle rules of the instance, or is there a way to create an EBS volume separately and tell the instance resource to use that as the root block device?

Hi @mesmeraldo,

ignore_changes = [tags] means to ignore the top-level tags attribute of the EC2 instance itself. That path doesn’t match the tags attribute nested inside the root_block_device block.

Specifying to ignore the nested attribute unfortunately requires understanding some details of how the provider models that nested block. Specifically, you’d need to know what kind of expression you’d need to write if you wanted to refer to the nested tags in some other expression in your module, because ignore_changes uses similar syntax elements.

To answer that, I ran terraform providers schema -json in a configuration that uses the hashicorp/aws provider, and then found the schema definition for the root_block_device block type, which starts like this:

              ...
              "root_block_device": {
                "nesting_mode": "list",
                "block": {
                  "attributes": {
                    ...

This tells me that root_block_device is treated by the provider as a list of objects. Since an EC2 instance always has a root block device, I think we can assume that this list will always have one element describing that single block device.

Given that, the ignore_changes setting for this would be:

  ignore_changes = [
    tags, # (assuming you still want to ignore the instance-level tags)
    root_block_device[0].tags,
  ]

The second path here specifies the tags attribute of the first (“zeroth”) element of the root_block_device list, which should therefore match the value shown as changing in the diff you shared.

The above is a direct answer to your question, but there’s also a more general way to solve this using an AWS provider feature…


For the AWS provider in particular you may not need to use ignore_changes for this at all, because the provider offers its own feature to ignore specific tag keys globally across all resource instances managed by a particular provider configuration.

If you want to use this method then you would include an ignore_tags block in your provider "aws" block:

provider "aws" {
  # ...
  ignore_tags {
    keys = ["xx:lifeline:lastBackupDate"]
  }
  # ...
}

Alternatively, if your organization has a tagging scheme were you use a specific prefix for all tag keys that are expected to be managed outside of Terraform, you could write a general configuration for all keys with that prefix:

provider "aws" {
  # ...
  ignore_tags {
    # Assuming that "xx:lifeline:" is a prefix
    # that denotes "managed by something outside
    # of Terraform".
    key_prefixes = ["xx:lifeline:"]
  }
  # ...
}

When you set one of these options, the AWS provider should effectively pretend that any tags matching your selection don’t exist at all as far as Terraform is concerned, without you having to specify this separately in each resource block.

There’s more detail on this option in ignore_tags configuration block from the AWS provider documentation.

@apparentlymart Thank you so much for the explanation. I used the first method and it worked as described. I am more interested in the second answer (at the provider level) as that would allow for all our managed service provider tags regardless of resource.

Thanks again for you help.