3
votes

The resource aws_iam_policy_attachment has the following warning

WARNING: The aws_iam_policy_attachment resource creates exclusive attachments of IAM policies. Across the entire AWS account, all of the users/roles/groups to which a single policy is attached must be declared by a single aws_iam_policy_attachment resource. This means that even any users/roles/groups that have the attached policy via any other mechanism (including other Terraform resources) will have that attached policy revoked by this resource. Consider aws_iam_role_policy_attachment, aws_iam_user_policy_attachment, or aws_iam_group_policy_attachment instead. These resources do not enforce exclusive attachment of an IAM policy.

We changed some of our code from

resource "aws_iam_policy_attachment" "logs" {
  name       = "${var.function_name}-logs"
  roles      = [aws_iam_role.lambda.name]
  policy_arn = aws_iam_policy.logs[0].arn
}

to

resource "aws_iam_role_policy_attachment" "logs" {
  name       = "${var.function_name}-logs"
  role       = aws_iam_role.lambda.name
  policy_arn = aws_iam_policy.logs[0].arn
}

The change above is simple but now terraform wants to remove the aws_iam_policy_attachment resource and add the aws_iam_role_policy_attachment. Previously, when we applied the terraform for a module using a shared managed IAM resource, it detached the policy from 30 different IAM roles, forcing us to reattach them by finding and reapplying our terraform modules.

What is a safe strategy to use the less dangerous resource aws_iam_role_policy_attachment?

Our current strategy

  1. Recreate managed IAM policy as an inline policy and add to role

  2. Remove the managed policy manually using AWS console

    • Possibly easier with this CLI command. It just seems in the console.

      aws iam detach-role-policy \
        --role-name my-role-name \
        --policy-arn arn:aws:iam:1234567890:role/logs
      
  3. Remove the bad resource from the state

    • May not be necessary since it was removed in the previous step
    • terraform state rm aws_iam_policy_attachment.logs
  4. Target apply the new attachment

    • target apply -target aws_iam_role_policy_attachment.logs
  5. Sanity check

    • terraform plan
  6. Remove the inline policy from the first step

1
Unnerving in what way? It will just remove the existing attachment which means you will have a potential blip in IAM permissions (which you'd have with your manual approach too). Due to the fact that this is racy you might also need to apply twice. If the attach runs before the detach then the IAM API will likely error on the attach (attaching the same policy multiple times), then the detach will run and then show you the error. A second apply will fix that for you because the policy is already detached.ydaetskcoR
Agree that there is really nothing unnerving about an instantaneous policy re-attachment. Since I do not believe policy attachments have AWS IDs (for the purpose of API), you would be unable to do state manipulation to work around this either.Matt Schuchard
You can actually import the aws_iam_role_policy_attachment resource so that is an option if you don't want to have a brief blip on IAM permissions while you refactor this or there's another reason you want to avoid a potential intermittent failure before a retry fixes things. I'd personally just run the apply and if it fails double tap it as this is a one off migration when refactoring.ydaetskcoR
When we applied the terraform for a module using a shared managed IAM resource, it detached the policy from 30 different IAM roles, forcing us to reattach them by finding and reapplying our terraform modules. We've come up with a set of steps to do this safely in the future but wanted to reach out to see if it can be done in a safer way. Have you folks run into this as well?SomeGuyOnAComputer
The importation of aws_iam_role_policy_attachment isn't the issue. The issue is the removal of the aws_iam_policy_attachment which causes detachment in other roles outside of the terraform module being applied.SomeGuyOnAComputer

1 Answers

0
votes

note on state manipulation

Whenever I am going to do state surgery, I change the state to be a local state. Do all my operations. Then run a plan to ensure my changes have caused no diffs. Then put the state back to your propper backend. This article explains how to do that:

https://medium.com/faun/cleaning-up-a-terraform-state-file-the-right-way-ab509f6e47f3

But at a minimum, at least do: terraform state pull > backup.tfstate

state commands for your task

first, make terraform stop tracking the old way you did this terraform state rm aws_iam_policy_attachment.logs

Then just do an import on the new associative resource:

terraform import aws_iam_role_policy_attachment.logs lambda-role/arn:aws:iam::xxxxxxxxxxxx:policy/policy-name

per docs: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment

Do a terraform plan and you should see no diffs.

conclusion

This allows you to not touch your actual AWS configuration. You wont end up deleting any roles or permissions for even a minute. It's safe and verifiable, if you backup your state ahead of time.