Search code examples
aws-lambdayamlgithub-actionsaws-cloudformationamazon-vpc

Yaml file for CloudFormation - select which subnet ids to put lambdas in


I'm trying to put my lambdas in the appropriate VPC given the environment. How can that be achieved given I'm building the VPCs in a separate nested stack given the environment?

Using Github actions and sam deploy if that matters.

Parameters:
  environment:
    Type: String
  devLambdaSubnetIds:
    Type: String
    Default: !Join [',', subnet-[devVpcA], subnet-[devVpcB]]
  prodLambdaSubnetIds:
    Type: String
    Default: !Join [',', subnet-[prodVpcA], subnet-[prodVpcB]]
...
Resources:
 HealthCheckFunction:
    Type: AWS::Serverless::Function
    Properties:
        ...
        VpcConfig:
        Ipv6AllowedForDualStack: false
        SecurityGroupIds: 
          - !Ref genericSecurityGroup
        SubnetIds: HERE THIS NEEDS TO BE !Ref devLambdaSubnetIds or !Ref prodLambdaSubnetIds depending on the environment (which is either 'dev' or 'prod')

Solution

  • You could use a mapping and keep config for each env in the mapping.

    In the example below the subnet ids would need to be changed for real subnet ids.

    Parameters:
      env:
        Type: String
        Description: Specify an account/environment
        AllowedValues:
          - dev
          - prod
    
    Mappings:
      environments:
        dev:
          sb1: subnet-a
          sb2: subnet-b
        prod:
          sb1: subnet-c
          sb2: subnet-d
    
    Resources:
      HealthCheckFunction:
        Type: AWS::Serverless::Function
        Properties:
          ...
          VpcConfig:
            Ipv6AllowedForDualStack: false
            SecurityGroupIds:
              - !Ref genericSecurityGroup
            SubnetIds:
              - !FindInMap [environments, !Ref env, sb1]
              - !FindInMap [environments, !Ref env, sb2]
    

    You could alternately store the subnet ids in param store at paths like;

    /myapp/dev/subnet1
    /myapp/dev/subnet2
    /myapp/prod/subnet1
    /myapp/prod/subnet2
    

    Then, reference them in your template like this;

              - !Sub '{{resolve:ssm:/myapp/${env}/subnet1}}'
              - !Sub '{{resolve:ssm:/myapp/${env}/subnet2}}'
    

    You could use conditions as well.

    Conditions:
      IsDevEnvironment: !Equals [!Ref env, 'dev']
    

    Then add in the condition to the resource. You would need two distinct resources, one for dev and one for prod then, though.

      HealthCheckFunctionDevelopment:
        Type: AWS::Serverless::Function
        Condition: IsDevEnvironment
        Properties:
          ...
          VpcConfig:
            Ipv6AllowedForDualStack: false
            SecurityGroupIds:
              - !Ref genericSecurityGroup
            SubnetIds:
              - subnet1-harcoded
              - subnet2-harcoded