I have a role that I want to create only if there are entries for the given keys in the Mapping. The confusion comes when I have no values to put in for certain key / values (in this case, some regions don't have a value for "XClientPrincipals", so I get an error.
Example: The map:
alpha: ...
beta:
Region1:
YClientPrincipals:
- 'arn:aws:iam::#########:root'
Region3:
XClientPrincipals:
- 'arn:aws:iam::#########:root'
YClientPrincipals:
- 'arn:aws:iam::#########:root'
prod:
Region1:
YClientPrincipals:
- 'arn:aws:iam::#########:root'
Region2:
XClientPrincipals:
- 'arn:aws:iam::#########:root'
- 'arn:aws:iam::#########:root'
YClientPrincipals:
- 'arn:aws:iam::#########:root'
Region3:
XClientPrincipals:
- 'arn:aws:iam::#########:root'
- 'arn:aws:iam::#########:root'
YClientPrincipals:
- 'arn:aws:iam::#########:root'
The role:
# Role definition for LMSortPlanningWorkflow - https://issues.amazon.com/LMCP-3533
XClientRole:
Type: AWS::IAM::Role
Condition: IsBetaOrProd # Don't create external client roles in Alpha
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Action: 'sts:AssumeRole'
Effect: Allow
Principal:
AWS:
'Fn::FindInMap': [ { Ref: 'Domain' }, { Ref: 'Region' }, 'XClientPrincipals' ]
RoleName: { 'Fn::Sub': 'XClientRole' }
ManagedPolicyArns:
- Ref: SomeApiCallPolicy
The issue is that XClientPrincipals only applies to some Regions, and we only need to create the roles in those regions (and they're different between beta and prod). If I don't provide something in the map for every possible combination of domain and region we have, it will error when deploying for that domain region because it can't find anything in the map. But if I specify an empty array for that domain region, that's also an error because the principal needs a value. Is there a way to create a condition for only creating the role if it can find the value in the map first?
I'm pretty sure I could create a condition to only create the role and spell out acceptable domain and region values (1st and 2nd key) that should evaluate to true, but the actual mapping is a little more complicated than this, so it would be great to be able to just do a condition like:
RunLambdaInVPC:
Fn::Not: [ {Ref: FindInMap .... }, null]
but I don't think I've seen any examples of this or figured out a way to get something like this to work.
CodePudding user response:
You have to do it through cloudformation macro or a custom resource. You have to remember that CloudFormation is very, very limited in what it can do, and all those limitations can be overcome through the macros and the custom resources.
Alternatively, you have to change your requirements, and simply make them as simple as possible, so that plain CloudFormation can handle them.
CodePudding user response:
Yes, you can conditionally create resources based on the value of a certain mapping.
Here's an example that shows how the value of a region map can be used in a Condition
, that can then be used to determine whether a resource should be created or not:
AWSTemplateFormatVersion: "2010-09-09"
Mappings:
RegionMap:
us-east-1:
"HVM64": "ami-0ff8a91507f77f867"
us-west-1:
"HVM64": "ami-0bdb828fd58c52235"
IsProdMapping:
us-east-1:
"prod": "True"
us-west-1:
"prod": "False"
Resources:
EC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: !FindInMap [RegionMap, !Ref "AWS::Region", HVM64]
InstanceType: t3.nano
SubnetId: !Ref Subnet
RootRole:
Type: 'AWS::IAM::Role'
Condition: CreateIAMRole
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- 'sts:AssumeRole'
Path: /
Policies:
- PolicyName: root
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action: '*'
Resource: '*'
Conditions:
CreateIAMRole: !Equals
- !FindInMap [IsProdMapping, !Ref "AWS::Region", "prod"]
- "True"
Parameters:
VPC:
Type: AWS::EC2::VPC::Id
Description: The VPC where you want to deploy
Subnet:
Type: AWS::EC2::Subnet::Id
Description: The subnet where you want to deploy
If I deploy this template in us-east-1
, RootRole
is created.
If I deploy this template in us-west-1
, RootRole
is not created.