amazon-web-servicesterraformamazon-iamterraform-provider-awsamazon-kms

malformed policy / self reference


I was trying to provision AWS kms key using terraform, added the code which I am using. In this kms resource I need to add a AWS kinesis firehose role to access the kms key. For that in the code I added kms key as hardcorded (after provisioning). To add this role as part of the terraform apply I tried the below options

  1. Used * in the Resource field key/* and got the error "malformed policy document exception"
  2. Used aws_kms_key.key.arn Configuration for aws_kms_key.key may not refer to itself
resource "aws_kms_key" "key" {
  description             = var.description
  key_usage               = var.key_usage
  is_enabled              = true
  policy                  = jsonencode({
    Version = "2012-10-17",
    Id      = "key-default-1",
    Statement = [
       {
          Sid       = "Enable IAM User Permissions",
          Effect    = "Allow",
          Principal = { AWS = "*" },
          Action = [
            "kms:Create*",
            ..............
            "kms:CancelKeyDeletion",
          ],
          Resource = "*",
       },
       {
          "Sid": "Allow firehose role",
          "Effect": "Allow",
          "Principal": {
             "AWS": "arn:aws:iam::${local.account_id}:role/${var.somerole}"
            },
             "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey"
             ],
             "Resource": "arn:aws:kms:eu-central-1:${local.account_id}:key/111-111-111"
       },
 .
 .
 .
}

Solution

  • As mentioned in my comment, I would prefer using a separate resource for the key instead of adding the policy to the resource used for key creation. Here is what the code would look like if you were to decide to use that approach:

    resource "aws_kms_key" "kms" {
      description             = var.description
      key_usage               = var.key_usage
      is_enabled              = true
    }
    
    resource "aws_kms_key_policy" "kms_key" {
      key_id   = aws_kms_key.kms.key_id
    
      policy = jsonencode({
        Id      = "kms-key-policy",
        Version = "2012-10-17",
        Statement = [
        { 
          Sid    = "Allow administration of the key",
          Effect = "Allow",
          Principal = {
            "AWS" = "arn:aws:iam::<your account id>:root"
        },
          Action = [
            "kms:Create*",
            "kms:Describe*",
            "kms:Enable*",
            "kms:List*",
            "kms:Put*",
            "kms:Update*",
            "kms:Revoke*",
            "kms:Disable*",
            "kms:Get*",
            "kms:Delete*",
            "kms:ScheduleKeyDeletion",
            "kms:CancelKeyDelEetion"
           ],
           Resource = "*"
          }
          {
            Sid       = "Enable IAM User Permissions",
            Effect    = "Allow",
            Principal = { AWS = "*" },
            Action = [
              "kms:Create*",
              ..............
              "kms:CancelKeyDeletion",
            ],
            Resource = "*",
          },
            Sid = "Allow firehose role",
            Effect = "Allow",
            Principal = {
                AWS = "arn:aws:iam::${local.account_id}:role/${var.somerole}"
            },
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey"
            ],
            Resource = [aws_kms_key.kms.arn]
          }
        ]
      })
    }
    

    Additionally, you could use the aws_iam_policy_document data source to avoid some of the pitfalls of creating the policy inline. That part could then be done like the following:

    data "aws_iam_policy_document" "kms_key_policy" {
      statement {
        sid    = "Allow administration of the key"
        effect = "Allow"
        principals {
          type = "AWS"
          identifiers = [
            "arn:aws:iam::<your account id>:root"
          ]
        }
        actions = [
          "kms:Create*",
          "kms:Describe*",
          "kms:Enable*",
          "kms:List*",
          "kms:Put*",
          "kms:Update*",
          "kms:Revoke*",
          "kms:Disable*",
          "kms:Get*",
          "kms:Delete*",
          "kms:ScheduleKeyDeletion",
          "kms:CancelKeyDelEetion"
        ]
        resources = [
          "*"
        ]
      }
    
      statement {
        sid    = "Enable IAM User Permissions"
        effect = "Allow"
        principals {
          type        = "AWS"
          identifiers = ["*"]
        }
        actions = [
          "kms:Create*",
          "kms:CancelKeyDeletion",
          # add whatever is missing from the actions
        ]
        resources = ["*"]
      }
    
      statement {
        sid    = "Allow firehose role"
        effect = "Allow"
        principals {
          type = "AWS"
          identifiers = [
            "arn:aws:iam::${local.account_id}:role/${var.somerole}"
          ]
        }
        actions = [
          "kms:Encrypt",
          "kms:Decrypt",
          "kms:ReEncrypt*",
          "kms:GenerateDataKey*",
          "kms:DescribeKey"
        ]
        resources = [
          aws_kms_key.kms_key.arn
        ]
      }
    }
    
    resource "aws_kms_key" "kms" {
      description             = var.description
      key_usage               = var.key_usage
      is_enabled              = true
    }
    
    resource "aws_kms_key_policy" "kms_key" {
      key_id = aws_kms_key.kms.key_id
      policy = data.aws_iam_policy_document.kms_key_policy.json
    }