Ignore AMI changes
For platform engineers deciding whether to apply lifecycle_ignore_ami_changes: what it changes, how to enable it, and how to check it worked.
Adds ignore_changes = [ami, image_id] to EC2 instances. Prevents Terraform from replacing instances when a newer AMI is published.
What this rule does
Adds a lifecycle { ignore_changes = [...] } block to each matching resource. Terraform and OpenTofu will ignore external changes to the listed attributes on subsequent plans.
Ignored attributes: ami, image_id
Affected resources
| Resource | Service | Why |
|---|---|---|
aws_instance | Amazon EC2 | ami is a ForceNew attribute; changes trigger instance replacement |
aws_launch_template | EC2 Launch Templates | image_id changes trigger new template versions |
Before and after
Before (a module without the change):
resource "aws_instance" "this" {
# ... resource configuration ...
tags = var.tags
}After (with Ignore AMI changes applied):
resource "aws_instance" "this" {
# ... resource configuration ...
tags = var.tags
lifecycle {
ignore_changes = [ami, image_id]
}
}The only change is the rule transformation. All existing arguments, outputs, and module behavior remain identical.
The example above is illustrative. To see this rule run for real, open it in the
Rules Playground: it applies lifecycle_ignore_ami_changes to a
reviewed upstream module that declares the resources this rule targets, and
shows the diff the registry would serve. No account needed.
Why this rule exists
Many Terraform configurations use data.aws_ami lookups to find the latest AMI matching a set of filters. When AWS publishes a new AMI, the data source resolves to a different ID on the next plan. Because ami is a ForceNew attribute on aws_instance, Terraform plans to destroy and recreate the instance.
In production, unexpected instance replacement causes downtime. Teams that manage AMI updates through patching pipelines or blue-green deployments need Terraform to leave the ami attribute alone after creation.
Related Terraform and OpenTofu issues
| Repository | Issue | Title |
|---|---|---|
| hashicorp/terraform | #27360 | A method to override configuration and meta arguments within a module |
| hashicorp/terraform | #21546 | Passing ignore_changes into a module |
Limitations this rule answers
Per-module pages under Workarounds where this rule is the answer, each with the native workaround first and the diff the rule makes:
Default configuration
These are the values the rule ships with. Parameters never travel in a module source URL, so a rule named there runs with exactly these defaults. Your organization sets them per rule, in its Baseline or in a ruleset.
| Parameter | Type | Default | Description |
|---|---|---|---|
ignore_changes | list(string) | ["ami", "image_id"] | Lifecycle attributes to ignore |
resource_types | list(string) | ["aws_instance", "aws_launch_template"] | Target resource type patterns |
The HCL this rule is written in, with its parameters and the transformers it runs, is published at lifecycle_ignore_ami_changes.
How to enable
On a framework host, add the rule on top of your organization's Baseline with ?add_rules= in the HTTPS module source:
module "ec2_instance" {
source = "https://soc2.compliance.tf/terraform-aws-modules/ec2-instance/aws?version=x.y.z&add_rules=lifecycle_ignore_ami_changes"
}On your organization's host, an org admin adds the rule to the Baseline, which reaches every module served from that host, or to a named ruleset that a module selects with ?ruleset=:
module "ec2_instance" {
source = "https://bobthecorp.compliance.tf/terraform-aws-modules/ec2-instance/aws?version=x.y.z&ruleset=<ruleset-name>"
}Replace x.y.z with the release you use and bobthecorp with your organization's alias. Which parameters each host accepts, and which it refuses with a 400, is on Rulesets in the console.
How to check it worked
Read compliancetf-manifest.json in the module you received. Its entry for this rule carries an outcome: enforced means the change was made, not_applicable means nothing matched - no resource of a targeted type, or the module already carried the identical change. Do not infer enforcement from a successful terraform init; a rule that changes nothing also inits cleanly.
Known limits
- Does not cover
aws_launch_configuration(deprecated) or ECS task image references. - Does not prevent AMI-related changes on Auto Scaling Groups or Spot Fleet requests.
- The
ignore_changeslist is not split per resource type: bothamiandimage_idare written to every targeted resource. Neither type accepts both —aws_instancehas noimage_id,aws_launch_templatehas noami— and Terraform rejects anignore_changesentry naming an attribute a resource does not have, so the module failsterraform validate. Check the rule against a copy of your module before adopting it. - Only
.tfand.tofufiles are read. Modules written in JSON syntax (.tf.json,.tofu.json) are left untouched. - Only the module's own directory and its first-level
modules/*submodules are processed. Modules that this module calls by source URL are separate downloads and are handled on their own request. - Works with Terraform 1.x and OpenTofu 1.6 and later. The rule reads ordinary HCL, and anything it changes stays ordinary HCL.
Failure modes
| Scenario | Result |
|---|---|
| Instance needs a critical AMI security patch | You are responsible for updating the AMI through your patching pipeline. Terraform will not trigger a replacement automatically. |
| AMI data source is removed from config | The ignore_changes block remains but has no practical effect if the ami attribute is now a static value. |
Related
- EC2 instance workarounds
- Ignore tag changes
- Ignore autoscaling changes
- Rulesets in the console - where an org admin adds this rule to the Baseline or a ruleset
- Rule catalog - every rule, with what each one changes