Fix ignore_changes tags reset by another tag with an empty value#48008
Conversation
…branch When the SDK v2 transparent tagging interceptor's Finally/Update branch runs (because tags_all is not wholly known in the plan, e.g. when a tag value is set to an empty string and setTagsAll marks tags_all Computed), it rebuilt the desired tag map from d.GetRawConfig(). That returns the literal user configuration, in which lifecycle.ignore_changes has not yet been applied. The resulting UpdateTags call then included any ignored tag with the value the user wrote, overwriting out-of-band changes the lifecycle block was meant to preserve. Read the desired tags from d.GetRawPlan() instead, falling back to the raw config only when the plan's tags attribute is itself not wholly known (the unknown-references scenario the Finally branch was originally designed for). The Before/Update branch is unchanged, so the common case (no empty-string tag values) is unaffected. Update the unit-test mock plan to include the tags attribute alongside tags_all so it more accurately reflects what real plans look like. See #48007
Adds TestAccEC2Instance_tagsIgnoreChangesEmptyValue, which reproduces
the issue where a tag listed in lifecycle.ignore_changes was overwritten
on AWS when an unrelated tag in the same map was updated to an empty
string. The test exercises both the working case (Step changed to a
non-empty value, where ignore_changes is honored) and the bug case
(Step changed to an empty string), asserting the externally modified
stagingState tag value via a direct EC2 API check rather than only the
Terraform state.
Also adds two helpers used by the test:
- overrideInstanceTag: simulates an out-of-band tag modification.
- testAccCheckInstanceAPITagValue: verifies a tag value via the EC2
DescribeInstances API to detect cases where the provider has
overwritten an externally-modified tag despite ignore_changes.
See #48007
Community GuidelinesThis comment is added to every new Pull Request to provide quick reference to how the Terraform AWS Provider is maintained. Please review the information below, and thank you for contributing to the community that keeps the provider thriving! 🚀 Voting for Prioritization
Pull Request Authors
|
ignore_changes tags reset with empty value
ignore_changes tags reset with empty valueignore_changes tags reset by another tag with an empty value
|
Warning This Issue has been closed, meaning that any additional comments are much easier for the maintainers to miss. Please assume that the maintainers will not see them. Ongoing conversations amongst community members are welcome, however, the issue will be locked after 30 days. Moving conversations to another venue, such as the AWS Provider forum, is recommended. If you have additional concerns, please open a new issue, referencing this one where needed. |
|
@jar-b Thank you! |
|
This functionality has been released in v6.47.0 of the Terraform AWS Provider. Please see the Terraform documentation on provider versioning or reach out if you need any assistance upgrading. For further feature requests or bug reports with this functionality, please create a new GitHub issue following the template. Thank you! |
Rollback Plan
If a change needs to be reverted, we will publish an updated version of the library.
Changes to Security Controls
Are there any changes to security controls (access controls, encryption, logging) in this pull request? If so, explain.
Description
This fix impacts all plugin SDK resources with tags. It was reported for
aws_instanceand so I added the repro/regression acceptance test toec2_instance_test.go. For good measure, I also ran acceptances for SNS, Secrets Manager, and CloudWatch.Fixes a bug where
lifecycle.ignore_changeson individualtagselements (tags["k"]) was bypassed when another tag in the same map was updated to an empty string. The ignored tag's value from the user's configuration was sent to AWS duringUpdate, overwriting any out-of-band changes the lifecycle block was meant to preserve.Root cause is in the SDK v2 transparent tagging interceptor (
internal/provider/sdkv2/tags_interceptor.go):setTagsAllmarkstags_allas Computed whenever the tags map contains an empty-string value (KeyValueTags.HasZeroValue()).tags_allnot wholly known in the plan, theBefore/Updatebranch (which usesd.GetChange(tags_all)and is plan-aware) is skipped.Finally/Updatebranch ran instead and rebuilt the desired tag map fromd.GetRawConfig()— the literal user configuration, in whichlifecycle.ignore_changesis not applied. The resultingUpdateTagscall therefore included every tag the user wrote, including ignored ones.The fix reads the desired tags from
d.GetRawPlan()(where Terraform Core has already appliedignore_changes) and falls back tod.GetRawConfig()only when the plan'stagsattribute is itself not wholly known — preserving prior behavior for the unknown-references scenario theFinallybranch was originally designed for. TheBefore/Updatebranch is unchanged, so the common case (no empty-string tag values) is unaffected.A full root-cause walkthrough lives in the issue: see issue #48007.
Relations
Closes #48007
References
internal/provider/framework/tags_interceptor.go) does not have this bug; it already readstags_allfromrequest.Plan.GetAttribute(...).ignore_tagsblock (a different mechanism with a different documented contract).Output from Acceptance Testing
Before changes
After changes
Regression testing