Terraform malformed policy

Hi, I’m working with kms policy , I’ using templatefile, but the issue here is that terraform plan is rearranging the arn’s and adding a comma at the last arn.

When running terraform apply its failing with malformed policy. Is there any way to avoid this ?

Terraform 0.12.20

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

}

${jsonencode({
  "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": "*"
    }
  ]
})}
resource "aws_kms_key" "key" {
  description = ""
  tags        = local.common_tags
  policy = templatefile("${path.module}/key_policy.json.tpl", {
    allowed_resources = var.allowed_resources
  })
}

Terraform plan:

resource "aws_kms_key" "amp_key" {
    arn                      = "arn:aws:kms:us-east-1:xxxx:key/xxxxxx"
    customer_master_key_spec = "SYMMETRIC_DEFAULT"
    enable_key_rotation      = false
    id                       = "xxxx-xxxxxxxxx"
    is_enabled               = true
    key_id                   = "xxxxxxxxxxx-xxxxxx"
    key_usage                = "ENCRYPT_DECRYPT"
    policy                   = jsonencode(
        {
            Id        = "key-policy-1"
            Statement = [
                {
                    Action    = "kms:*"
                    Effect    = "Allow"
                    Principal = {
                        AWS = "arn:aws:iam::xxxxxxxxxxxx: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::xxxxxxxxxxxx:user/a",
                            "arn:aws:iam::xxxxxxxxxxxx:user/c",
                            "arn:aws:iam::xxxxxxxxxxxx:role/abc",
                            "arn:aws:iam::xxxxxxxxxxxx:user/a",
Terraform apply 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" {

Hi @skadem07,

That error is talking about policy-type problems rather than JSON-type problems, which tells me that the problem is not a syntax error (i.e. positioning of commas is not the problem) but rather an error in the data of the policy.

What you’ve seen here seems to be the same root cause as this issue in the AWS provider repository:

I wasn’t familiar with this issue before today so I’m working only with what I’ve understood from reading it just now, but I believe the problem is that this Terraform operation is both creating this KMS key and creating at least one of the users or roles that you’re listing as a principal, and the AWS IAM API is indicating that one of those objects was created successfully but it doesn’t propagate completely to all AWS services (including KMS, here) for some time afterward. KMS then fails to accept your policy because as far as it knows one of the users or roles doesn’t exist. This is, unfortunately, quite a common problem with AWS IAM: its design employs eventual consistency in order to scale well across all AWS regions and services.

The immediate-term workaround I’d suggest for that is that when you see this error you can wait a few minutes and then try terraform apply again, at which point IAM and KMS should be resynchronized and the KMS key creation should succeed.

I understand that this isn’t a very satisfying solution: the AWS provider would ideally recognize this situation and work around it, and I imagine that is what the issue 245 I linked above is representing. AWS does not offer any APIs to reliably determine when IAM change propagation is complete, but some other AWS provider resource types try to work around this by recognizing specific error codes and retrying for a minute or two in order to see if the problem goes away, though that’s perhaps more awkward in this case because the generic error code MalformedPolicyDocumentException is probably used to describe any problem with the policy document, not just that IAM objects it refers to don’t seem to exist.

Someone in the AWS provider issue also offered a less elegant workaround of using a local-exec provisioner to wait 15 seconds for the IAM role to propagate before considering it “created”, which I suppose is a way to encode the “if it doesn’t work immediately then wait and try again” workaround directly in the configuration so that you don’t have to modify how you use Terraform. (but you will have to wait 15 seconds after the IAM role is created, of course.)

1 Like

hmm,

I tried re-running terraform apply twice , the second time after 15 s, it didn’t work. May be there is something wrong with my policy?