Background
I’m going to assume you have experience with Lambda, AWS-SAM, and Cloudformation. To start with you should already have a template.yml for Cloudformation that looks alot like this:
---
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS template
Resources:
ApiGatewayApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
# Allows www.example.com to call these APIs
# SAM will automatically add AllowMethods with a list of methods for this API
Cors: "'www.example.com'"
DefinitionBody:
'Fn::Transform':
Name: 'AWS::Include'
# Replace <bucket> with your bucket name
Parameters:
Location: s3://<bucket>/swagger.yaml
LambdaFunction:
Type: AWS::Serverless::Function
Properties:
# Replace <bucket> with your bucket name
CodeUri: s3://<bucket>/api_swagger_cors.zip
Handler: index.handler
Runtime: nodejs6.10
Events:
ProxyApiRoot:
Type: Api
Properties:
RestApiId: !Ref ApiGatewayApi
Path: /
Method: ANY
ProxyApiGreedy:
Type: Api
Properties:
RestApiId: !Ref ApiGatewayApi
Path: /{proxy+}
Method: ANY
Outputs:
ApiUrl:
Description: URL of your API endpoint
Value: !Join
- ''
- - https://
- !Ref ApiGatewayApi
- '.execute-api.'
- !Ref 'AWS::Region'
- '.amazonaws.com/Prod'
There are two distinct approaches you can take to dynamically retrieve environment variables in Lambda. The approach you take is dictated by how frequently your variable changes.
- Your environment variable changes frequently.
- I would recommend retrieving the variable from an external endpoint. We won’t cover this use case in the blog post.
- Your environment variables is fairly static, but you don’t want to hardcode the variable or make it public in a code repository.
- Retrieving from AWS SSM parameter store as a string is the best option in my opinion.
- Retrieving from AWS SSM parameter store as a string is the best option in my opinion.
Let’s walk through method #2.
- To get started, go to the parameter store and add the name of your environment variable, it’s value and set the type to “String”.
- Cloudformation doesn’t support Secure String at the time of writing.
- Adjust your Cloudformation’s role to be able to access the newly created parameter
- Add the parameter to the Cloudformation template via the following:
MyEnvVarParameterName: Type: 'Aws::SSM::Parameter::Value<String> Default: MyEnvParamaterNameSetInTheStore
- Add the parameter to you lambda function as an environment variable with the following:
MyLambdaEnvName: Ref: MyEnvVarParameterName
- If you would like the environment variable to be hidden from view in the AWS Console then set NoEcho property to true.
So your final version would look something like this:
---
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS Template
Parameters:
MyEnvParameterName:
Type: 'Aws::SSM::Parameter::Value<String>
Default: MyEnvParamaterNameSetInTheStore
Resources:
ApiGatewayApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
# Allows www.example.com to call these APIs
# SAM will automatically add AllowMethods with a list of methods for this API
Cors: "'www.example.com'"
DefinitionBody:
'Fn::Transform':
Name: 'AWS::Include'
# Replace <bucket> with your bucket name
Parameters:
Location: s3://<bucket>/swagger.yaml
LambdaFunction:
Type: AWS::Serverless::Function
Properties:
# Replace <bucket> with your bucket name
CodeUri: s3://<bucket>/api_swagger_cors.zip
Handler: index.handler
Runtime: nodejs6.10
Environment:
Variables:
MyLambdaEnvName:
Ref: MyEnvParameterName
Events:
ProxyApiRoot:
Type: Api
Properties:
RestApiId: !Ref ApiGatewayApi
Path: /
Method: ANY
ProxyApiGreedy:
Type: Api
Properties:
RestApiId: !Ref ApiGatewayApi
Path: /{proxy+}
Method: ANY
Outputs:
ApiUrl:
Description: URL of your API endpoint
Value: !Join
- ''
- - https://
- !Ref ApiGatewayApi
- '.execute-api.'
- !Ref 'AWS::Region'
- '.amazonaws.com/Prod'