Deploying AWS Lambda Functions with Terraform
A comprehensive guide to deploying serverless functions on AWS Lambda using Terraform Infrastructure as Code
Deploying AWS Lambda Functions with Terraform
AWS Lambda lets you run code without provisioning servers. This guide shows how to deploy Lambda functions using Terraform for infrastructure as code.
Video Tutorial
Learn more about deploying AWS Lambda with Terraform in this comprehensive video tutorial:
Related Guides:
- For integrating Lambda with API Gateway, see AWS Lambda with API Gateway
- For API Gateway specific setup, see AWS API Gateway
Prerequisites
- AWS CLI configured
- Terraform installed
- Basic understanding of serverless architecture
Project Structure
aws-lambda-terraform/
├── main.tf
├── variables.tf
├── outputs.tf
└── terraform.tfvars
Basic Lambda Configuration
provider "aws" {
region = var.aws_region
}
# IAM role for Lambda
resource "aws_iam_role" "lambda" {
name = "${var.project_name}-lambda-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "lambda.amazonaws.com"
}
}
]
})
}
# CloudWatch Logs policy
resource "aws_iam_role_policy_attachment" "lambda_logs" {
role = aws_iam_role.lambda.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
# Lambda function
resource "aws_lambda_function" "main" {
filename = "lambda_function.zip"
function_name = "${var.project_name}-function"
role = aws_iam_role.lambda.arn
handler = "index.handler"
runtime = "nodejs14.x"
environment {
variables = {
ENVIRONMENT = var.environment
}
}
tags = {
Environment = var.environment
}
}
# CloudWatch Log Group
resource "aws_cloudwatch_log_group" "lambda" {
name = "/aws/lambda/${aws_lambda_function.main.function_name}"
retention_in_days = 14
}
Function Code (index.js)
exports.handler = async (event) => {
console.log('Event:', JSON.stringify(event));
return {
statusCode: 200,
body: JSON.stringify({
message: 'Hello from Lambda!'
})
};
};
Advanced Features
1. VPC Configuration
resource "aws_lambda_function" "vpc" {
filename = "lambda_function.zip"
function_name = "${var.project_name}-vpc-function"
role = aws_iam_role.lambda.arn
handler = "index.handler"
runtime = "nodejs14.x"
vpc_config {
subnet_ids = var.subnet_ids
security_group_ids = [aws_security_group.lambda.id]
}
}
resource "aws_security_group" "lambda" {
name = "${var.project_name}-lambda-sg"
description = "Security group for Lambda function"
vpc_id = var.vpc_id
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
2. Lambda Layers
resource "aws_lambda_layer_version" "dependencies" {
filename = "layer.zip"
layer_name = "${var.project_name}-dependencies"
compatible_runtimes = ["nodejs14.x"]
}
resource "aws_lambda_function" "with_layer" {
filename = "lambda_function.zip"
function_name = "${var.project_name}-layered-function"
role = aws_iam_role.lambda.arn
handler = "index.handler"
runtime = "nodejs14.x"
layers = [aws_lambda_layer_version.dependencies.arn]
}
3. Function URL
resource "aws_lambda_function_url" "url" {
function_name = aws_lambda_function.main.function_name
authorization_type = "NONE"
cors {
allow_credentials = true
allow_origins = ["*"]
allow_methods = ["*"]
allow_headers = ["date", "keep-alive"]
expose_headers = ["keep-alive", "date"]
max_age = 86400
}
}
Monitoring Configuration
# CloudWatch Alarm for Errors
resource "aws_cloudwatch_metric_alarm" "lambda_errors" {
alarm_name = "${var.project_name}-errors"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = "1"
metric_name = "Errors"
namespace = "AWS/Lambda"
period = "300"
statistic = "Sum"
threshold = "0"
alarm_description = "This metric monitors lambda function errors"
alarm_actions = [var.sns_topic_arn]
dimensions = {
FunctionName = aws_lambda_function.main.function_name
}
}
# CloudWatch Dashboard
resource "aws_cloudwatch_dashboard" "lambda" {
dashboard_name = "${var.project_name}-lambda"
dashboard_body = jsonencode({
widgets = [
{
type = "metric"
x = 0
y = 0
width = 12
height = 6
properties = {
metrics = [
["AWS/Lambda", "Invocations", "FunctionName", aws_lambda_function.main.function_name],
["AWS/Lambda", "Errors", "FunctionName", aws_lambda_function.main.function_name],
["AWS/Lambda", "Duration", "FunctionName", aws_lambda_function.main.function_name]
]
period = 300
stat = "Sum"
region = var.aws_region
title = "Lambda Metrics"
}
}
]
})
}
Best Practices
-
Function Size
- Keep functions small and focused
- Use layers for dependencies
- Optimize package size
-
Error Handling
- Implement proper error handling
- Set up monitoring and alerts
- Use structured logging
-
Security
- Use IAM roles with least privilege
- Encrypt environment variables
- Regular security audits
-
Performance
- Optimize memory allocation
- Reuse connections
- Implement proper timeouts
Common Use Cases
- Event Processing
resource "aws_lambda_function" "event_processor" {
filename = "event_processor.zip"
function_name = "${var.project_name}-event-processor"
role = aws_iam_role.lambda.arn
handler = "index.handler"
runtime = "nodejs14.x"
timeout = 30
memory_size = 256
}
- Scheduled Tasks
resource "aws_cloudwatch_event_rule" "schedule" {
name = "${var.project_name}-schedule"
description = "Schedule for Lambda Function"
schedule_expression = "rate(1 hour)"
}
resource "aws_cloudwatch_event_target" "schedule_lambda" {
rule = aws_cloudwatch_event_rule.schedule.name
target_id = "ProcessScheduledEvent"
arn = aws_lambda_function.main.arn
}
resource "aws_lambda_permission" "allow_eventbridge" {
statement_id = "AllowEventBridgeInvoke"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.main.function_name
principal = "events.amazonaws.com"
source_arn = aws_cloudwatch_event_rule.schedule.arn
}
Variables
variable "aws_region" {
description = "AWS region"
type = string
default = "us-west-2"
}
variable "project_name" {
description = "Project name"
type = string
}
variable "environment" {
description = "Environment name"
type = string
default = "dev"
}
variable "vpc_id" {
description = "VPC ID for Lambda function"
type = string
}
variable "subnet_ids" {
description = "Subnet IDs for Lambda function"
type = list(string)
}
variable "sns_topic_arn" {
description = "SNS Topic ARN for alarms"
type = string
}
Outputs
output "function_name" {
description = "Lambda function name"
value = aws_lambda_function.main.function_name
}
output "function_arn" {
description = "Lambda function ARN"
value = aws_lambda_function.main.arn
}
output "function_url" {
description = "Lambda function URL"
value = aws_lambda_function_url.url.url
}
Conclusion
This setup provides a comprehensive foundation for deploying AWS Lambda functions using Terraform. Remember to:
- Follow security best practices
- Implement proper monitoring
- Optimize function performance
- Use proper error handling
For integrating this Lambda function with API Gateway, see our guide on AWS Lambda with API Gateway.