Home > database >  Create role only if FindInMap value is present? / What to do if Mapping doesn't have values for
Create role only if FindInMap value is present? / What to do if Mapping doesn't have values for

Time:04-22

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.

  • Related