Files
DevOps-Security-Agent-Skills/infrastructure/cloud-aws/aws-lambda/SKILL.md
T

413 lines
12 KiB
Markdown
Raw Normal View History

2026-01-27 17:35:45 -05:00
---
name: aws-lambda
description: Build and deploy serverless functions on AWS Lambda. Configure triggers, manage permissions, and optimize performance. Use when implementing serverless applications.
license: MIT
metadata:
author: devops-skills
version: "1.0"
---
# AWS Lambda
2026-03-24 18:02:50 -04:00
Build serverless applications with AWS Lambda, covering function creation, event sources, layers, SAM templates, and cold start optimization.
2026-01-27 17:35:45 -05:00
2026-03-24 18:02:50 -04:00
## When to Use This Skill
- Building event-driven applications triggered by API Gateway, S3, SQS, or EventBridge
- Running scheduled tasks (cron) without managing servers
- Processing data streams from Kinesis or DynamoDB
- Building lightweight APIs with API Gateway or function URLs
- Implementing webhooks, Slack bots, or automation scripts
- Reducing compute costs for intermittent or bursty workloads
## Prerequisites
- AWS CLI v2 installed and configured
- IAM permissions: `lambda:*`, `iam:PassRole`, `logs:*`, `apigateway:*`, `s3:*`
- Python 3.11+, Node.js 20+, or another supported runtime installed locally
- (Optional) AWS SAM CLI for local development and deployment
## Create and Deploy a Function
2026-01-27 17:35:45 -05:00
```bash
2026-03-24 18:02:50 -04:00
# Create a deployment package
cd my-function
zip -r function.zip app.py
# Create the Lambda function
2026-01-27 17:35:45 -05:00
aws lambda create-function \
2026-03-24 18:02:50 -04:00
--function-name my-api-handler \
--runtime python3.12 \
2026-01-27 17:35:45 -05:00
--handler app.handler \
2026-03-24 18:02:50 -04:00
--role arn:aws:iam::123456789012:role/LambdaExecRole \
--zip-file fileb://function.zip \
--memory-size 256 \
--timeout 30 \
--environment 'Variables={STAGE=production,LOG_LEVEL=INFO}' \
--architectures arm64 \
--tracing-config Mode=Active \
--tags '{"Team":"backend","Environment":"production"}'
# Update function code
aws lambda update-function-code \
--function-name my-api-handler \
2026-01-27 17:35:45 -05:00
--zip-file fileb://function.zip
2026-03-24 18:02:50 -04:00
# Update function configuration
aws lambda update-function-configuration \
--function-name my-api-handler \
--memory-size 512 \
--timeout 60 \
--environment 'Variables={STAGE=production,LOG_LEVEL=WARNING}'
# Publish a version (immutable snapshot)
aws lambda publish-version \
--function-name my-api-handler \
--description "v1.2.0 - added rate limiting"
# Create an alias pointing to the version
aws lambda create-alias \
--function-name my-api-handler \
--name live \
--function-version 3
# Weighted alias for canary deployments (90% v3, 10% v4)
aws lambda update-alias \
--function-name my-api-handler \
--name live \
--function-version 4 \
--routing-config '{"AdditionalVersionWeights":{"3":0.9}}'
2026-01-27 17:35:45 -05:00
```
2026-03-24 18:02:50 -04:00
## Function Code Examples
2026-01-27 17:35:45 -05:00
```python
2026-03-24 18:02:50 -04:00
# app.py - API Gateway handler with structured logging
2026-01-27 17:35:45 -05:00
import json
2026-03-24 18:02:50 -04:00
import logging
import os
logger = logging.getLogger()
logger.setLevel(os.environ.get("LOG_LEVEL", "INFO"))
2026-01-27 17:35:45 -05:00
def handler(event, context):
2026-03-24 18:02:50 -04:00
"""Handle API Gateway proxy event."""
logger.info("Request: %s %s", event["httpMethod"], event["path"])
try:
body = json.loads(event.get("body", "{}"))
result = process_request(body)
return {
"statusCode": 200,
"headers": {
"Content-Type": "application/json",
"X-Request-Id": context.aws_request_id
},
"body": json.dumps(result)
}
except ValueError as e:
logger.warning("Validation error: %s", e)
return {"statusCode": 400, "body": json.dumps({"error": str(e)})}
except Exception as e:
logger.exception("Unhandled error")
return {"statusCode": 500, "body": json.dumps({"error": "Internal server error"})}
def process_request(body):
return {"message": "OK", "data": body}
```
```python
# sqs_processor.py - SQS batch processor with partial failure reporting
import json
import logging
logger = logging.getLogger()
logger.setLevel("INFO")
def handler(event, context):
"""Process SQS messages with partial batch failure reporting."""
failed_ids = []
for record in event["Records"]:
try:
body = json.loads(record["body"])
logger.info("Processing message: %s", record["messageId"])
process_message(body)
except Exception as e:
logger.error("Failed message %s: %s", record["messageId"], e)
failed_ids.append(record["messageId"])
# Return failed items so only those get retried
2026-01-27 17:35:45 -05:00
return {
2026-03-24 18:02:50 -04:00
"batchItemFailures": [
{"itemIdentifier": msg_id} for msg_id in failed_ids
]
2026-01-27 17:35:45 -05:00
}
2026-03-24 18:02:50 -04:00
def process_message(body):
pass # your logic here
2026-01-27 17:35:45 -05:00
```
2026-03-24 18:02:50 -04:00
## Lambda Layers
2026-01-27 17:35:45 -05:00
```bash
2026-03-24 18:02:50 -04:00
# Build a layer for Python dependencies
mkdir -p layer/python
pip install requests boto3-stubs -t layer/python/
cd layer
zip -r ../my-layer.zip python/
2026-01-27 17:35:45 -05:00
2026-03-24 18:02:50 -04:00
# Publish the layer
aws lambda publish-layer-version \
--layer-name common-deps \
--description "Shared Python dependencies" \
--zip-file fileb://my-layer.zip \
--compatible-runtimes python3.11 python3.12 \
--compatible-architectures arm64 x86_64
# Attach layer to a function
aws lambda update-function-configuration \
--function-name my-api-handler \
--layers "arn:aws:lambda:us-east-1:123456789012:layer:common-deps:1"
# List available layers
aws lambda list-layers --compatible-runtime python3.12
```
## Event Source Mappings
```bash
# SQS trigger with batch processing
aws lambda create-event-source-mapping \
--function-name sqs-processor \
--event-source-arn arn:aws:sqs:us-east-1:123456789012:my-queue \
--batch-size 10 \
--maximum-batching-window-in-seconds 5 \
--function-response-types ReportBatchItemFailures
# DynamoDB Streams trigger
aws lambda create-event-source-mapping \
--function-name stream-processor \
--event-source-arn arn:aws:dynamodb:us-east-1:123456789012:table/my-table/stream/2026-01-01T00:00:00.000 \
--batch-size 100 \
--starting-position LATEST \
--maximum-retry-attempts 3 \
--bisect-batch-on-function-error \
--destination-config '{"OnFailure":{"Destination":"arn:aws:sqs:us-east-1:123456789012:dlq"}}'
# S3 event notification (via Lambda permission + S3 config)
2026-01-27 17:35:45 -05:00
aws lambda add-permission \
2026-03-24 18:02:50 -04:00
--function-name image-processor \
--statement-id s3-trigger \
2026-01-27 17:35:45 -05:00
--action lambda:InvokeFunction \
2026-03-24 18:02:50 -04:00
--principal s3.amazonaws.com \
--source-arn arn:aws:s3:::my-uploads-bucket \
--source-account 123456789012
aws s3api put-bucket-notification-configuration \
--bucket my-uploads-bucket \
--notification-configuration '{
"LambdaFunctionConfigurations": [{
"LambdaFunctionArn": "arn:aws:lambda:us-east-1:123456789012:function:image-processor",
"Events": ["s3:ObjectCreated:*"],
"Filter": {"Key": {"FilterRules": [{"Name": "suffix", "Value": ".jpg"}]}}
}]
}'
# Schedule with EventBridge (cron)
aws events put-rule \
--name daily-cleanup \
--schedule-expression "cron(0 2 * * ? *)" \
--state ENABLED
aws lambda add-permission \
--function-name daily-cleanup \
--statement-id eventbridge \
--action lambda:InvokeFunction \
--principal events.amazonaws.com \
--source-arn arn:aws:events:us-east-1:123456789012:rule/daily-cleanup
aws events put-targets \
--rule daily-cleanup \
--targets '[{"Id":"1","Arn":"arn:aws:lambda:us-east-1:123456789012:function:daily-cleanup"}]'
2026-01-27 17:35:45 -05:00
```
2026-03-24 18:02:50 -04:00
## Function URLs (No API Gateway Needed)
2026-01-27 17:35:45 -05:00
```bash
2026-03-24 18:02:50 -04:00
# Create a function URL (public HTTPS endpoint)
aws lambda create-function-url-config \
--function-name my-api-handler \
--auth-type NONE \
--cors '{
"AllowOrigins": ["https://myapp.com"],
"AllowMethods": ["GET", "POST"],
"AllowHeaders": ["Content-Type"],
"MaxAge": 86400
}'
2026-01-27 17:35:45 -05:00
2026-03-24 18:02:50 -04:00
# Grant public invoke for function URL
aws lambda add-permission \
--function-name my-api-handler \
--statement-id function-url-public \
--action lambda:InvokeFunctionUrl \
--principal "*" \
--function-url-auth-type NONE
2026-01-27 17:35:45 -05:00
```
2026-03-24 18:02:50 -04:00
## Cold Start Optimization
2026-01-27 17:35:45 -05:00
2026-03-24 18:02:50 -04:00
```bash
# Enable provisioned concurrency to eliminate cold starts
aws lambda put-provisioned-concurrency-config \
--function-name my-api-handler \
--qualifier live \
--provisioned-concurrent-executions 10
# Set reserved concurrency (throttle limit)
aws lambda put-function-concurrency \
--function-name my-api-handler \
--reserved-concurrent-executions 100
# Enable SnapStart for Java functions (near-zero cold starts)
aws lambda update-function-configuration \
--function-name my-java-handler \
--snap-start '{"ApplyOn": "PublishedVersions"}'
aws lambda publish-version --function-name my-java-handler
```
Cold start reduction tips:
- Use `arm64` architecture (Graviton) for faster init and lower cost
- Minimize deployment package size; use layers for large dependencies
- Initialize SDK clients outside the handler function
- Avoid VPC unless required (VPC cold starts are longer)
- Use provisioned concurrency for latency-sensitive paths
## SAM Template
```yaml
# template.yaml - AWS SAM application
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: My serverless API
Globals:
Function:
Runtime: python3.12
Architectures: [arm64]
MemorySize: 256
Timeout: 30
Tracing: Active
Environment:
Variables:
STAGE: !Ref Stage
LOG_LEVEL: INFO
Parameters:
Stage:
Type: String
Default: dev
AllowedValues: [dev, staging, prod]
Resources:
ApiFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub "${Stage}-api-handler"
Handler: app.handler
CodeUri: src/
Layers:
- !Ref DepsLayer
Events:
GetItems:
Type: Api
Properties:
Path: /items
Method: get
PostItem:
Type: Api
Properties:
Path: /items
Method: post
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref ItemsTable
QueueProcessor:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub "${Stage}-queue-processor"
Handler: sqs_processor.handler
CodeUri: src/
Events:
SQSEvent:
Type: SQS
Properties:
Queue: !GetAtt ProcessingQueue.Arn
BatchSize: 10
FunctionResponseTypes:
- ReportBatchItemFailures
DepsLayer:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: common-deps
ContentUri: layer/
CompatibleRuntimes:
- python3.12
ItemsTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: !Sub "${Stage}-items"
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
ProcessingQueue:
Type: AWS::SQS::Queue
Properties:
QueueName: !Sub "${Stage}-processing"
VisibilityTimeout: 360
Outputs:
ApiEndpoint:
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod"
```
```bash
# SAM CLI commands
sam build
sam local invoke ApiFunction --event events/get-items.json
sam local start-api --port 3000
sam deploy --guided
sam logs --name ApiFunction --stack-name my-stack --tail
```
## Troubleshooting
| Problem | Cause | Fix |
|---|---|---|
| Function times out | Timeout too low or downstream slow | Increase timeout; check VPC/NAT config |
| Out of memory | Memory limit too small | Increase `--memory-size`; profile with CloudWatch Insights |
| Permission denied on AWS API | Execution role missing policy | Attach required policy to the execution role |
| Cold starts > 5s | Large package or VPC overhead | Use layers, arm64, provisioned concurrency; remove VPC if not needed |
| SQS messages reprocessed | Visibility timeout < function timeout | Set queue visibility timeout to 6x function timeout |
| Event source mapping disabled | Too many consecutive errors | Fix the function error; re-enable the mapping |
| Layer not found | Wrong region or deleted version | Verify layer ARN region matches function region |
| Canary deployment not shifting | Alias routing config wrong | Verify version numbers in routing config |
| Cannot invoke function URL | Missing resource-based policy | Add `lambda:InvokeFunctionUrl` permission |
2026-01-27 17:35:45 -05:00
## Related Skills
2026-03-24 18:02:50 -04:00
- [aws-iam](../aws-iam/) - Execution roles and permissions
- [terraform-aws](../terraform-aws/) - IaC deployment for Lambda
- [aws-s3](../aws-s3/) - S3 event triggers
- [aws-vpc](../aws-vpc/) - VPC configuration for Lambda
- [aws-cost-optimization](../aws-cost-optimization/) - Optimizing Lambda spend