amazon-web-servicesaws-cloudformationamazon-kms

How to use Fn::If with array values in cloud formation templates


I am working on a cloud formation template for a KMS key. In the policy document I want to set the the principals depending on the stage (whether it is prod or test). I can use Fn:If easily if there is only one principal for both stages. But I have more than one principals for each stage and Fn:If only allows you to assign a value, not a collection according to my understanding (correct me if I am wrong).

I have tried assigning a collection to the value and it gives me "map keys must be strings; received a collection instead" error when validating the template using the CloudFormation designer in AWS accounnt.

"MyEncryptionKey": {
            "DeletionPolicy": "Retain",
            "Properties": {
                "Description": "MyEncryptionKey",
                "EnableKeyRotation": true,
                "Enabled": true,
                "KeyPolicy": {
                    "Statement": [
                        {
                            "Action": "kms:*",
                            "Effect": "Allow",
                            "Principal": {
                                "AWS": "root"
                            },
                            "Resource": "*"
                        },
                        {
                            "Action": "kms:Decrypt",
                            "Effect": "Allow",
                            "Principal": {
                                "AWS": [
                                    {
                                        "Fn::If": [
                                            "IsProd",
                                            {["arn1","arn2"]},
                                            "arn2"
                                        ]
                                    }
                                ]
                            },
                            "Resource": "*"
                        }
                    ]
                }
            },
            "Version": "2012-10-17",
            "Type": "AWS::KMS::Key"
        }

Ideally the second statement in key policy should have a two arn values if prod and one arn value if not prod.

I am also open to explore if there is any other way of achieving this instead of using Fn::If here


Solution

  • Instead of considering value evaluated from Fn::If as a single array item, consider it an array. Replace the Principal with the following and it will work.

    JSON

    {
      "Principal": {
        "AWS": {
          "Fn::If": [
            "IsProd",
            [
              "arn1"
            ],
            [
              "arn1",
              "arn2"
            ]
          ]
        }
      }
    }
    

    It will look simple in yaml

    Principal:
      AWS:
        Fn::If:
        - IsProd
        - - arn1
        - - arn1
          - arn2