🙆

terraform applyをすると、意図せずIAMロールがアップデートされてしまう

2023/06/11に公開

事象

以下のように2つのポリシーをアタッチするIAMロールをTerraformでデプロイしていました。

resource "aws_iam_policy" "GetParameterStore" {
  name   = "GetParameterStore"
  path   = "/"
  policy = data.aws_iam_policy_document.GetParameterStore.json
}

resource "aws_iam_role" "task_execution_role" {
  name = "${var.system_name}_${var.environment}_task_execution_role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect    = "Allow"
        Principal = { Service = "ecs-tasks.amazonaws.com" }
        Action    = "sts:AssumeRole"
      }
    ]
  })
  managed_policy_arns = [
    "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy",
  ]
}

resource "aws_iam_role_policy_attachment" "GetParameterStore" {
    role = aws_iam_role.task_execution_role.name
    policy_arn = aws_iam_policy.GetParameterStore.arn
}

この状態でterraform plan,applyを試すと、このようにアップデートされてしまいます。
コードは変更していないため、No Changeが出る想定でした。

Terraform will perform the following actions:

  # module.app.aws_iam_role.task_execution_role will be updated in-place
  ~ resource "aws_iam_role" "task_execution_role" {
        id                    = "fargate-nginx_dev_task_execution_role"
      ~ managed_policy_arns   = [
          - "arn:aws:iam::xxxxxxxxxxxx:policy/GetParameterStore",
            # (1 unchanged element hidden)
        ]
        name                  = "fargate-nginx_dev_task_execution_role"
        tags                  = {}
        # (9 unchanged attributes hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

原因

aws_iam_roleのmanaged_policy_arnsaws_iam_role_policy_attachmentを併用しているため。

対処方法

上記のどちらかに統一します。
こちらはmanaged_policy_arnsに統一したコードです。

resource "aws_iam_policy" "GetParameterStore" {
  name   = "GetParameterStore"
  path   = "/"
  policy = data.aws_iam_policy_document.GetParameterStore.json
}

resource "aws_iam_role" "task_execution_role" {
  name = "${var.system_name}_${var.environment}_task_execution_role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect    = "Allow"
        Principal = { Service = "ecs-tasks.amazonaws.com" }
        Action    = "sts:AssumeRole"
      }
    ]
  })
  managed_policy_arns = [
    "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy",
+    "${aws_iam_policy.GetParameterStore.arn}"
  ]
}

- resource "aws_iam_role_policy_attachment" "GetParameterStore" {
-     role = aws_iam_role.task_execution_role.name
-     policy_arn = aws_iam_policy.GetParameterStore.arn
- }

深堀りする

terraformのaws_iam_role_policy_attachmentドキュメントに以下の様に記載がありました。

For a given role, this resource is incompatible with using the aws_iam_role resource managed_policy_arns argument. When using that argument and this resource, both will attempt to manage the role's managed policy attachments and Terraform will show a permanent difference.

併用すると差分を出し続けるらしいです。
managed_policy_arns側にも注意書きがあります。

どっちを使うのがいいの?

うーん...わかりません。
aws_iam_role_policy_attachmentをポリシー毎に書くことを考えると
managed_policy_arnsのほうが比較的簡潔に書けると思います。
そう考えるとmanaged_policy_arnsに軍配かな...

参考記事[1]によると、外部で設定変更した場合のTerraformの振る舞いに差分があるみたいです。
元にもどってほしいか変更を許容するか...今は判断出来ないですね。

参考

以下の記事を大変参考にさせていただきました。

脚注
  1. https://qiita.com/hmdsg/items/7862213637fc4c3d9a3f ↩︎

Discussion