AWS SAM – Running nested !FindInMap (Quick Tip)

AWS SAM is a framework for deploying severless applications. To deploy an application with SAM you have to create a template.yaml file which describes the entire stack that will be deployed to support the application.

If you’re like me and you love the DRY principle, you hate to see things like the following

Mappings:
  EnvMapping:
    dev:
      VpcId: vpc-xxxxxxxxx
      SubnetIds:
        - subnet-xxxxxxxx
        - subnet-xxxxxxxx
        - subnet-xxxxxxxx
      Foo: bar
    performance:
      VpcId: vpc-xxxxxxxxx
      SubnetIds:
        - subnet-xxxxxxxx
        - subnet-xxxxxxxx
        - subnet-xxxxxxxx
      Bar: bing
    feature: 
      VpcId: vpc-xxxxxxxxx
      SubnetIds:
        - subnet-xxxxxxxx
        - subnet-xxxxxxxx
        - subnet-xxxxxxxx
      Baz: foo
    prod:
      VpcId: vpc-yyyyyyyy
      SubnetIds:
        - subnet-yyyyyyyy
        - subnet-yyyyyyyy
        - subnet-yyyyyyyy

This is obviously redundant. The VPC id and Subnet ids are being repeated and if you need to update your VPC, you would have to change the information for each environment.

The alternative is to create a VpcMapping and then use a value from the EnvMapping as a key. For example, see the solution below which removes the redundant VPC declarations and puts them into a map.

Mappings:
  VpcMapping:
    prod:
      VpcId: vpc-yyyyyyyy
      SubnetIds:
        - subnet-yyyyyyyy
        - subnet-yyyyyyyy
        - subnet-yyyyyyyy
    nonprod:
      VpcId: vpc-xxxxxxxxx
      SubnetIds:
        - subnet-xxxxxxxx
        - subnet-xxxxxxxx
        - subnet-xxxxxxxx
  EnvMapping:
    dev:
      Vpc: nonprod
      Foo: bar
    performance:
      Vpc: nonprod
      Bar: bing
    feature: 
      Vpc: nonprod
      Baz: foo
    prod:
      Vpc: prod

As you can see, the Vpc field serves as the VpcMapping key. Now, when you need to reference your VpcId or SubnetIds, you can use a nested !FindInMap function. See below

VpcId: !FindInMap
  - VpcMapping
  - !FindInMap
    - EnvMapping
    - !Ref Env
    - Vpc
  - VpcId

Or if you prefer that in a single line (retrieving the subnet ids this time)

SubnetIds: !FindInMap [VpcMapping, !FindInMap [EnvMapping, !Ref Env, Vpc], SubnetIds]

Hopefully this helps keep you DRY