Problem
When migrating an AWS WAFv2 WebACL from referencing an IPSet to a Rule Group in a single Terraform apply, the operation may fail with the following error. This occurs because Terraform attempts to delete the IPSet before the WebACL has been updated to stop referencing it.
WAFAssociatedItemException: AWS WAF couldn’t perform the operation because your resource is being used...
Cause
Terraform calculates the dependency graph and determines that the old IPSet resource is no longer needed and should be destroyed. Simultaneously, it plans to update the WebACL to reference the new Rule Group. However, the AWS API prevents the deletion of an IPSet while it is still associated with a WebACL. The timing of the API calls during terraform apply leads to this conflict, as the deletion is attempted before the association is removed.
Solutions
There are two primary approaches to perform this migration successfully.
Solution 1: Two-Step Migration
This approach separates the migration into two distinct terraform apply operations to avoid the resource conflict.
Current Configuration:
Your initial configuration may look similar to this, with the WebACL directly referencing the IPSet.
resource "aws_wafv2_ip_set" "test_ipset" {
name = "test-ipset"
scope = "REGIONAL"
# ...
}
resource "aws_wafv2_web_acl" "test_acl" {
name = "test-acl"
scope = "REGIONAL"
# ...
rule {
# ...
statement {
ip_set_reference_statement {
arn = aws_wafv2_ip_set.test_ipset.arn
}
}
}
}Procedure:
-
First Apply: Update the WebACL Reference
Modify the
aws_wafv2_web_aclresource to reference the newaws_wafv2_rule_groupinstead of theIPSet. Keep theaws_wafv2_ip_setresource in your configuration for this step. Runterraform apply.# Keep the IPSet resource during the first apply. resource "aws_wafv2_ip_set" "test_ipset" { name = "test-ipset" scope = "REGIONAL" # ... } resource "aws_wafv2_rule_group" "test_rg" { name = "test-rule-group" scope = "REGIONAL" # ... } # Update the WebACL to reference the Rule Group. resource "aws_wafv2_web_acl" "test_acl" { name = "test-acl" scope = "REGIONAL" # ... rule { # ... statement { rule_group_reference_statement { arn = aws_wafv2_rule_group.test_rg.arn } } } } -
Second Apply: Remove the IPSet
After the first apply succeeds, the
WebACLno longer has an association with theIPSet. You can now safely remove theaws_wafv2_ip_setresource from your configuration and runterraform applyagain. Terraform will cleanly delete the orphanedIPSet.
Solution 2: Use the lifecycle Meta-Argument
For automated CI/CD pipelines or large-scale deployments, you can use the lifecycle meta-argument with prevent_destroy = true to protect the IPSet from premature deletion during the transition.
Procedure:
-
Add
prevent_destroyand Update the WebACLAdd a
lifecycleblock to theaws_wafv2_ip_setresource. At the same time, update theWebACLto reference the newRule Groupand remove theIPSetreference from the configuration. Runterraform apply.resource "aws_wafv2_ip_set" "test_ipset" { name = "test-ipset" scope = "REGIONAL" # ... lifecycle { prevent_destroy = true } }Terraform will attempt to destroy the
IPSet, but thelifecycleblock will prevent it and produce an error, while still successfully updating theWebACLassociation. This error is expected and can be ignored for this step. -
Remove
prevent_destroyand the IPSetIn a subsequent commit or module version, remove the entire
aws_wafv2_ip_setresource, including thelifecycleblock. Runterraform apply. Since theWebACLassociation is already removed, Terraform can now successfully destroy theIPSet.