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

12,312

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
Share:
12,312
SanD
Author by

SanD

A Software engineer experienced in Java and C++.

Updated on June 09, 2022

Comments

  • SanD
    SanD over 1 year

    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

  • Tomasz Gandor
    Tomasz Gandor over 2 years
    This is good enough for small arrays... What about large lists - is there no way where we need not specify all the common elements twice?