Terraform AWS Lambda es la solución definitiva para automatizar el despliegue de funciones serverless en Amazon Web Services mediante infraestructura como código. Esta combinación permite gestionar aplicaciones sin servidor de forma reproducible, escalable y eficiente, eliminando configuraciones manuales propensas a errores.
¿Qué es Terraform AWS Lambda?
AWS Lambda es un servicio de computación serverless que ejecuta código en respuesta a eventos sin necesidad de aprovisionar o administrar servidores. Cuando combinamos Lambda con Terraform, obtenemos una metodología de infraestructura como código (IaC) que permite versionar, reutilizar y compartir configuraciones de funciones serverless.
El recurso aws_lambda_function de HashiCorp permite definir funciones Lambda declarativamente. Esto significa especificar el estado deseado de tu infraestructura y dejar que esta herramienta se encargue de alcanzarlo.
A diferencia de las configuraciones manuales en la consola de AWS, este enfoque ofrece trazabilidad completa mediante control de versiones Git, capacidad de replicar entornos idénticos en desarrollo, staging y producción, y automatización completa del ciclo de vida de las funciones serverless.
Ventajas de usar Terraform AWS Lambda
La automatización con infraestructura como código proporciona beneficios significativos frente al despliegue manual:
- Reproducibilidad garantizada: Cada despliegue utiliza exactamente la misma configuración, eliminando inconsistencias entre entornos.
- Versionado completo: Todo cambio queda registrado en Git, permitiendo rollbacks inmediatos y auditorías completas.
- Reutilización mediante módulos: Crea plantillas reutilizables que estandarizan funciones Lambda en toda tu organización.
- Reducción de errores humanos: La automatización elimina errores de configuración manual típicos en consolas web.
- Integración CI/CD nativa: Despliegues automáticos en pipelines de Jenkins, GitHub Actions o GitLab CI.
- Gestión de dependencias: El módulo oficial terraform-aws-modules/lambda maneja empaquetado, capas y dependencias automáticamente.
Según estadísticas recientes del Terraform Registry, el módulo oficial para Lambda acumula más de 78.9 millones de descargas, convirtiéndolo en uno de los módulos más utilizados del ecosistema AWS.
Configuración básica de Terraform AWS Lambda
Para desplegar una función Lambda básica necesitas cuatro componentes fundamentales: el código de la función empaquetado en ZIP, un rol IAM con permisos de ejecución, la función Lambda propiamente dicha, y opcionalmente CloudWatch Logs para monitoreo.
A continuación se muestra un ejemplo completo de configuración:
# Empaquetar código de la función
data "archive_file" "lambda_zip" {
type = "zip"
source_dir = "${path.module}/lambda-function"
output_path = "${path.module}/lambda-function.zip"
}
# Rol IAM para Lambda
resource "aws_iam_role" "lambda_exec" {
name = "lambda-exec-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "lambda.amazonaws.com"
}
}]
})
}
# Adjuntar política de ejecución básica
resource "aws_iam_role_policy_attachment" "lambda_policy" {
role = aws_iam_role.lambda_exec.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
# Función Lambda
resource "aws_lambda_function" "api_handler" {
filename = data.archive_file.lambda_zip.output_path
function_name = "api-handler"
role = aws_iam_role.lambda_exec.arn
handler = "index.handler"
runtime = "nodejs20.x"
timeout = 30
memory_size = 512
source_code_hash = data.archive_file.lambda_zip.output_base64sha256
environment {
variables = {
ENV = "production"
LOG_LEVEL = "info"
}
}
}
# CloudWatch Logs
resource "aws_cloudwatch_log_group" "lambda_logs" {
name = "/aws/lambda/${aws_lambda_function.api_handler.function_name}"
retention_in_days = 30
}
Este código crea una función Lambda completa con empaquetado automático, permisos IAM correctos y logging en CloudWatch. El atributo source_code_hash asegura que la función se actualice automáticamente cuando el código cambie.
Uso del módulo oficial Terraform AWS Lambda
El módulo terraform-aws-modules/lambda/aws simplifica drásticamente la configuración al gestionar automáticamente el empaquetado, dependencias, permisos y recursos relacionados. Este módulo es mantenido oficialmente por la comunidad y sigue las mejores prácticas de AWS.
Ejemplo con el módulo oficial:
module "lambda_function" {
source = "terraform-aws-modules/lambda/aws"
version = "~> 7.0"
function_name = "api-processor"
description = "Procesa peticiones API en tiempo real"
handler = "index.lambda_handler"
runtime = "python3.12"
source_path = "../src/lambda-function"
# Almacenar en S3 para funciones grandes
store_on_s3 = true
s3_bucket = "my-lambda-builds-bucket"
# Variables de entorno
environment_variables = {
DATABASE_URL = var.database_url
API_KEY = var.api_key
}
# Configuración de red para acceso VPC
vpc_subnet_ids = module.vpc.private_subnets
vpc_security_group_ids = [aws_security_group.lambda_sg.id]
attach_network_policy = true
# Permisos adicionales
attach_policy_json = true
policy_json = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:Query"
]
Resource = aws_dynamodb_table.data.arn
}
]
})
# Triggers permitidos
allowed_triggers = {
APIGateway = {
service = "apigateway"
source_arn = "${aws_apigatewayv2_api.main.execution_arn}/*/*"
}
}
tags = {
Environment = "production"
ManagedBy = "Terraform"
}
}
Esta configuración gestiona automáticamente la creación del paquete ZIP, la subida a S3, los permisos IAM, la configuración de red VPC y los triggers de invocación. El módulo reduce cientos de líneas de código a una configuración clara y mantenible.
Integración con API Gateway mediante Terraform
Para exponer funciones Lambda vía HTTP, la integración con API Gateway es esencial. El siguiente ejemplo muestra cómo crear una API HTTP completa con integración Lambda:
# API Gateway HTTP
resource "aws_apigatewayv2_api" "lambda_api" {
name = "lambda-http-api"
protocol_type = "HTTP"
cors_configuration {
allow_origins = ["https://example.com"]
allow_methods = ["GET", "POST", "PUT", "DELETE"]
allow_headers = ["content-type", "authorization"]
max_age = 300
}
}
# Stage de producción
resource "aws_apigatewayv2_stage" "production" {
api_id = aws_apigatewayv2_api.lambda_api.id
name = "production"
auto_deploy = true
access_log_settings {
destination_arn = aws_cloudwatch_log_group.api_logs.arn
format = jsonencode({
requestId = "$context.requestId"
ip = "$context.identity.sourceIp"
requestTime = "$context.requestTime"
httpMethod = "$context.httpMethod"
routeKey = "$context.routeKey"
status = "$context.status"
protocol = "$context.protocol"
responseLength = "$context.responseLength"
})
}
}
# Integración Lambda
resource "aws_apigatewayv2_integration" "lambda_integration" {
api_id = aws_apigatewayv2_api.lambda_api.id
integration_type = "AWS_PROXY"
integration_uri = aws_lambda_function.api_handler.invoke_arn
integration_method = "POST"
payload_format_version = "2.0"
}
# Ruta de API
resource "aws_apigatewayv2_route" "get_handler" {
api_id = aws_apigatewayv2_api.lambda_api.id
route_key = "GET /api/v1/users"
target = "integrations/${aws_apigatewayv2_integration.lambda_integration.id}"
}
# Permiso de invocación
resource "aws_lambda_permission" "api_gateway" {
statement_id = "AllowAPIGatewayInvoke"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.api_handler.function_name
principal = "apigateway.amazonaws.com"
source_arn = "${aws_apigatewayv2_api.lambda_api.execution_arn}/*/*"
}
# CloudWatch para API Gateway
resource "aws_cloudwatch_log_group" "api_logs" {
name = "/aws/apigateway/${aws_apigatewayv2_api.lambda_api.name}"
retention_in_days = 30
}
Esta configuración crea una API HTTP completa con CORS configurado, logging detallado en CloudWatch, y enrutamiento automático a tu función serverless. El uso de payload_format_version = "2.0" proporciona el formato de evento optimizado para HTTP APIs.
Mejores prácticas de seguridad para Terraform AWS Lambda
La seguridad en funciones serverless requiere atención especial a permisos IAM, gestión de secretos y configuración de red:
Principio de mínimo privilegio
Concede únicamente los permisos estrictamente necesarios para cada función:
resource "aws_iam_role_policy" "lambda_dynamodb" {
name = "lambda-dynamodb-access"
role = aws_iam_role.lambda_exec.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"dynamodb:GetItem",
"dynamodb:Query"
]
Resource = "arn:aws:dynamodb:${var.region}:${var.account_id}:table/users"
Condition = {
StringEquals = {
"dynamodb:LeadingKeys" = ["$${aws:username}"]
}
}
}
]
})
}
Gestión segura de secretos
Nunca hardcodees credenciales. Utiliza AWS Secrets Manager o Parameter Store:
# Crear secreto
resource "aws_secretsmanager_secret" "api_key" {
name = "lambda/api-key"
}
resource "aws_secretsmanager_secret_version" "api_key" {
secret_id = aws_secretsmanager_secret.api_key.id
secret_string = var.api_key
}
# Permisos para leer secreto
resource "aws_iam_role_policy" "secrets_access" {
name = "secrets-manager-access"
role = aws_iam_role.lambda_exec.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = [
"secretsmanager:GetSecretValue"
]
Resource = aws_secretsmanager_secret.api_key.arn
}]
})
}
# Pasar ARN del secreto a Lambda
resource "aws_lambda_function" "secure_function" {
# ... otras configuraciones ...
environment {
variables = {
SECRET_ARN = aws_secretsmanager_secret.api_key.arn
}
}
}
Aislamiento de red con VPC
Para funciones que acceden a recursos privados, configura VPC correctamente:
module "lambda_in_vpc" {
source = "terraform-aws-modules/lambda/aws"
function_name = "private-lambda"
handler = "index.handler"
runtime = "python3.12"
source_path = "../src/private-function"
# Configuración VPC
vpc_subnet_ids = data.aws_subnets.private.ids
vpc_security_group_ids = [aws_security_group.lambda_sg.id]
attach_network_policy = true # Añade permisos ENI automáticamente
}
# Security Group para Lambda
resource "aws_security_group" "lambda_sg" {
name = "lambda-sg"
description = "Security group for Lambda functions"
vpc_id = data.aws_vpc.main.id
egress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "HTTPS outbound"
}
egress {
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [aws_security_group.rds_sg.id]
description = "PostgreSQL access"
}
}
Recuerda que las funciones en VPC requieren NAT Gateway o VPC Endpoints para acceder a servicios AWS públicos. Si necesitas más información sobre automatización de infraestructura, revisa nuestra guía de Docker Compose para arquitecturas de microservicios.
Gestión de capas Lambda con Terraform
Las capas Lambda permiten compartir código, dependencias y librerías entre múltiples funciones, reduciendo el tamaño de los paquetes y facilitando el mantenimiento:
# Crear capa con dependencias comunes
module "lambda_layer" {
source = "terraform-aws-modules/lambda/aws"
version = "~> 7.0"
create_layer = true
layer_name = "common-dependencies"
description = "Librerías compartidas para funciones Python"
compatible_runtimes = ["python3.12", "python3.11"]
source_path = [
{
path = "../layers/python"
pip_requirements = "../layers/requirements.txt"
prefix_in_zip = "python"
}
]
store_on_s3 = true
s3_bucket = "lambda-layers-bucket"
}
# Usar capa en función Lambda
module "lambda_with_layer" {
source = "terraform-aws-modules/lambda/aws"
function_name = "function-with-dependencies"
handler = "index.handler"
runtime = "python3.12"
source_path = "../src/function"
layers = [
module.lambda_layer.lambda_layer_arn
]
}
Las capas pueden contener hasta 250 MB de código comprimido y se cargan en /opt en el entorno de ejecución. Esto es especialmente útil para frameworks pesados como TensorFlow, pandas o bibliotecas de procesamiento de imágenes.
Monitoreo y observabilidad con CloudWatch
El monitoreo efectivo es crítico para aplicaciones serverless en producción. CloudWatch proporciona métricas, logs y alarmas integradas:
# Alarma para errores de Lambda
resource "aws_cloudwatch_metric_alarm" "lambda_errors" {
alarm_name = "lambda-errors-${aws_lambda_function.api_handler.function_name}"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 2
metric_name = "Errors"
namespace = "AWS/Lambda"
period = 300
statistic = "Sum"
threshold = 5
alarm_description = "Triggered when Lambda errors exceed threshold"
treat_missing_data = "notBreaching"
dimensions = {
FunctionName = aws_lambda_function.api_handler.function_name
}
alarm_actions = [aws_sns_topic.alerts.arn]
}
# Alarma para duración excesiva
resource "aws_cloudwatch_metric_alarm" "lambda_duration" {
alarm_name = "lambda-duration-${aws_lambda_function.api_handler.function_name}"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 3
metric_name = "Duration"
namespace = "AWS/Lambda"
period = 60
statistic = "Average"
threshold = 5000 # 5 segundos
alarm_description = "Triggered when average duration exceeds 5 seconds"
dimensions = {
FunctionName = aws_lambda_function.api_handler.function_name
}
alarm_actions = [aws_sns_topic.alerts.arn]
}
# Alarma para invocaciones concurrentes
resource "aws_cloudwatch_metric_alarm" "lambda_throttles" {
alarm_name = "lambda-throttles-${aws_lambda_function.api_handler.function_name}"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "Throttles"
namespace = "AWS/Lambda"
period = 60
statistic = "Sum"
threshold = 10
alarm_description = "Triggered when function is throttled"
dimensions = {
FunctionName = aws_lambda_function.api_handler.function_name
}
alarm_actions = [aws_sns_topic.alerts.arn]
}
# SNS Topic para notificaciones
resource "aws_sns_topic" "alerts" {
name = "lambda-alerts"
}
resource "aws_sns_topic_subscription" "email" {
topic_arn = aws_sns_topic.alerts.arn
protocol = "email"
endpoint = "[email protected]"
}
Para monitoreo avanzado de infraestructura, considera herramientas como Uptime Kuma que complementan las métricas nativas de CloudWatch con dashboards personalizados.
Estrategias de despliegue y versionado
Lambda soporta versionado y alias para despliegues blue-green y canary:
# Publicar versión inmutable
resource "aws_lambda_function" "api_handler" {
# ... configuración base ...
publish = true # Crea nueva versión en cada deploy
}
# Alias de producción apuntando a versión estable
resource "aws_lambda_alias" "production" {
name = "production"
description = "Alias de producción estable"
function_name = aws_lambda_function.api_handler.function_name
function_version = aws_lambda_function.api_handler.version
}
# Despliegue canary con tráfico dividido
resource "aws_lambda_alias" "canary" {
name = "canary"
description = "Despliegue canary con 10% de tráfico"
function_name = aws_lambda_function.api_handler.function_name
function_version = aws_lambda_function.api_handler.version
routing_config {
additional_version_weights = {
(aws_lambda_function.api_handler.version - 1) = 0.9 # 90% a versión anterior
}
}
}
# API Gateway usa alias para enrutamiento
resource "aws_lambda_permission" "api_gateway_production" {
statement_id = "AllowAPIGatewayInvokeProduction"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.api_handler.function_name
principal = "apigateway.amazonaws.com"
qualifier = aws_lambda_alias.production.name
source_arn = "${aws_apigatewayv2_api.lambda_api.execution_arn}/*/*"
}
Este enfoque permite rollbacks instantáneos simplemente actualizando el alias sin necesidad de redesplegar código.
Automatización CI/CD para despliegues Lambda
Integrar este flujo en pipelines CI/CD garantiza despliegues consistentes y auditables. Ejemplo con GitHub Actions:
name: Deploy Lambda with Terraform
on:
push:
branches: [main]
paths:
- 'terraform/**'
- 'src/**'
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.7.0
- name: Terraform Init
working-directory: terraform
run: terraform init
- name: Terraform Validate
working-directory: terraform
run: terraform validate
- name: Terraform Plan
working-directory: terraform
run: terraform plan -out=tfplan
- name: Terraform Apply
working-directory: terraform
run: terraform apply -auto-approve tfplan
- name: Run Integration Tests
run: |
pip install pytest requests
pytest tests/integration/
Este pipeline ejecuta validación, planificación, despliegue y pruebas automáticas en cada push a la rama principal, asegurando calidad y consistencia en cada cambio de infraestructura.
Preguntas frecuentes (FAQ)
¿Cómo gestiono dependencias de Python en funciones Lambda con Terraform?
El módulo oficial terraform-aws-modules/lambda/aws gestiona automáticamente dependencias mediante el parámetro source_path con pip_requirements. Especifica un archivo requirements.txt y el módulo instalará las dependencias localmente o en Docker antes de empaquetar. Para dependencias compartidas entre múltiples funciones, utiliza capas Lambda.
¿Cuál es la diferencia entre aws_lambda_function y el módulo terraform-aws-modules/lambda/aws?
El recurso aws_lambda_function es el recurso nativo que requiere gestión manual de empaquetado, permisos y recursos relacionados. El módulo terraform-aws-modules/lambda/aws es una abstracción de alto nivel que automatiza empaquetado, dependencias, capas, permisos IAM y triggers. El módulo reduce drásticamente la complejidad y sigue mejores prácticas de AWS automáticamente.
¿Cómo implemento blue-green deployments en Lambda mediante Terraform?
Utiliza versionado de Lambda con alias y tráfico dividido. Configura publish = true para crear versiones inmutables, crea alias apuntando a versiones específicas, y usa routing_config para dividir tráfico entre versiones. API Gateway debe invocar el alias en lugar de la función directamente. Esto permite despliegues canary con porcentajes de tráfico configurables y rollbacks instantáneos.
¿Necesito VPC para mis funciones Lambda gestionadas con esta herramienta?
Solo si tus funciones necesitan acceder a recursos privados como bases de datos RDS, clusters ElastiCache o servicios internos. Las funciones sin VPC tienen acceso directo a Internet y servicios AWS públicos con menor latencia de arranque en frío. Funciones en VPC requieren ENIs que añaden latencia inicial y necesitan NAT Gateway o VPC Endpoints para servicios AWS públicos.
¿Cómo gestiono secretos de forma segura en funciones Lambda con Terraform?
Utiliza AWS Secrets Manager o Systems Manager Parameter Store para almacenar secretos, nunca variables de entorno o código. Concede permisos IAM para secretsmanager:GetSecretValue específicamente al ARN del secreto. Pasa el ARN del secreto como variable de entorno y recupera el valor en runtime desde el código de la función. Rota secretos periódicamente usando rotación automática de Secrets Manager.
Conclusión
Terraform AWS Lambda combina la potencia del serverless computing con las ventajas de infraestructura como código, permitiendo despliegues reproducibles, escalables y auditables. Al automatizar el ciclo de vida completo de funciones Lambda mediante declaraciones de código, eliminas errores manuales, mejoras la consistencia entre entornos y habilitas flujos CI/CD robustos.
El módulo oficial terraform-aws-modules/lambda/aws simplifica drásticamente la gestión de funciones serverless al manejar automáticamente empaquetado, dependencias, permisos y recursos relacionados. Con más de 78.9 millones de descargas, este módulo representa el estándar de facto para gestionar Lambda mediante infraestructura como código en AWS.
Implementa las mejores prácticas descritas: principio de mínimo privilegio en IAM, gestión segura de secretos con Secrets Manager, monitoreo proactivo con CloudWatch Alarms, y estrategias de despliegue blue-green con alias y versionado. Estas prácticas garantizan aplicaciones serverless seguras, observables y resilientes en producción.
Comienza hoy mismo automatizando tus despliegues Lambda y experimenta los beneficios de la infraestructura declarativa. Para complementar tu arquitectura serverless, explora herramientas de seguridad como Vaultwarden para gestión de credenciales en tu equipo de desarrollo.
