Ignore AMI Changes
Adds ignore_changes = [ami, image_id] to EC2 instances. Prevents Terraform from replacing instances when a newer AMI is published.
When to use this rule
Use this when: Your EC2 instances use data.aws_ami lookups that resolve to new AMI IDs when AWS publishes updates, and you manage AMI updates separately (Systems Manager, AMI pipelines, or blue-green deployments).
Do not use this when: You want Terraform to replace instances when a new AMI is available. Or you use a fixed AMI ID rather than a data source lookup.
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 |
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 |
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
Before and after
Before (upstream module):
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.
Real-world scenario
AWS published a new Amazon Linux 2 AMI on a Tuesday. Wednesday morning, terraform plan proposed replacing 12 production EC2 instances, which would have caused 15 minutes of downtime per instance during business hours.
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.
Compliance framework support
This rule is not a compliance control. It supports these framework objectives as an operational safeguard:
| Framework | Controls | Role |
|---|---|---|
| SOC 2 | CC7.1 | Supports change management by preventing unplanned instance replacements |
Default configuration
These are the values the rule ships with. They are not settable from a module source URL: ?rules= carries rule names only, so a per-request enable uses exactly the defaults below. Your organization sets them per rule, in its Baseline or in a ruleset, from the Operational Rules page; see Baseline rules and rulesets.
| 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 |
How to enable
On a framework host, per request:
Add ?rules=lifecycle_ignore_ami_changes to your HTTPS module source. Use the full namespaced id. A bare lifecycle_ignore_ami_changes matches no rule: it is skipped server-side and your terraform init still succeeds, without the rule.
module "example" {
source = "https://soc2.compliance.tf/terraform-aws-modules/s3-bucket/aws?version=5.0.0&rules=lifecycle_ignore_ami_changes"
}On your organization's host:
Add the rule to the organization's Baseline, which applies to every module served from the bare organization form <alias>.compliance.tf/<namespace>/<name>/<provider>, or to a named ruleset that one module selects with ?ruleset=<name> on the HTTPS form of that address. A project environment (<alias>.compliance.tf/<project>/<env>/<module>) serves the rules frozen in its bound snapshot instead: there the rule goes into the config draft and reaches the environment by promotion. On both organization forms ?rules= is refused with a 400 β including the subtractive - prefix β rather than dropped, so you cannot mistake an ignored override for an applied one. Change the configuration, not the URL. See Baseline rules and rulesets for the configuration flow, and registry resolution for how the address forms differ.
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. |
Terraform and OpenTofu compatible
This rule works with both Terraform (1.x+) and OpenTofu (1.6+). It reads ordinary HCL, and anything it changes stays ordinary HCL, so the module behaves the same under either tool.
Help us improve this page
Operational Rules are a new feature. We'd love your feedback on this rule page β what's useful, what's missing, what's confusing. Share feedback.