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
The Fn::GetAtt intrinsic function returns the value of an attribute from a resource in the template. For more information about GetAtt return values for a particular resource, refer to the documentation for that resource in the Resource and property reference.
You define all conditions in the Conditions section of a template except for Fn::If conditions. You can use the Fn::If condition in the metadata attribute, update policy attribute, and property values in the Resources section and Outputs sections of a template.
You use the Ref intrinsic function to reference a parameter, and AWS CloudFormation uses the parameter's value to provision the stack. You can reference parameters from the Resources and Outputs sections of the same template.
Fn::Sub. The intrinsic function Fn::Sub substitutes variables in an input string with values that you specify. In your templates, you can use this function to construct commands or outputs that include values that aren't available until you create or update a stack.
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
Actually if you insert an empty element (AWS::NoValue
) in your array, CloudFormation will ignore it. So you can do this instead of duplicating all common elements of the array:
Principal:
AWS:
- "arn1"
- "Fn::If":
- "IsProd"
- Ref: "AWS::NoValue"
- "arn2"
I'm not sure it works in your specific use case, but I just used it to conditionnaly add a CloudFront cache behavior and origin, and it worked.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With