I'm writing a CloudFormation template for an IAM role that I will assume through STS. I need to add a condition where a key equals a value, where both the key and value depends on a "Stage" parameter. The value I've been able to programmatically change depending on the parameter, but all my attempts to change the key based on Stage have failed.
I've tried both using a map and !FindInMap to get the correct key, as well as tried to construct a condition with both cases using !If.
In the first case...
Mappings:
Constants:
beta:
Id: "beta.example.com"
Endpoint: "beta-link.example.com/api/oauth2/v2:aud"
prod:
Id: "example.com"
Endpoint: "link.example.com/api/oauth2/v2:aud"
AssumeRolePolicyDocument:
Statement:
Action:
- "sts:AssumeRoleWithWebIdentity"
Condition:
StringEquals:
!FindInMap [Constants, !Ref Stage, Endpoint]:
- !FindInMap [Constants, !Ref Stage, Id]
... I got an error: map keys must be strings; received a map instead
In the second case...
AssumeRolePolicyDocument:
Statement:
Action:
- "sts:AssumeRoleWithWebIdentity"
Condition:
!If
- !Equals [!Ref Stage, prod]
- StringEquals:
"link.example.com/api/oauth2/v2:aud": "example.com"
- StringEquals:
"beta-link.example.com/api/oauth2/v2:aud": "beta.example.com"
...I got another error: Template format error: Conditions can only be boolean operations on parameters and other conditions
In short, how can I specify a condition where both key and value depend on a parameter?
I have struggled around 8 hours continuously and finally found an answer to this problem. Just for the viewers I would like to summarise the problem:
Problem Statement : As a infrastructure engineer, I want to write a cloudformation resource for AWS::IAM::Role which defines a AssumeRolePolicyDocument with a Condition clause where the key needs to be parameterised. Also another question is can we use intrinsic functions with Condition keys?
Answer: Yes, it is possible using an out of the box style. AssumeRolePolicyDocument is a String Type as per the AWS Cloudformation documentation for 'AWS::IAM::Role'. So instead of using YAML style data to the AssumeRolePolicyDocument property, just pass a raw JSON formatted Assumerole policy using Fn::Sub and use variables to replace the key without any issues or warnings. Below is an example that you can use. Its a complex use case that i was trying to solve but it shows how you can replace keys under a IAM Condition clause using !SUB,!Select etc.
ExampleAppRole:
Type: 'AWS::IAM::Role'
Properties:
RoleName: !Sub ${Environment}-ExampleAppRole
AssumeRolePolicyDocument:
Fn::Sub:
- |
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::${AWS::AccountId}:oidc-provider/oidc.eks.${AWS::Region}.amazonaws.com/id/${id}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${clusterid}": "${serviceaccount}"
}
}
}
]
}
-
clusterid: !Join ["",[!Sub "oidc.eks.${AWS::Region}.amazonaws.com/id/",!Select [1, !Split ["//", !Select [0, !Split [".", !GetAtt Cluster.Endpoint]]]],":sub"]]
id: !Select [1, !Split ["//", !Select [0, !Split [".", !GetAtt Cluster.Endpoint]]]]
Region: !Sub ${AWS::Region}
serviceaccount: system:serviceaccount:default:awsiamroleexample
Path: /
ManagedPolicyArns:
- !Ref SnsPublishAccessPolicy
Let me know your thoughts in the comments section.
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