Aws Cloudformation Embedded Python Lambda
Cloudformation stack with embedded python lambda.
Resources diagram
AWS Lambda described as a cloudformation resource:
- Python handler embedded into stack definition
- IAM Policies to send logs to CloudWatch & X-Ray
Cloudformation
CloudWatch
Log group for streaming lambda execution logs
LambdaLogGroup:
Type: 'AWS::Logs::LogGroup'
Properties:
LogGroupName: !Sub '/aws/lambda/${Environment}-python-lambda'
RetentionInDays: 5
IAM Role
Allow creating log stream and xray tracking
LambdaRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: 'Allow'
Principal:
Service:
- 'lambda.amazonaws.com'
Action:
- 'sts:AssumeRole'
# ManagedPolicyArns:
# - !Join
# - ''
# - - 'arn:'
# - !Ref 'AWS::Partition'
# - ':iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole'
Policies:
- PolicyName: !Sub '${Env}-python-lambda'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:CreateLogStream
- logs:PutLogEvents
Resource:
- !Sub "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${Env}-python-lambda:*:*"
- Effect: Allow
Action:
- xray:PutTraceSegments
- xray:PutTelemetryRecords
Resource: '*'
VPC and AWSLambdaVPCAccessExecutionRole
Provides minimum permissions for a Lambda function to execute while accessing a resource within a VPC - create, describe, delete network interfaces and write permissions to CloudWatch Logs.
Python lambda
LambdaFunction:
DependsOn:
- LambdaRole
- LambdaLogGroup
Type: AWS::Lambda::Function
Properties:
Description: 'Python lambda'
FunctionName: !Sub '${Env}-python-lambda'
Handler: index.handler
Runtime: python3.7
MemorySize: 256
Timeout: 30
Environment:
Variables:
VAR_A: !Sub "${Env}.example.templating"
VAR_B: "/A/B/C"
# VpcConfig:
# SecurityGroupIds:
# - Fn::ImportValue: !Sub '${Env}-security-group'
# SubnetIds:
# - Fn::ImportValue: !Sub '${Env}-private-subnet-1'
# - Fn::ImportValue: !Sub '${Env}-private-subnet-2'
TracingConfig:
Mode: Active
Role: !GetAtt LambdaRole.Arn
Code:
ZipFile: |
import os
import json
VAR_A = os.environ['VAR_A']
VAR_B = os.environ['VAR_B']
def handler(event, context):
print("Event: {}".format(event))
body = {
'a': VAR_A,
'b': VAR_B,
}
result = {
'statusCode': 200,
'headers': {},
'body': body,
}
return result
VPC and Subnets
Configuration must be provided with security group ENI will be bound and a list of subnets lambda will be deployed to.
Template
Complete cloudformation template
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Embedded python lambda.'
Parameters:
Env:
Type: 'String'
Description: 'Logical environment dev|test etc'
Resources:
LambdaLogGroup:
Type: 'AWS::Logs::LogGroup'
Properties:
LogGroupName: !Sub '/aws/lambda/${Env}-python-lambda'
RetentionInDays: 5
LambdaRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: 'Allow'
Principal:
Service:
- 'lambda.amazonaws.com'
Action:
- 'sts:AssumeRole'
# ManagedPolicyArns:
# - !Join
# - ''
# - - 'arn:'
# - !Ref 'AWS::Partition'
# - ':iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole'
Policies:
- PolicyName: !Sub '${Env}-python-lambda'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:CreateLogStream
- logs:PutLogEvents
Resource:
- !Sub "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${Env}-python-lambda:*:*"
- Effect: Allow
Action:
- xray:PutTraceSegments
- xray:PutTelemetryRecords
Resource: '*'
LambdaFunction:
DependsOn:
- LambdaRole
- LambdaLogGroup
Type: AWS::Lambda::Function
Properties:
Description: 'Python lambda'
FunctionName: !Sub '${Env}-python-lambda'
Handler: index.handler
Runtime: python3.7
MemorySize: 256
Timeout: 30
Environment:
Variables:
VAR_A: !Sub "${Env}.example.templating"
VAR_B: "/A/B/C"
# VpcConfig:
# SecurityGroupIds:
# - Fn::ImportValue: !Sub '${Env}-security-group'
# SubnetIds:
# - Fn::ImportValue: !Sub '${Env}-private-subnet-1'
# - Fn::ImportValue: !Sub '${Env}-private-subnet-2'
TracingConfig:
Mode: Active
Role: !GetAtt LambdaRole.Arn
Code:
ZipFile: |
import os
import json
VAR_A = os.environ['VAR_A']
VAR_B = os.environ['VAR_B']
def handler(event, context):
print("Event: {}".format(event))
body = {
'a': VAR_A,
'b': VAR_B,
}
result = {
'statusCode': 200,
'headers': {},
'body': body,
}
return result
Notes
Handy thing when lambda is used as a glue point between services and can simply be part of infrastructure configuration.