hashicorp / terraform-provider-aws

The AWS Provider enables Terraform to manage AWS resources.
https://registry.terraform.io/providers/hashicorp/aws
Mozilla Public License 2.0
9.83k stars 9.17k forks source link

Rename WAF rule fails with `WAFReferencedItemException` #8410

Open ghost opened 5 years ago

ghost commented 5 years ago

This issue was originally opened by @gasi as hashicorp/terraform#21069. It was migrated here as a result of the provider split. The original body of the issue is below.


Community Note

Terraform Version

> terraform --version
Terraform v0.11.13
+ provider.aws v2.6.0
+ provider.template v2.1.1

Affected Resource(s)

Expected Behavior

Actual Behavior

Error: Error applying plan:

1 error(s) occurred:

* module.vines_waf.aws_wafregional_byte_match_set.foo (destroy): 1 error(s) occurred:

* aws_wafregional_byte_match_set.foo: Error deleting ByteMatchSet: WAFReferencedItemException: This entity is still referenced by other entities.
    status code: 400, request id: <redacted>

Steps to Reproduce

  1. Create WAF resources:
resource "aws_wafregional_rule" "foo_parent" {
  name        = "${var.environment}foo_parent"
  metric_name = "${var.environment}foo_parent"

  # predicate whose `name` we change
  predicate {
    data_id = "${aws_wafregional_byte_match_set.foo.id}"
    negated = false
    type = "ByteMatch"
  }
}

resource "aws_wafregional_byte_match_set" "foo" {
  name = "${var.environment}-foo"

  byte_match_tuples {
    text_transformation = "LOWERCASE"
    target_string = "bar"
    positional_constraint = "CONTAINS"
    field_to_match {
      type = "URI"
    }
  }
}
  1. Run terraform apply

  2. Change name of foo to bar:

  name = "${var.environment}-bar"
  1. Run terraform apply again

Important Factoids

References

mxlan commented 5 years ago

I've encountered this same issue,

It appears that the resource or provider is not respecting the WAF relationships and doesn't attempt to perform the necessary actions in the correct order.

It outputs the plan to change the rule / or acl, and destroy and recreate the condition / rule.

Normally if you do that you need to create the new rule / condition first, then modify the rule / acl, and finally delete the old condition / rule (it seems to have reversed these last two steps). It doesn't seem like that terraform sticks to that order of operations.

Are there any workarounds? using a "depends_on" block doesn't appear to work. Ah, okay I'll need to use create_before_destroy. Though this will help if a resource is renamed but will not help resolve the case in which you remove a resource and create a new resource reference, the new resource will be created but deletion of the old resource will be attempted before the rule/acl modification happens. I've had to manually modify the rule/acl to remove the reference before running the apply.

Provider versions: 1.6 & 2.7, haven't tried all the others in between but I'm assuming they all experience the same issue.

jsmigovsky commented 4 years ago

To destroy a rule I had to manually go into the console and remove the association between the ACL and the Rule. Not an ideal course of action, but running terraform apply is no longer chocking on this association.

rdelcampog commented 4 years ago

I'm experimenting the same issue:

  # aws_wafregional_ipset.blacklist will be destroyed
  - resource "aws_wafregional_ipset" "blacklist" {
      - arn  = "xxxxxxxxxx" -> null
      - id   = "e15c39cd-fc2f-4510-aa02-a4a3fdf9e1a0" -> null
      - name = "xxxxxxxxxx" -> null

      - ip_set_descriptor {
          - type  = "IPV4" -> null
          - value = "xxxxxxxxxx" -> null
        }
    }

  # aws_wafregional_rule.blacklist will be destroyed
  - resource "aws_wafregional_rule" "blacklist" {
      - arn         = "xxxxxxxxxx" -> null
      - id          = "xxxxxxxxxx" -> null
      - metric_name = "genericdetectblacklistedips" -> null
      - name        = "xxxxxxxxxx" -> null
      - tags        = {} -> null

      - predicate {
          - data_id = "e15c39cd-fc2f-4510-aa02-a4a3fdf9e1a0" -> null
          - negated = false -> null
          - type    = "IPMatch" -> null
        }
    }

  # aws_wafregional_web_acl.wafregional_acl will be updated in-place
  ~ resource "aws_wafregional_web_acl" "wafregional_acl" {
     ...
      - rule {
          - priority = 1 -> null
          - rule_id  = "9e9f157b-ec2c-4be7-a1fe-1d877c8505a4" -> null
          - type     = "REGULAR" -> null

          - action {
              - type = "DENY" -> null
            }
        }
    }

After running terraform apply:

Error: Error deleting ByteMatchSet: WAFReferencedItemException: This entity is still referenced by other entities.
    status code: 400, request id: c4fe0a4c-efc1-48a1-a9ea-c39889106e19

Terraform is not removing the WAF ACL rule after trying to remove the rule.

voycey commented 4 years ago

Any updates on this - this is unusable right now

blang commented 4 years ago

For me this involved the association between aws_wafregional_rule and aws_wafregional_web_acl, where the rule is destroyed before the web_acl is changed. I solved this temporarily by forcing the web_acl to be recreated when rules change. E.g.:

resource "random_pet" "acl_name" {
  separator = "-"
  length    = 2

  keepers = { # Create string from your rules }
}

resource "aws_wafregional_web_acl" "default" {
  name        = format("%s-%s", var.name, random_pet.acl_name.id)
  ...
}
headlessme commented 4 years ago

This is causing us some pain – did anyone find a workaround that doesn't involve any manual steps?

ghost commented 3 years ago

Can confirm, this is still an issue in 0.14.3 but for aws_wafv2_rule_group.

sam-sbl commented 2 years ago

I just hit this issue today. A simple lifecycle block on the aws_wafregional_rule seems to have done the trick:

 lifecycle {
    create_before_destroy = true
  }