terraformmalformedaws-iam-policy

Terraform resource creation aws_iam_policy fails due to malformed policy document


I want to create an AWS IAM policy for multiple ECR repos

Terraform module call

module "cocos-ecr-all-repo-policy" {
  count      = (data.aws_region.current.name == "eu-central-1" ? 1 : 0)
  source     = "./modules/ecr-policies/ecr-all-repo-policy"
  account_id = data.aws_caller_identity.current.account_id
}

Module

variable "account_id" {
  type        = string
  description = "AWS account id"
}

resource "aws_iam_policy" "iam-policy" {
  name = "ecr-repo-user-policy"
  description = "IAM policy for ecr users"

  tags = {
    Creator = "terraform"
  }

  policy = jsonencode({
    Version   = "2012-10-17"
    statement = [
      {
        sid       = "EcrRepositoryAccess"
        effect    = "Allow"
        action   = [
          "ecr:DescribeImages",
          "ecr:ListTagsForResource",
          "ecr:ListImages",
          "ecr:PutImage",
          "ecr:GetDownloadUrlForLayer",
          "ecr:BatchGetImage",
          "ecr:BatchCheckLayerAvailability",
          "ecr:BatchDeleteImage",
          "ecr:InitiateLayerUpload",
          "ecr:UploadLayerPart",
          "ecr:CompleteLayerUpload",
        ]
        resources = [
          "arn:aws:ecr:*:${var.account_id}:repository/repo1/*",
          "arn:aws:ecr:*:${var.account_id}:repository/repo2/*",
        ]
      },
      {
        sid       = "EcrToken"
        effect    = "Allow"
        actions   = [
          "ecr:GetAuthorizationToken",
        ]
        resources = [
          "*",
        ]
      }
    ]
  })

}

Plan returns this

Terraform will perform the following actions:

  # module.cocos-ecr-all-repo-policy[0].aws_iam_policy.iam-policy will be created
  + resource "aws_iam_policy" "iam-policy" {
      + arn         = (known after apply)
      + description = "IAM policy for ecr users"
      + id          = (known after apply)
      + name        = "ecr-repo-user-policy"
      + path        = "/"
      + policy      = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = [
                          + "ecr:DescribeImages",
                          + "ecr:ListTagsForResource",
                          + "ecr:ListImages",
                          + "ecr:PutImage",
                          + "ecr:GetDownloadUrlForLayer",
                          + "ecr:BatchGetImage",
                          + "ecr:BatchCheckLayerAvailability",
                          + "ecr:BatchDeleteImage",
                          + "ecr:InitiateLayerUpload",
                          + "ecr:UploadLayerPart",
                          + "ecr:CompleteLayerUpload",
                        ]
                      + Effect    = "Allow"
                      + Resources = [
                          + "arn:aws:ecr:*:<AWS account id>:repository/repo1/*",
                          + "arn:aws:ecr:*:<AWS account id>:repository/repo2/*",
                        ]
                      + Sid       = "EcrRepositoryAccess"
                    },
                  + {
                      + Actions   = [
                          + "ecr:GetAuthorizationToken",
                        ]
                      + Effect    = "Allow"
                      + Resources = [
                          + "*",
                        ]
                      + Sid       = "EcrToken"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + policy_id   = (known after apply)
      + tags        = {
          + "Creator" = "terraform"
        }
      + tags_all    = {
          + "Creator" = "terraform"
        }
    }

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

Apply returned error message:

Error: error creating IAM policy ecr-repo-user-policy: MalformedPolicyDocument: Syntax errors in policy.

Creation of policy with AWS Console GUI works fine.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ecr:DescribeImages",
                "ecr:ListTagsForResource",
                "ecr:ListImages",
                "ecr:PutImage",
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage",
                "ecr:BatchCheckLayerAvailability",
                "ecr:InitiateLayerUpload",
                "ecr:UploadLayerPart",
                "ecr:CompleteLayerUpload"
            ],
            "Resource": [
                "arn:aws:ecr:*:<AWS account id>:repository/repo1/*",
                "arn:aws:ecr:*:<AWS account id>:repository/repo2/*"
            ]
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "ecr:GetAuthorizationToken",
            "Resource": "*"
        }
    ]
}

The problem is with first statement to create ECR repo permissions. I tried different changes to terraform code, un/capitalization of key words like Action, add/remove comma after last line of ressource and action blocks. Commenting out second statement did not change anything. Nothing did help. Any help would be appreciated.


Solution

  • It's because of syntax errors in your policy doc

    All the keys in this policy doc should be in Camelcase and use singular nouns instead of plural, for example, it's Resource instead of resources. You can also find a short example here at the official doc as well https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy

    So, Your policy should be like this

      policy = jsonencode({
        Version   = "2012-10-17"
        Statement = [
          {
            Sid       = "EcrRepositoryAccess"
            Effect    = "Allow"
            Action   = [
              "ecr:DescribeImages",
              "ecr:ListTagsForResource",
              "ecr:ListImages",
              "ecr:PutImage",
              "ecr:GetDownloadUrlForLayer",
              "ecr:BatchGetImage",
              "ecr:BatchCheckLayerAvailability",
              "ecr:BatchDeleteImage",
              "ecr:InitiateLayerUpload",
              "ecr:UploadLayerPart",
              "ecr:CompleteLayerUpload",
            ]
            Resource = [
              "arn:aws:ecr:*:<AWS account id>::repository/repo1/*",
              "arn:aws:ecr:*:<AWS account id>::repository/repo2/*",
            ]
          },
          {
            Sid       = "EcrToken"
            Effect    = "Allow"
            Action   = [
              "ecr:GetAuthorizationToken",
            ]
            Resource = [
              "*",
            ]
          }
        ]
      })