AWS CloudFormation Lambda Serverless
Overview
Create production-ready serverless infrastructure using AWS CloudFormation templates. This skill covers Lambda functions, layers, event sources, API Gateway, Step Functions, cold start optimization, and best practices for parameters, outputs, and cross-stack references.
When to Use
Use this skill when:
-
Creating new Lambda functions with CloudFormation
-
Configuring Lambda layers for shared code
-
Integrating Lambda with API Gateway (REST and HTTP API)
-
Implementing event sources (SQS, SNS, EventBridge, S3, DynamoDB)
-
Creating Step Functions with Lambda workflows
-
Optimizing cold start and performance
-
Organizing templates with Parameters, Outputs, Mappings, Conditions
-
Implementing cross-stack references with export/import
-
Using Transform for macros and reuse
CloudFormation Template Structure
Base Template with Standard Format
AWSTemplateFormatVersion: 2010-09-09 Description: Lambda function with API Gateway integration
Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Function Configuration Parameters: - FunctionName - Runtime - Handler - Label: default: Deployment Settings Parameters: - Environment - DeployStage
Parameters: FunctionName: Type: String Default: my-lambda-function Description: Name of the Lambda function
Runtime: Type: String Default: python3.11 AllowedValues: - python3.8 - python3.9 - python3.10 - python3.11 - nodejs18.x - nodejs20.x - java11 - java17 - java21
Handler: Type: String Default: index.handler
Environment: Type: String Default: dev AllowedValues: - dev - staging - production
DeployStage: Type: String Default: dev
Mappings: EnvironmentConfig: dev: MemorySize: 128 Timeout: 30 ReservedConcurrentExecutions: 5 staging: MemorySize: 256 Timeout: 60 ReservedConcurrentExecutions: 20 production: MemorySize: 512 Timeout: 120 ReservedConcurrentExecutions: 100
Conditions: IsProduction: !Equals [!Ref Environment, production] IsDev: !Equals [!Ref Environment, dev]
Transform:
- AWS::Serverless-2016-10-31
Resources:
Lambda Function
MyLambdaFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Ref FunctionName Runtime: !Ref Runtime Handler: !Ref Handler Code: S3Bucket: !Ref SourceBucket S3Key: !Sub "lambda/${Environment}/function.zip" MemorySize: !FindInMap [EnvironmentConfig, !Ref Environment, MemorySize] Timeout: !FindInMap [EnvironmentConfig, !Ref Environment, Timeout] Role: !GetAtt LambdaExecutionRole.Arn Environment: Variables: ENVIRONMENT: !Ref Environment LOG_LEVEL: !If [IsProduction, INFO, DEBUG] Tags: - Key: Environment Value: !Ref Environment - Key: Project Value: !Ref ProjectName
Outputs: LambdaFunctionArn: Description: ARN of the Lambda function Value: !GetAtt MyLambdaFunction.Arn Export: Name: !Sub "${AWS::StackName}-LambdaFunctionArn"
Best Practices for Parameters
AWS-Specific Parameter Types
Parameters:
AWS-specific types for validation
VPCId: Type: AWS::EC2::VPC::Id Description: VPC where Lambda will run
SubnetIds: Type: List<AWS::EC2::Subnet::Id> Description: Subnets for Lambda VPC config
SecurityGroupIds: Type: List<AWS::EC2::SecurityGroup::Id> Description: Security groups for Lambda
LambdaRuntime: Type: AWS::Lambda::Runtime Description: Lambda runtime selection
IAMRoleArn: Type: AWS::IAM::Role::Arn Description: IAM role for Lambda execution
S3BucketForCode: Type: AWS::S3::Bucket Description: S3 bucket for Lambda code
KMSKeyArn: Type: AWS::KMS::Key::Arn Description: KMS key for environment variables
Parameter Constraints
Parameters: FunctionName: Type: String Default: my-function Description: Lambda function name ConstraintDescription: Must be 1-64 characters, alphanumeric and hyphens MinLength: 1 MaxLength: 64 AllowedPattern: "[a-zA-Z0-9-_]+"
MemorySize: Type: Number Default: 128 Description: Memory allocation in MB MinValue: 128 MaxValue: 10240 ConstraintDescription: Must be between 128 and 10240 MB
Timeout: Type: Number Default: 30 Description: Function timeout in seconds MinValue: 1 MaxValue: 900 ConstraintDescription: Must be between 1 and 900 seconds
EnvironmentName: Type: String Default: dev Description: Deployment environment AllowedValues: - dev - staging - production ConstraintDescription: Must be dev, staging, or production
SSM Parameter References
Parameters: DatabaseConnectionString: Type: AWS::SSM::Parameter::Value<String> Default: /myapp/database/connection-string Description: Database connection string from SSM
ApiKey: Type: AWS::SSM::Parameter::Value<SecureString> Default: /myapp/external-api/key Description: API key from SSM Parameter Store
Outputs and Cross-Stack References
Export/Import Patterns
Stack A - Network Stack
AWSTemplateFormatVersion: 2010-09-09 Description: Network infrastructure stack
Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16 EnableDnsHostnames: true EnableDnsSupport: true Tags: - Key: Name Value: !Sub "${AWS::StackName}-vpc"
Outputs: VPCId: Description: VPC ID Value: !Ref VPC Export: Name: !Sub "${AWS::StackName}-VPCId"
PublicSubnetIds: Description: Public subnet IDs Value: !Join [",", [!Ref PublicSubnet1, !Ref PublicSubnet2]] Export: Name: !Sub "${AWS::StackName}-PublicSubnetIds"
PrivateSubnetIds: Description: Private subnet IDs Value: !Join [",", [!Ref PrivateSubnet1, !Ref PrivateSubnet2]] Export: Name: !Sub "${AWS::StackName}-PrivateSubnetIds"
LambdaSecurityGroupId: Description: Security group ID for Lambda Value: !Ref LambdaSecurityGroup Export: Name: !Sub "${AWS::StackName}-LambdaSecurityGroupId"
Stack B - Application Stack (imports from Stack A)
AWSTemplateFormatVersion: 2010-09-09 Description: Lambda application stack
Parameters: NetworkStackName: Type: String Default: network-stack Description: Name of the network stack
Resources: MyLambdaFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Sub "${AWS::StackName}-processor" Runtime: python3.11 Handler: index.handler Code: S3Bucket: !Ref CodeBucket S3Key: lambda/function.zip Role: !GetAtt LambdaExecutionRole.Arn VpcConfig: SecurityGroupIds: - !ImportValue !Sub "${NetworkStackName}-LambdaSecurityGroupId" SubnetIds: - !Select [0, !Split [",", !ImportValue !Sub "${NetworkStackName}-PrivateSubnetIds"]] - !Select [1, !Split [",", !ImportValue !Sub "${NetworkStackName}-PrivateSubnetIds"]]
Nested Stacks for Modularity
AWSTemplateFormatVersion: 2010-09-09 Description: Main stack with nested Lambda stacks
Resources:
Nested stack for Lambda functions
LambdaFunctionsStack: Type: AWS::CloudFormation::Stack Properties: TemplateURL: https://s3.amazonaws.com/bucket/lambda-functions.yaml TimeoutInMinutes: 15 Parameters: Environment: !Ref Environment FunctionNamePrefix: !Ref FunctionNamePrefix
Nested stack for API Gateway
ApiGatewayStack: Type: AWS::CloudFormation::Stack Properties: TemplateURL: https://s3.amazonaws.com/bucket/api-gateway.yaml TimeoutInMinutes: 15 Parameters: Environment: !Ref Environment LambdaFunctionArn: !GetAtt LambdaFunctionsStack.Outputs.FunctionArn
Lambda Functions with Advanced Configurations
Lambda Base with VPC and Environment
AWSTemplateFormatVersion: 2010-09-09 Description: Lambda function with VPC, environment variables, and monitoring
Parameters: Environment: Type: String Default: dev AllowedValues: - dev - staging - production
VpcConfig: Type: String Default: full AllowedValues: - none - full - internal
Resources: LambdaExecutionRole: Type: AWS::IAM::Role Properties: RoleName: !Sub "${AWS::StackName}-lambda-role" AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Policies: - PolicyName: !Sub "${AWS::StackName}-vpc-policy" PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - ec2:CreateNetworkInterface - ec2:DescribeNetworkInterfaces - ec2:DeleteNetworkInterface Resource: "*" - PolicyName: !Sub "${AWS::StackName}-secrets-policy" PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - secretsmanager:GetSecretValue Resource: !Ref SecretsArn
MyLambdaFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Sub "${AWS::StackName}-processor" Runtime: python3.11 Handler: index.handler Code: S3Bucket: !Ref CodeBucket S3Key: !Sub "lambda/${Environment}/function.zip" MemorySize: 256 Timeout: 60 Role: !GetAtt LambdaExecutionRole.Arn VpcConfig: !If - IsFullVpc - SecurityGroupIds: - !Ref LambdaSecurityGroup SubnetIds: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 - !Ref AWS::NoValue Environment: Variables: ENVIRONMENT: !Ref Environment LOG_LEVEL: !If [IsProduction, INFO, DEBUG] DB_HOST: !Ref DatabaseHost DB_NAME: !Ref DatabaseName TracingConfig: Mode: !If [IsProduction, Active, PassThrough] Tags: - Key: Environment Value: !Ref Environment - Key: Project Value: !Ref ProjectName - Key: CostCenter Value: !Ref CostCenter
LambdaFunctionUrl: Type: AWS::Lambda::Url Properties: AuthType: AWS_IAM TargetFunctionArn: !GetAtt MyLambdaFunction.Arn Cors: AllowCredentials: true AllowHeaders: - "" AllowMethods: - GET - POST AllowOrigins: - !If [IsProduction, !Ref ProductionCorsOrigin, ""] MaxAge: 86400
Conditions: IsFullVpc: !Equals [!Ref VpcConfig, full] IsProduction: !Equals [!Ref Environment, production]
Lambda with Provisioned Concurrency
Resources: MyLambdaFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Sub "${AWS::StackName}-api" Runtime: python3.11 Handler: app.handler Code: S3Bucket: !Ref CodeBucket S3Key: lambda/api.zip MemorySize: 512 Timeout: 30 Role: !GetAtt LambdaExecutionRole.Arn
ProvisionedConcurrencyConfig: Type: AWS::Lambda::ProvisionedConcurrencyConfig Properties: FunctionName: !Ref MyLambdaFunction ProvisionedConcurrentExecutions: 5 ProvisionedExecutionTarget: AllocationStrategy: PRICE_OPTIMIZED
Lambda Layers
AWSTemplateFormatVersion: 2010-09-09 Description: Lambda function with layers
Resources: CommonLibraryLayer: Type: AWS::Lambda::LayerVersion Properties: LayerName: !Sub "${AWS::StackName}-common-lib" Description: Common utilities for Lambda functions Content: S3Bucket: !Ref LayersBucket S3Key: layers/common-lib.zip CompatibleRuntimes: - python3.9 - python3.10 - python3.11 CompatibleArchitectures: - x86_64 - arm64
DataProcessingLayer: Type: AWS::Lambda::LayerVersion Properties: LayerName: !Sub "${AWS::StackName}-data-processing" Description: Data processing utilities Content: S3Bucket: !Ref LayersBucket S3Key: layers/data-processing.zip CompatibleRuntimes: - python3.11
MyLambdaFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Sub "${AWS::StackName}-processor" Runtime: python3.11 Handler: index.handler Code: S3Bucket: !Ref CodeBucket S3Key: lambda/processor.zip Layers: - !Ref CommonLibraryLayer - !Ref DataProcessingLayer
API Gateway Integration
API Gateway REST with Lambda Proxy
AWSTemplateFormatVersion: 2010-09-09 Description: API Gateway REST with Lambda proxy integration
Resources: ApiGatewayRestApi: Type: AWS::ApiGateway::RestApi Properties: Name: !Sub "${AWS::StackName}-api" Description: REST API for Lambda backend EndpointConfiguration: Types: - REGIONAL MinimumCompressionSize: 1024 DisableExecuteApiEndpoint: false
ApiGatewayResource: Type: AWS::ApiGateway::Resource Properties: RestApiId: !Ref ApiGatewayRestApi ParentId: !GetAtt ApiGatewayRestApi.RootResourceId PathPart: items
ApiGatewayMethod: Type: AWS::ApiGateway::Method Properties: RestApiId: !Ref ApiGatewayRestApi ResourceId: !Ref ApiGatewayResource HttpMethod: GET AuthorizationType: COGNITO_USER_POOLS AuthorizerId: !Ref ApiGatewayAuthorizer RequestParameters: method.request.querystring.id: true Integration: Type: AWS_PROXY IntegrationHttpMethod: POST Uri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyLambdaFunction.Arn}/invocations" IntegrationResponses: - StatusCode: 200 ResponseParameters: method.response.header.Access-Control-Allow-Origin: "'*'" method.response.header.Content-Type: "'application/json'" PassthroughBehavior: WHEN_NO_MATCH MethodResponses: - StatusCode: 200 ResponseModels: application/json: Empty ResponseParameters: method.response.header.Access-Control-Allow-Origin: true
ApiGatewayDeployment: Type: AWS::ApiGateway::Deployment DependsOn: ApiGatewayMethod Properties: RestApiId: !Ref ApiGatewayRestApi StageName: !Ref DeployStage StageDescription: LoggingLevel: !If [IsProduction, INFO, ERROR] DataTraceEnabled: !If [IsProduction, false, true] MetricsEnabled: true ThrottlingRateLimit: 100 ThrottlingBurstLimit: 200 Variables: Environment: !Ref Environment
LambdaPermission: Type: AWS::Lambda::Permission Properties: FunctionName: !Ref MyLambdaFunction Action: lambda:InvokeFunction Principal: apigateway.amazonaws.com SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiGatewayRestApi}///*"
ApiGatewayAuthorizer: Type: AWS::ApiGateway::Authorizer Properties: Name: !Sub "${AWS::StackName}-authorizer" Type: COGNITO_USER_POOLS RestApiId: !Ref ApiGatewayRestApi ProviderARNs: - !Ref CognitoUserPoolArn IdentitySource: method.request.header.Authorization AuthorizerResultTtlInSeconds: 300
Outputs: ApiEndpoint: Description: API Gateway endpoint URL Value: !Sub "https://${ApiGatewayRestApi}.execute-api.${AWS::Region}.amazonaws.com/${DeployStage}/items"
API Gateway HTTP API with Lambda
Resources: HttpApi: Type: AWS::ApiGatewayV2::Api Properties: Name: !Sub "${AWS::StackName}-http-api" ProtocolType: HTTP CorsConfiguration: AllowOrigins: - !If [IsProduction, !Ref ProductionDomain, ""] AllowMethods: - GET - POST - PUT - DELETE - OPTIONS AllowHeaders: - "" MaxAge: 86400
HttpApiStage: Type: AWS::ApiGatewayV2::Stage Properties: ApiId: !Ref HttpApi StageName: !Ref DeployStage AutoDeploy: true DefaultRouteSettings: DetailedMetricsEnabled: true ThrottlingBurstLimit: 100 ThrottlingRateLimit: 50
HttpApiIntegration: Type: AWS::ApiGatewayV2::Integration Properties: ApiId: !Ref HttpApi IntegrationType: AWS_PROXY IntegrationUri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyLambdaFunction.Arn}/invocations" PayloadFormatVersion: "2.0"
HttpApiRoute: Type: AWS::ApiGatewayV2::Route Properties: ApiId: !Ref HttpApi RouteKey: ANY /items/{id} Target: !Sub "integrations/${HttpApiIntegration.Id}"
Event Sources
SQS Event Source
Resources: MyLambdaFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Sub "${AWS::StackName}-sqs-processor" Runtime: python3.11 Handler: sqs_handler.handler Code: S3Bucket: !Ref CodeBucket S3Key: lambda/sqs-processor.zip Timeout: 300 Role: !GetAtt LambdaExecutionRole.Arn
Queue: Type: AWS::SQS::Queue Properties: QueueName: !Sub "${AWS::StackName}-queue" VisibilityTimeout: 360 MessageRetentionPeriod: 1209600 RedrivePolicy: deadLetterTargetArn: !GetAtt DeadLetterQueue.Arn maxReceiveCount: 5
DeadLetterQueue: Type: AWS::SQS::Queue Properties: QueueName: !Sub "${AWS::StackName}-dlq"
EventSourceMapping: Type: AWS::Lambda::EventSourceMapping Properties: FunctionName: !Ref MyLambdaFunction EventSourceArn: !GetAtt Queue.Arn BatchSize: 10 MaximumBatchingWindowInSeconds: 60 ScalingConfig: MaximumConcurrency: 10 FilterCriteria: Filters: - Pattern: '{"body": {"messageType": ["order", "notification"]}}' Enabled: true
LambdaExecutionRole: Type: AWS::IAM::Role Properties: RoleName: !Sub "${AWS::StackName}-sqs-role" AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaSQSQueueExecutionRole Policies: - PolicyName: !Sub "${AWS::StackName}-dlq-policy" PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - sqs:DeleteMessage - sqs:ReceiveMessage Resource: !GetAtt DeadLetterQueue.Arn
SNS Event Source
Resources: MyLambdaFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Sub "${AWS::StackName}-sns-processor" Runtime: python3.11 Handler: sns_handler.handler Code: S3Bucket: !Ref CodeBucket S3Key: lambda/sns-processor.zip
Topic: Type: AWS::SNS::Topic Properties: TopicName: !Sub "${AWS::StackName}-topic" DisplayName: !Sub "${AWS::StackName} Notifications" Subscription: - Endpoint: !GetAtt MyLambdaFunction.Arn Protocol: lambda Tags: - Key: Environment Value: !Ref Environment
TopicPolicy: Type: AWS::SNS::TopicPolicy Properties: Topics: - !Ref Topic PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: sns.amazonaws.com Action: sns:Publish Resource: !Ref Topic
LambdaPermission: Type: AWS::Lambda::Permission Properties: FunctionName: !Ref MyLambdaFunction Action: lambda:InvokeFunction Principal: sns.amazonaws.com SourceArn: !Ref Topic
EventBridge (CloudWatch Events)
Resources: MyLambdaFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Sub "${AWS::StackName}-scheduler" Runtime: python3.11 Handler: scheduler.handler Code: S3Bucket: !Ref CodeBucket S3Key: lambda/scheduler.zip Timeout: 300 Role: !GetAtt LambdaExecutionRole.Arn
ScheduledRule: Type: AWS::Events::Rule Properties: Name: !Sub "${AWS::StackName}-scheduled-rule" ScheduleExpression: "rate(5 minutes)" State: ENABLED Targets: - Id: !Ref MyLambdaFunction Arn: !GetAtt MyLambdaFunction.Arn RetryPolicy: MaximumEventAgeInSeconds: 86400 MaximumRetryAttempts: 3
LambdaPermission: Type: AWS::Lambda::Permission Properties: FunctionName: !Ref MyLambdaFunction Action: lambda:InvokeFunction Principal: events.amazonaws.com SourceArn: !GetAtt ScheduledRule.Arn
S3 Event Source
Resources: MyLambdaFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Sub "${AWS::StackName}-s3-processor" Runtime: python3.11 Handler: s3_handler.handler Code: S3Bucket: !Ref CodeBucket S3Key: lambda/s3-processor.zip Timeout: 300 Role: !GetAtt LambdaExecutionRole.Arn
Bucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub "${AWS::StackName}-uploads-${AWS::AccountId}-${AWS::Region}" PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 VersioningConfiguration: Status: Enabled NotificationConfiguration: LambdaConfigurations: - Event: s3:ObjectCreated:* Filter: S3Key: Rules: - Name: suffix Value: .csv Function: !GetAtt MyLambdaFunction.Arn - Event: s3:ObjectCreated:* Filter: S3Key: Rules: - Name: prefix Value: processed/ Function: !GetAtt MyLambdaFunction.Arn
LambdaPermission: Type: AWS::Lambda::Permission Properties: FunctionName: !Ref MyLambdaFunction Action: lambda:InvokeFunction Principal: s3.amazonaws.com SourceArn: !GetAtt Bucket.Arn
Step Functions Integration
AWSTemplateFormatVersion: 2010-09-09 Description: Step Functions with Lambda tasks
Resources:
Lambda functions for Step Functions
ProcessItemFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Sub "${AWS::StackName}-process-item" Runtime: python3.11 Handler: process_item.handler Code: S3Bucket: !Ref CodeBucket S3Key: lambda/process-item.zip Timeout: 300 Role: !GetAtt LambdaExecutionRole.Arn
ValidateItemFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Sub "${AWS::StackName}-validate-item" Runtime: python3.11 Handler: validate_item.handler Code: S3Bucket: !Ref CodeBucket S3Key: lambda/validate-item.zip Timeout: 60 Role: !GetAtt LambdaExecutionRole.Arn
NotifyCompletionFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Sub "${AWS::StackName}-notify-completion" Runtime: python3.11 Handler: notify.handler Code: S3Bucket: !Ref CodeBucket S3Key: lambda/notify.zip Timeout: 60 Role: !GetAtt LambdaExecutionRole.Arn
Step Functions State Machine
ProcessingStateMachine: Type: AWS::StepFunctions::StateMachine Properties: StateMachineName: !Sub "${AWS::StackName}-processor" StateMachineType: STANDARD DefinitionString: !Sub | { "Comment": "Item processing state machine", "StartAt": "ValidateItem", "States": { "ValidateItem": { "Type": "Task", "Resource": "${ValidateItemFunction.Arn}", "Retry": [ { "ErrorEquals": ["States.TaskFailed"], "IntervalSeconds": 2, "MaxAttempts": 3, "BackoffRate": 2 } ], "Next": "ProcessItem" }, "ProcessItem": { "Type": "Task", "Resource": "${ProcessItemFunction.Arn}", "Retry": [ { "ErrorEquals": ["States.TaskFailed"], "IntervalSeconds": 5, "MaxAttempts": 2, "BackoffRate": 2 } ], "Catch": [ { "ErrorEquals": ["States.ALL"], "Next": "HandleFailure" } ], "Next": "NotifyCompletion" }, "NotifyCompletion": { "Type": "Task", "Resource": "${NotifyCompletionFunction.Arn}", "End": true }, "HandleFailure": { "Type": "Pass", "End": true } } } RoleArn: !GetAtt StepFunctionsExecutionRole.Arn LoggingConfiguration: Level: ALL IncludeExecutionData: true Destinations: - CloudWatchLogsLogGroup: !Ref StateMachineLogGroup
StepFunctionsExecutionRole: Type: AWS::IAM::Role Properties: RoleName: !Sub "${AWS::StackName}-sfn-role" AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: states.amazonaws.com Action: sts:AssumeRole Policies: - PolicyName: !Sub "${AWS::StackName}-lambda-invoke" PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - lambda:InvokeFunction Resource: - !GetAtt ProcessItemFunction.Arn - !GetAtt ValidateItemFunction.Arn - !GetAtt NotifyCompletionFunction.Arn
StateMachineLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub "/aws/state-machine/${AWS::StackName}" RetentionInDays: 30
Cold Start Optimization
AWSTemplateFormatVersion: 2010-09-09 Description: Lambda function optimized for cold start
Parameters: Environment: Type: String Default: dev AllowedValues: - dev - staging - production
Resources:
Use AWS::Serverless::Function for better cold start
OptimizedLambdaFunction: Type: AWS::Serverless::Function Properties: FunctionName: !Sub "${AWS::StackName}-optimized" CodeUri: s3://bucket/function.zip Handler: app.handler Runtime: python3.11 MemorySize: 512 Timeout: 30 EphemeralStorage: Size: 1024 SnapStart: ApplyOn: PublishedVersions ProvisionedConcurrencyConfig: ProvisionedConcurrentExecutions: !If [IsProduction, 5, 0] Layers: - !Ref CommonDependenciesLayer Environment: Variables: PYTHONPATH: "/var/task:/opt" Policies: - AWSLambdaVPCAccessExecutionRole - AmazonS3ReadOnlyAccess VpcConfig: SecurityGroupIds: - !Ref LambdaSecurityGroup SubnetIds: !Ref PrivateSubnetIds EventInvokeConfig: MaximumEventAgeInSeconds: 3600 MaximumRetryAttempts: 2
Optimized layer with pre-installed dependencies
CommonDependenciesLayer: Type: AWS::Serverless::LayerVersion Properties: LayerName: !Sub "${AWS::StackName}-dependencies" Description: Pre-installed Python dependencies for Lambda ContentUri: s3://bucket/layers/dependencies.zip CompatibleRuntimes: - python3.11 CompatibleArchitectures: - x86_64 RetentionPolicy: Retain
Conditions: IsProduction: !Equals [!Ref Environment, production]
Outputs: FunctionArn: Description: Lambda function ARN Value: !GetAtt OptimizedLambdaFunction.Arn FunctionUrl: Description: Lambda function URL for direct invocation Value: !GetAtt OptimizedLambdaFunction.Url
Monitoring and Logging
AWSTemplateFormatVersion: 2010-09-09 Description: Lambda with comprehensive monitoring
Resources: MyLambdaFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Sub "${AWS::StackName}-monitored" Runtime: python3.11 Handler: app.handler Code: S3Bucket: !Ref CodeBucket S3Key: lambda/function.zip Role: !GetAtt LambdaExecutionRole.Arn TracingConfig: Mode: Active
Log group with retention
LambdaLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub "/aws/lambda/${AWS::StackName}-monitored" RetentionInDays: 30 KmsKeyId: !Ref LogKmsKey
Metric filter for errors
ErrorMetricFilter: Type: AWS::Logs::MetricFilter Properties: LogGroupName: !Ref LambdaLogGroup FilterPattern: 'ERROR' MetricTransformations: - MetricValue: "1" MetricNamespace: !Sub "${AWS::StackName}/Lambda" MetricName: ErrorCount
CloudWatch Alarms
HighErrorRateAlarm: Type: AWS::CloudWatch::Alarm Properties: AlarmName: !Sub "${AWS::StackName}-high-error-rate" AlarmDescription: Alert when error rate exceeds threshold MetricName: Errors Namespace: AWS/Lambda Dimensions: - Name: FunctionName Value: !Ref MyLambdaFunction Statistic: Sum Period: 60 EvaluationPeriods: 5 Threshold: 10 ComparisonOperator: GreaterThanThreshold AlarmActions: - !Ref AlertTopic
HighThrottlesAlarm: Type: AWS::CloudWatch::Alarm Properties: AlarmName: !Sub "${AWS::StackName}-high-throttles" AlarmDescription: Alert when throttling occurs MetricName: Throttles Namespace: AWS/Lambda Dimensions: - Name: FunctionName Value: !Ref MyLambdaFunction Statistic: Sum Period: 60 EvaluationPeriods: 3 Threshold: 5 ComparisonOperator: GreaterThanThreshold
AlertTopic: Type: AWS::SNS::Topic Properties: TopicName: !Sub "${AWS::StackName}-alerts"
Lambda Destination for async invocations
LambdaDestination: Type: AWS::Lambda::EventInvokeConfig Properties: FunctionName: !Ref MyLambdaFunction MaximumEventAgeInSeconds: 3600 MaximumRetryAttempts: 2 Qualifier: $LATEST
Conditions and Transform
Conditions for Environment-Specific Resources
AWSTemplateFormatVersion: 2010-09-09 Description: Lambda with conditional resources
Parameters: Environment: Type: String Default: dev AllowedValues: - dev - staging - production Description: Deployment environment
Conditions: IsProduction: !Equals [!Ref Environment, production] IsStaging: !Equals [!Ref Environment, staging] CreateDeadLetterQueue: !Or [!Equals [!Ref Environment, staging], !Equals [!Ref Environment, production]] EnableXray: !Not [!Equals [!Ref Environment, dev]]
Resources: MyLambdaFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Sub "${AWS::StackName}-function" Runtime: python3.11 Handler: app.handler Code: S3Bucket: !Ref CodeBucket S3Key: !Sub "lambda/${Environment}/function.zip" Timeout: !If [IsProduction, 60, 30] MemorySize: !If [IsProduction, 512, 256] Role: !GetAtt LambdaExecutionRole.Arn TracingConfig: !If - EnableXray - Mode: Active - !Ref AWS::NoValue Environment: Variables: LOG_LEVEL: !If [IsProduction, INFO, DEBUG]
DeadLetterQueue: Type: AWS::SQS::Queue Condition: CreateDeadLetterQueue Properties: QueueName: !Sub "${AWS::StackName}-dlq"
Transform for Code Reuse
AWSTemplateFormatVersion: 2010-09-09 Transform: AWS::Serverless-2016-10-31
Description: Using SAM Transform for Lambda
Globals: Function: Timeout: 30 Runtime: python3.11 Tracing: Active Environment: Variables: LOG_LEVEL: INFO Metadata: DockerBuild: true Dockerfile: Dockerfile DockerContext: lambda_function/
Resources: MyFunction: Type: AWS::Serverless::Function Properties: FunctionName: !Sub "${AWS::StackName}-sam-function" Handler: app.handler CodeUri: lambda_function/ Policies: - S3ReadPolicy: BucketName: !Ref DataBucket - DynamoDBReadPolicy: TableName: !Ref DataTable Events: Api: Type: Api Properties: Path: /items Method: get SqsQueue: Type: SQS Properties: Queue: !GetAtt Queue.Arn BatchSize: 10 AutoPublishAlias: !Ref Environment DeploymentPreference: Type: !Ref DeploymentConfig Alarms: - !Ref ErrorAlarm - !Ref LatencyAlarm
DataTable: Type: AWS::Serverless::SimpleTable Properties: TableName: !Sub "${AWS::StackName}-table" PrimaryKey: Name: id Type: String
Parameters: Environment: Type: String Default: dev DeploymentConfig: Type: String Default: AllAtOnce AllowedValues: - Canary10Percent5Minutes - Canary10Percent10Minutes - Canary10Percent15Minutes - AllAtOnce - Linear10PercentEvery1Minute - Linear10PercentEvery2Minutes - Linear10PercentEvery3Minutes
Best Practices
Security
-
Use IAM roles with minimum necessary permissions
-
Encrypt environment variables with KMS
-
Use VPC for private resource access
-
Configure resource-based policies for invocations
-
Enable AWS WAF for API Gateway protection
-
Use API keys and throttling for protection
Performance
-
Choose memory size based on profiling
-
Use provisioned concurrency for critical latency
-
Optimize package size for cold start
-
Use layers for shared dependencies
-
Pre-compile code for interpreted languages
-
Consider SnapStart for Java/.NET
Monitoring
-
Enable detailed metrics and tracing
-
Configure appropriate log retention
-
Create alarms for errors and throttling
-
Use Lambda destinations for async error handling
-
Implement distributed tracing
Deployment
-
Use change sets before deployment
-
Test templates with cfn-lint
-
Organize stacks by lifecycle and ownership
-
Use nested stacks for modularity
-
Implement blue/green deployments
CloudFormation Stack Management Best Practices
Stack Policies
Stack policies protect stack resources from unintentional updates that could cause critical changes or deletions.
Resources: LambdaFunction: Type: AWS::Lambda::Function Properties: # Function configuration
Stack policy to protect Lambda function from updates
StackPolicy: Type: AWS::CloudFormation::StackPolicy Properties: PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: "" Action: "Update:" Resource: "" - Effect: Deny Principal: "" Action: - Update:Replace - Update:Delete Resource: - LogicalId: LambdaFunction ResourceType: AWS::Lambda::Function Condition: StringEquals: ResourceAttribute: Arn: Fn::Ref: LambdaFunction
Termination Protection
Enable termination protection to prevent accidental stack deletion, especially for production environments.
AWSTemplateFormatVersion: 2010-09-09 Description: Lambda function with termination protection
Resources: MyLambdaFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Sub "${AWS::StackName}-function" Runtime: python3.11 Handler: app.handler Code: S3Bucket: !Ref CodeBucket S3Key: lambda/function.zip Role: !GetAtt LambdaExecutionRole.Arn
Enable termination protection (must be set during stack creation)
This is a stack-level attribute, not a resource
Important: Termination protection must be enabled during stack creation via AWS Console, CLI, or API:
aws cloudformation create-stack
--stack-name my-lambda-stack
--template-body file://template.yaml
--enable-termination-protection
--capabilities CAPABILITY_IAM
Drift Detection
Detect when infrastructure has diverged from the CloudFormation template.
Resources:
All Lambda resources support drift detection
MyLambdaFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Sub "${AWS::StackName}-function" Runtime: python3.11 Handler: app.handler Code: S3Bucket: !Ref CodeBucket S3Key: lambda/function.zip Role: !GetAtt LambdaExecutionRole.Arn Environment: Variables: ENVIRONMENT: !Ref Environment LOG_LEVEL: !Ref LogLevel
CLI commands for drift detection:
Detect drift on a stack
aws cloudformation detect-drift --stack-name my-lambda-stack
Get drift detection status
aws cloudformation describe-stack-drift-detection-status
--stack-drift-detection-id <detection-id>
Get resource drift status
aws cloudformation describe-stack-resource-drifts
--stack-name my-lambda-stack
Compare actual vs expected resource properties
aws cloudformation get-stack-policy --stack-name my-lambda-stack
Change Sets
Use change sets to preview and review stack changes before execution.
Resources: MyLambdaFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Sub "${AWS::StackName}-function" Runtime: python3.11 Handler: app.handler Code: S3Bucket: !Ref CodeBucket S3Key: lambda/function.zip Role: !GetAtt LambdaExecutionRole.Arn MemorySize: !Ref MemorySize Timeout: !Ref Timeout
Parameters: MemorySize: Type: Number Default: 256 Description: Memory allocation in MB
Timeout: Type: Number Default: 30 Description: Function timeout in seconds
Change set workflow:
1. Create a change set
aws cloudformation create-change-set
--stack-name my-lambda-stack
--change-set-name my-changeset
--template-body file://template.yaml
--capabilities CAPABILITY_IAM
--parameters ParameterKey=MemorySize,ParameterValue=512
2. Describe the change set to review changes
aws cloudformation describe-change-set
--stack-name my-lambda-stack
--change-set-name my-changeset
3. Execute the change set
aws cloudformation execute-change-set
--stack-name my-lambda-stack
--change-set-name my-changeset
Or delete if changes are not acceptable
aws cloudformation delete-change-set
--stack-name my-lambda-stack
--change-set-name my-changeset
Change set types:
-
CREATE : For new stacks
-
UPDATE : For existing stacks
-
IMPORT : For importing existing resources
Related Resources
-
AWS Lambda Documentation
-
AWS CloudFormation User Guide
-
AWS SAM Documentation
-
Lambda Best Practices
Additional Files
For complete details on resources and their properties, see:
-
REFERENCE.md - Detailed reference guide for all CloudFormation resources
-
EXAMPLES.md - Complete production-ready examples