Dynamic environment variables for AWS Lambda using cloudformation template

18,101

So, I tried so many ways to achieve this, but we can not pass the dynamic key-value pair to nested lambda stack from the parent stack. I had a confirmation from the AWS support that this is not possible as this moment.

They suggested a another way which I liked and implemented and its mentioned as below:

Pass the key: value pair as a JSON string and parse it appropriately in the lambda function.

Environment:
  Variables:
    Env1: '{"REGION": "REGION_VALUE", "ENDPOINT": "http://SOME_ENDPOINT"}'  

This suggestion has a little overhead on programming to parse the JSON string, but at this moment I will recommend this as solution for above problem.

Share:
18,101
Rishikesh Darandale
Author by

Rishikesh Darandale

A developer, reader and learner!

Updated on June 18, 2022

Comments

  • Rishikesh Darandale
    Rishikesh Darandale almost 2 years

    I have to use AWS lambda in various stack of my application, thus I have created a generic cloud-formation template to create a lambda function. This template can be included in another cloud-formation template for further use as a nested stack.

        # Basics
    AWSTemplateFormatVersion: '2010-09-09'
    Description: AWS CloudFormation Template to create a lambda function for java 8 or nodejs
    
    # Parameters
    Parameters:
      FunctionName:
        Type: String
        Description: Funciton Name
      HandlerName:
        Type: String
        Description: Handler Name
      FunctionCodeS3Bucket:
        Type: String
        Description: Name of s3 bucket where the function code is present
        Default: my-deployment-bucket
      FunctionCodeS3Key:
        Type: String
        Description: Function code present in s3 bucket
      MemorySize:
        Type: Number
        Description: Memory size between 128 MB - 1536 MB and multiple of 64
        MinValue: '128'
        MaxValue: '1536'
        Default: '128'
      RoleARN:
        Type: String
        Description: Role ARN for this function
      Runtime:
        Type: String
        Description: Runtime Environment name e.g nodejs, java8
        AllowedPattern: ^(nodejs6.10|nodejs4.3|java8)$
        ConstraintDescription: must be a valid environment (nodejs6.10|nodejs4.3|java8) name.
      Timeout:
        Type: Number
        Description: Timeout in seconds
        Default: '3'
      Env1:
        Type: String
        Description: Environment Variable with format Key|value
        Default: ''
      Env2:
        Type: String
        Description: Environment Variable with format Key|value
        Default: ''
      Env3:
        Type: String
        Description: Environment Variable with format Key|value
        Default: ''
      Env4:
        Type: String
        Description: Environment Variable with format Key|value
        Default: ''
    
    # Conditions
    Conditions:
      Env1Exist: !Not [ !Equals [!Ref Env1, '']]
      Env2Exist: !Not [ !Equals [!Ref Env2, '']]
      Env3Exist: !Not [ !Equals [!Ref Env3, '']]
      Env4Exist: !Not [ !Equals [!Ref Env4, '']]
    
    # Resources
    Resources:
      LambdaFunction:
        Type: AWS::Lambda::Function
        Properties:
          Code:
            S3Bucket: !Ref 'FunctionCodeS3Bucket'
            S3Key: !Ref 'FunctionCodeS3Key'
          Description: !Sub 'Lambda function for: ${FunctionName}'
          Environment:
            Variables:
              'Fn::If':
                - Env1Exist
                -
                  - !Select [0, !Split ["|", !Ref Env1]]: !Select [1, !Split ["|", !Ref Env1]]
                  - 'Fn::If':
                    - Env2Exist
                    - !Select [0, !Split ["|", !Ref Env2]]: !Select [1, !Split ["|", !Ref Env2]]
                    - !Ref "AWS::NoValue"
                  - 'Fn::If':
                    - Env3Exist
                    - !Select [0, !Split ["|", !Ref Env3]]: !Select [1, !Split ["|", !Ref Env3]]
                    - !Ref "AWS::NoValue"
                  - 'Fn::If':
                    - Env4Exist
                    - !Select [0, !Split ["|", !Ref Env4]]: !Select [1, !Split ["|", !Ref Env4]]
                    - !Ref "AWS::NoValue"
                - !Ref "AWS::NoValue"
          FunctionName: !Ref 'FunctionName'
          Handler: !Ref 'HandlerName'
          MemorySize: !Ref 'MemorySize'
          Role: !Ref 'RoleARN'
          Runtime: !Ref 'Runtime'
          Timeout: !Ref 'Timeout'
    Outputs:
      LambdaFunctionARN:
        Value: !GetAtt 'LambdaFunction.Arn'
    

    I want to inject the environment variables to the the function and that will be passed from parent stack as below:

    # Resouces
    Resources:
      # Lambda for search Function
      ChildStackLambdaFunction:
        Type: AWS::CloudFormation::Stack
        Properties:
          TemplateURL: <<REF_TO_ABOVE_LAMBDA_STACK.yml>>
          Parameters:
            FunctionName: test
            HandlerName: 'index.handler'
            FunctionCodeS3Bucket: <<BUCKET_NAME>>
            FunctionCodeS3Key: <<FUNCTION_DEPLOYMENT_NAME>>
            MemorySize: '256'
            RoleARN: <<ROLE_ARN>>
            Runtime: nodejs6.10
            Timeout: '60'
            Env1: !Sub 'AWS_REGION|${AWS::Region}'
    

    When I deploy this stack, I am getting below error. Can anybody help me to resolve this one?

    Template format error: [/Resources/LambdaFunction/Type/Environment/Variables/Fn::If/1/0] map keys must be strings; received a map instead

    Passing key-value parameter is referred from here

  • Rishikesh Darandale
    Rishikesh Darandale about 6 years
    Do you have a better one?
  • Steven de Salas
    Steven de Salas about 6 years
    Nope. Hoping someone may come up with it ;)
  • Pavel Bernshtam
    Pavel Bernshtam over 3 years
    Do you have example of such lambda?
  • marcin2x4
    marcin2x4 over 2 years
    Can you share entire code of your lambda stack?