Search code examples
amazon-web-servicesterraformterraform-provider-awsamazon-kms

Terraform malformed policy


I'm working on importing kms into terraform, I have imported these resources, but when i try to run a terraform plan its rearranging the arn's and hence the last arn has a comma. Thus my terraform apply is failing.

Is there anyway I can avoid this rearranging? I think in this case i should be using a data block instead of adding the policy directly. But i'm not sure how to pass the data block ..

Looks like i can't use a data block, Is there any way i can to avoid the rearranging on arn in Principal block?

I'm using terraform 0.12.20

policy.json.tpl

{
    "Version": "2012-10-17",
    "Id": "key-policy-1",
    "Statement": [{
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": ${allowed_resources}
            },
            "Action": "kms:*",
            "Resource": "*"
        },
        {
            "Sid": "Allow use of the key",
            "Effect": "Allow",
            "Principal": {
                "AWS": ${allowed_resources}
            },
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey"
            ],
            "Resource": "*"
        }
    ]
}

main.tf

resource "aws_kms_key" "key" {
  description = ""
  tags        = local.common_tags
  policy      = templatefile("${path.module}/policy.json.tpl", {
    allowed_resources = var.allowed_resources
  })
}

variables.tf

variable "allowed_resources" {
  description = "list of all principal resources"
  type        = list(string)
  default = [
    "arn:aws:iam::xxxxxxxxxxxx:user/a",
    "arn:aws:iam::xxxxxxxxxxxxx:user/b",
    "arn:aws:iam::xxxxxxxxxx:user/c",
    "arn:aws:iam::xxxxxxxxxx:role/abc
  ]
}

Error

10:53:19 Error: MalformedPolicyDocumentException: Policy contains a statement with one or more invalid principals.
10:53:19 
10:53:19   on main.tf line 8, in resource "kms_key" "key":
10:53:19    8: resource "aws_kms_key" "key" {

Terraform plan: Terraform will perform the following actions:

  # aws_kms_key.amp_key will be updated in-place
  ~ resource "aws_kms_key" "amp_key" {
        arn                      = "arn:aws:kms:us-east-1:xxxx:key/xxx-xxx-xxx-xx-xxxxxxxx"
        customer_master_key_spec = "SYMMETRIC_DEFAULT"
        enable_key_rotation      = false
        id                       = "xxx-xxx-xxx-xx-xxxxxxxx"
        is_enabled               = true
        key_id                   = "xxx-xxx-xxx-xx-xxxxxxxx"
        key_usage                = "ENCRYPT_DECRYPT"
      ~ policy                   = jsonencode(
          ~ {
                Id        = "key-policy-1"
              ~ Statement = [
                    {
                        Action    = "kms:*"
                        Effect    = "Allow"
                        Principal = {
                            AWS = "arn:aws:iam::xxxxxxxx:root"
                        }
                        Resource  = "*"
                        Sid       = "Enable IAM User Permissions"
                    },
                  ~ {
                        Action    = [
                            "kms:Encrypt",
                            "kms:Decrypt",
                            "kms:ReEncrypt*",
                            "kms:GenerateDataKey*",
                            "kms:DescribeKey",
                        ]
                        Effect    = "Allow"
                      ~ Principal = {
                          ~ AWS = [
                              + "arn:aws:iam::xxxxxx:user/c",
                              + "arn:aws:iam::xxxxxx:user/a",
                              - "arn:aws:iam::xxxxxx:role/abc",
                              - "arn:aws:iam::xxxxxx:user/a",
                              - "arn:aws:iam::xxxxxx:user/c",
                                "arn:aws:iam::xxxxxx:user/b",
                              + "arn:aws:iam::xxxxxx:role/abc",
                         ]
                       }
                     ]
                Version   = "2012-10-17"
                     }
                 )

When i tried to use data block

data "template_file" "temp_file" {
  template = "${file("${path.module}/amp_key_policy.json.tpl")}"
  vars = {
    allowed_resources = "${var.allowed_resources}" //tried without quotes
  }
}
resource "aws_kms_key" "amp_key" {
  description = ""
  tags        = local.common_tags
  policy      = data.template_file.temp_file.rendered
}

Error: Incorrect attribute value type

  on main.tf line 10, in data "template_file" "temp_file":
  10:   vars = {
  11:     allowed_resources = "${var.allowed_resources}"
  12:   }

Inappropriate value for attribute "vars": element "allowed_resources": string required.

Updated:

i tried using aws_iam_policy_document.

data "aws_iam_policy_document" "amp_key_doc" {
  for_each = toset(var.allowed_resources)
  statement {
    sid    = "Enable IAM User Permissions"
    effect = "Allow"
    principals {
      identifiers = ["arn:aws:iam::xxxxx:root"]
      type        = "AWS"
    }
    actions   = ["kms:*"]
    resources = ["*"]
  }

  statement {
    sid    = "Allow access for Key Administrators"
    effect = "Allow"
    principals {
      identifiers = ["arn:aws:iam::xxxx:user/a"]
      type        = "AWS"
    }
    actions = [
      "kms:Create*",
      "kms:Describe*",
      "kms:Enable*",
      "kms:List*",
      "kms:Put*",
      "kms:Update*",
      "kms:Revoke*",
      "kms:Disable*",
      "kms:Get*",
      "kms:Delete*",
      "kms:TagResource",
      "kms:UntagResource",
      "kms:ScheduleKeyDeletion",
    "kms:CancelKeyDeletion"]
    resources = ["*"]
  }

  statement {
    sid    = "Allow use of the key"
    effect = "Allow"
    principals {
      identifiers = [var.allowed_resources]
      type        = "AWS"
    }
    actions = [
      "kms:Encrypt",
      "kms:Decrypt",
      "kms:ReEncrypt*",
      "kms:GenerateDataKey*",
      "kms:DescribeKey"
    ]
    resources = ["*"]
  }

  statement {
    sid    = "Allow attachment of persistent resources"
    effect = "Allow"
    principals {
      identifiers = [var.allowed_resources]
      type        = "AWS"
    }
    actions = [
      "kms:CreateGrant",
      "kms:ListGrants",
      "kms:RevokeGrant"
    ]
    resources = ["*"]
    condition {
      test     = "Bool"
      values   = ["true"]
      variable = "kms:GrantIsForAWSResource"
    }
  }
}


resource "aws_kms_key" "key" {
  description = ""
  tags        = local.common_tags
  policy      = data.aws_iam_policy_document.key_doc.json

Got an error , How do we pass the entire chunk of allowed_resources?

Error: Incorrect attribute value type

  on data.tf line 43, in data "aws_iam_policy_document" "key_doc":
  43:       identifiers = [var.allowed_resources]

Inappropriate value for attribute "identifiers": element 0: string required.

Error: Incorrect attribute value type

on data.tf line 60, in data "aws_iam_policy_document" "key_doc": 60: identifiers = [var.allowed_resources]

Inappropriate value for attribute "identifiers": element 0: string required.


Solution

  • The error comes down to values of vars only supporting primitive types as stated in the documentation

    Variables for interpolation within the template. Note that variables must all be primitives. Direct references to lists or maps will cause a validation error.

    If you create your policy as a iam_policy_document you can use the json attribute of the resource to pass into your aws_kms_key resource.