AWS Lambda Governance & Serverless Policies
Implement governance for AWS Lambda functions including security policies, cost controls, performance monitoring, and compliance automation.
π Prerequisites
- Expert knowledge of AWS Lambda, including execution environments and invocation models.
- Advanced proficiency with IAM Policies, especially execution roles and permissions boundaries.
- Strong experience with Terraform for deploying serverless applications and governance controls.
- Skills in Python for writing Lambda functions for automation.
π‘ Serverless Governance: A Paradigm Shift
Governing serverless applications requires a different mindset than traditional infrastructure. The ephemeral, event-driven nature of Lambda means that governance must focus on the "blast radius" of each function. Effective governance is achieved by enforcing fine-grained IAM permissions, setting proactive cost and concurrency limits, and embedding security checks directly into the deployment pipeline.
What You'll Learn
π·οΈ Topics Covered
Security Governance: The Execution Role is Everything
The single most important security control for a Lambda function is its **IAM Execution Role**. This role defines exactly what the function is allowed to do when it runs. The principle of least privilege is paramount.
π JSON: A Least-Privilege Execution Role Policy
This policy grants a Lambda function the minimum permissions required to write logs and interact with a specific S3 bucket and DynamoDB table. Note the use of specific ARNs to limit the resource scope.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowLogging",
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:us-east-1:123456789012:*"
},
{
"Sid": "AllowS3ObjectAccess",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-app-data-bucket/processed/*"
},
{
"Sid": "AllowDynamoDBItemAccess",
"Effect": "Allow",
"Action": [
"dynamodb:UpdateItem",
"dynamodb:GetItem"
],
"Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/AppStateTable"
}
]
} Preventive Controls: Safely Delegating with Permissions Boundaries
To empower developers while maintaining security, you can use **Permissions Boundaries** to set the maximum permissions any Lambda function in a specific application can have. Developers can create roles for their functions, but those roles can never escalate privileges beyond the boundary you've defined.
π‘οΈ JSON: A Lambda Permissions Boundary
This boundary ensures that any Lambda function role created by a developer can *never* access KMS keys, modify IAM resources, or access data outside of the application's designated S3 prefix.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "CorePermissions",
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
},
{
"Sid": "AllowedServiceAccess",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"dynamodb:GetItem"
],
"Resource": [
"arn:aws:s3:::my-app-data-bucket/*",
"arn:aws:dynamodb:us-east-1:123456789012:table/AppStateTable"
]
},
{
"Sid": "DenyPrivilegeEscalation",
"Effect": "Deny",
"Action": [
"iam:*",
"kms:*"
],
"Resource": "*"
}
]
} Automated Cost Governance and Control
A misconfigured Lambda function (e.g., in a recursive loop) can cause a massive, unexpected bill in minutes. Proactive cost controls are essential for serverless.
Automation Pattern: Concurrency Limiter
This expert pattern uses an "enforcer" Lambda function that runs periodically. It scans for functions with a specific tag (e.g., `CostControl=HighRisk`) and automatically applies a low reserved concurrency limit to them, acting as a circuit breaker against runaway costs.
π Python: Lambda Concurrency Limiter
This script finds all functions tagged `CostControl=HighRisk` and sets their reserved concurrency to 5, preventing them from scaling uncontrollably.
import boto3
lambda_client = boto3.client('lambda')
tagging_client = boto3.client('resourcegroupstaggingapi')
# The concurrency limit to apply as a safety measure
CONCURRENCY_LIMIT = 5
def lambda_handler(event, context):
paginator = tagging_client.get_paginator('get_resources')
pages = paginator.paginate(
TagFilters=[
{'Key': 'CostControl', 'Values': ['HighRisk']}
],
ResourceTypeFilters=['lambda']
)
for page in pages:
for resource in page['ResourceTagMappingList']:
function_arn = resource['ResourceARN']
function_name = function_arn.split(':')[-1]
print(f"Found high-risk function: {function_name}")
try:
# Check current concurrency
config = lambda_client.get_function_concurrency(FunctionName=function_name)
# If a limit is already set and it's different, we don't override.
# Or, you could choose to always enforce your limit.
if 'ReservedConcurrentExecutions' in config:
print(f"Function {function_name} already has a concurrency limit. Skipping.")
continue
print(f"Applying concurrency limit of {CONCURRENCY_LIMIT} to {function_name}...")
lambda_client.put_function_concurrency(
FunctionName=function_name,
ReservedConcurrentExecutions=CONCURRENCY_LIMIT
)
print(f"Successfully applied limit to {function_name}.")
except Exception as e:
print(f"Failed to apply limit to {function_name}. Error: {e}")
return {"status": "Complete"}
Detective Controls with AWS Config
AWS Config provides managed rules to continuously check your Lambda functions for security and operational best practices after they are deployed.
ποΈ HCL: Deploying Config Rules for Lambda Governance
This Terraform deploys two critical Config rules: one to check that functions are deployed inside a VPC, and another to check for overly permissive execution roles.
# Rule 1: Ensure Lambda functions are inside a VPC for network isolation
resource "aws_config_config_rule" "lambda_in_vpc" {
name = "lambda-function-in-vpc"
source {
owner = "AWS"
source_identifier = "LAMBDA_FUNCTION_IN_VPC"
}
}
# Rule 2: Check for wild card permissions in Lambda execution roles
resource "aws_config_config_rule" "lambda_iam_least_privilege" {
name = "lambda-iam-least-privilege-check"
source {
owner = "AWS"
source_identifier = "IAM_ROLE_MANAGED_POLICY_CHECK"
}
input_parameters = jsonencode({
"policyArns": "arn:aws:iam::aws:policy/AdministratorAccess,arn:aws:iam::aws:policy/PowerUserAccess"
})
scope {
compliance_resource_types = ["AWS::IAM::Role"]
}
}
Troubleshooting Advanced Lambda Issues
Serverless architectures introduce unique challenges. Hereβs how to debug them.
β±οΈ High "Cold Start" Latency
- Symptom: Your API Gateway reports high `IntegrationLatency` on the first request after a period of inactivity.
- Cause: The Lambda service has to initialize a new execution environment: download code, start the runtime, and run initialization code. This only happens on the first invocation or after a function has been idle.
- Solutions:
- Provisioned Concurrency: For latency-critical functions, configure provisioned concurrency to keep a set number of environments "warm" and ready to execute. This has a cost implication.
- Optimize Dependencies: Reduce the size of your deployment package. Use layers for large dependencies and only import modules inside your handler function where possible.
- Choose Interpreted Languages: Languages like Python and Node.js generally have faster cold start times than compiled languages like Java or .NET.
π VPC Networking Timeouts
- Symptom: A Lambda function in a VPC times out trying to connect to a public API (e.g., Stripe, Twilio) or another AWS service.
- Cause: When a Lambda is placed in a VPC, it loses its default internet access. It can only access resources within that VPC or on-premises via a VPN/Direct Connect.
- Solution: The function's subnets must have a route to a **NAT Gateway**. The NAT Gateway resides in a public subnet and provides a path to the internet for resources in private subnets. This is the standard, secure pattern for giving VPC-based Lambdas internet access.
π Expert-Level Serverless Governance Best Practices
- One Role, One Function: Each Lambda function should have its own dedicated IAM execution role with the minimum necessary permissions. Never share roles.
- Use Permissions Boundaries for Delegation: When allowing developers to create functions, enforce a strict permissions boundary on their IAM user/role to prevent privilege escalation.
- Automate Cost Controls: Don't rely on manual monitoring. Use automated scripts to apply concurrency limits or other restrictions to potentially expensive functions.
- Shift Security Left: Scan your serverless application's IaC templates for overly permissive roles *before* deployment using tools like `cfn-lint` or Checkov.