Guide: Managing Lambda and Serverless
Relevant source files
The following files were used as context for generating this wiki page:
The Terraform AWS provider enables full lifecycle management of AWS resources, which is fundamental for building serverless applications. This guide focuses on using the provider to define, configure, and connect AWS Lambda functions with other services like API Gateway and Cognito to create event-driven, serverless architectures. By defining these components as code, you can achieve repeatable and version-controlled infrastructure deployments.
This document will explore the core resources involved, such as aws_lambda_function, aws_apigatewayv2_api, and aws_cognito_user_pool, demonstrating how they are interconnected. We will use a WebSocket chat application and a Cognito user pool with Lambda triggers as practical examples to illustrate these concepts.
Sources: README.md, internal/service/lambda/README.md, examples/api-gateway-websocket-chat-app/main.tf
Core Components
The aws_lambda_function Resource
The aws_lambda_function resource is the central component for defining a Lambda function. It specifies the function's code, runtime environment, execution role, and other configurations.
A typical Lambda function definition includes:
- Code Location: The path to the deployment package (e.g., a
.zipfile). Thearchive_filedata source is often used to create this package on the fly. - Execution Role: An IAM role that grants the function permission to access other AWS services.
- Handler: The method within your code that Lambda calls to begin execution.
- Runtime: The language environment for the function (e.g.,
nodejs12.x). - Environment Variables: Key-value pairs passed to the function's code.
The following table details key arguments for the aws_lambda_function resource.
| Argument | Type | Description | Example Value |
|---|---|---|---|
function_name | String | A unique name for your Lambda function. | OnConnectFunction |
filename | String | The path to the function's deployment package. | data.archive_file.OnConnectZip.output_path |
role | String | The ARN of the function's execution role. | aws_iam_role.OnConnectRole.arn |
handler | String | The function entrypoint in your code. | app.handler |
runtime | String | The identifier of the function's runtime. | nodejs12.x |
memory_size | Number | Amount of memory in MB allocated to the function. | 256 |
environment | Block | A block for defining environment variables. | variables = { TABLE_NAME = "..." } |
Sources: examples/api-gateway-websocket-chat-app/main.tf:190-201, examples/cognito-user-pool/main.tf:28-34
IAM Roles and Permissions
Lambda functions require explicit permissions to interact with other AWS services. This is managed through IAM roles and policies.
aws_iam_role: Defines an execution role for the Lambda function. Theassume_role_policyallows thelambda.amazonaws.comservice to assume this role.aws_iam_policy: Defines a set of permissions. For example, a policy can grant a function CRUD access to a DynamoDB table or permission to write logs to CloudWatch.aws_iam_role_policy_attachment: Attaches a policy to the role.
The diagram below illustrates the relationship between a Lambda function and its required IAM resources.
This diagram shows that an aws_lambda_function is assigned an aws_iam_role, which in turn has multiple aws_iam_policy documents attached to it, granting specific permissions.
Sources: examples/api-gateway-websocket-chat-app/main.tf:51-73, examples/api-gateway-websocket-chat-app/main.tf:209-222, examples/api-gateway-websocket-chat-app/main.tf:224-227
Lambda Invocation Patterns
Lambda functions are event-driven and can be triggered by various AWS services.
API Gateway WebSocket Integration
A common serverless pattern is to use API Gateway to expose Lambda functions via an HTTP or WebSocket API. For a WebSocket API, special routes ($connect, $disconnect, $default) and custom routes can be mapped to different Lambda functions to handle the connection lifecycle and messaging.
The key resources for this integration are:
aws_apigatewayv2_api: Defines the WebSocket API itself.aws_apigatewayv2_route: Maps a route key (e.g.,$connectorsendmessage) to an integration.aws_apigatewayv2_integration: Connects a route to a Lambda function backend. Theintegration_uriis set to the Lambda function'sinvoke_arn.aws_lambda_permission: Grants the API Gateway service (apigateway.amazonaws.com) permission to invoke the Lambda function.
Sources: examples/api-gateway-websocket-chat-app/main.tf:78-82, examples/api-gateway-websocket-chat-app/main.tf:112-117, examples/api-gateway-websocket-chat-app/main.tf:103-109, examples/api-gateway-websocket-chat-app/main.tf:203-207
Cognito User Pool Triggers
AWS Cognito can trigger Lambda functions at various stages of the user lifecycle, such as before sign-up or after authentication. This allows for custom logic, such as data validation, custom messages, or migrating users from a legacy system.
These triggers are configured within the lambda_config block of the aws_cognito_user_pool resource. Each trigger is mapped to the ARN of a specific Lambda function.
The following table lists some of the available Cognito Lambda triggers.
| Trigger | Description |
|---|---|
pre_sign_up | Triggered before a new user is signed up. Can be used for custom validation. |
post_confirmation | Triggered after a new user is confirmed. |
pre_authentication | Triggered before a user is authenticated. |
post_authentication | Triggered after a user is authenticated. |
custom_message | Customizes verification and invitation messages. |
user_migration | Migrates a user from a legacy directory into the user pool. |
pre_token_generation | Customizes claims in the ID token before it is generated. |
Sources: examples/cognito-user-pool/main.tf:95-107
Here is an example snippet from a Terraform configuration file:
resource "aws_cognito_user_pool" "pool" {
# ... other configurations
lambda_config {
create_auth_challenge = aws_lambda_function.main.arn
custom_message = aws_lambda_function.main.arn
define_auth_challenge = aws_lambda_function.main.arn
post_authentication = aws_lambda_function.main.arn
post_confirmation = aws_lambda_function.main.arn
pre_authentication = aws_lambda_function.main.arn
pre_sign_up = aws_lambda_function.main.arn
pre_token_generation = aws_lambda_function.main.arn
user_migration = aws_lambda_function.main.arn
verify_auth_challenge_response = aws_lambda_function.main.arn
}
# ...
}
Sources: examples/cognito-user-pool/main.tf:95-107
Example Architecture: WebSocket Chat App
The api-gateway-websocket-chat-app example provides a complete serverless application demonstrating the integration of API Gateway, Lambda, and DynamoDB.
The architecture consists of:
- An API Gateway v2 WebSocket API that serves as the entry point for clients.
- Three Lambda Functions:
OnConnectFunction: Handles new client connections, storing theconnectionIdin DynamoDB.OnDisconnectFunction: Handles client disconnections, removing theconnectionIdfrom DynamoDB.SendMessageFunction: Receives messages from clients and broadcasts them to all other connected clients.
- A DynamoDB Table (
simplechat_connections) to persist active connection IDs. - IAM Roles and Policies to grant the necessary permissions for each function.
The following diagram illustrates the overall architecture and data flow.
The sequence diagram below shows the flow for a client sending a message.
Summary
The Terraform AWS provider offers a powerful and declarative way to manage serverless infrastructure. By defining Lambda functions, API Gateway endpoints, IAM permissions, and other resources as code, developers can build, deploy, and maintain complex serverless applications with confidence and repeatability. The examples of a WebSocket chat application and Cognito triggers highlight the flexibility of Lambda as a compute service that can be integrated across the AWS ecosystem.
Sources: README.md, internal/service/lambda/README.md