resource "aws_iam_role" "lambda_exec" {
name = "${var.project_name}-lambda-exec-${var.environment}"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "lambda.amazonaws.com"
}
}
]
})
}
resource "aws_iam_role_policy_attachment" "lambda_basic" {
role = aws_iam_role.lambda_exec.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
resource "aws_iam_role_policy_attachment" "lambda_xray" {
role = aws_iam_role.lambda_exec.name
policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
}
resource "aws_cloudwatch_log_group" "lambda_logs" {
name = "/aws/lambda/${var.project_name}-api-${var.environment}"
retention_in_days = 14 # 14-day retention keeps log storage 100% within free tier (5 GB/mo)
}
resource "aws_lambda_function" "backend" {
function_name = "${var.project_name}-api-${var.environment}"
role = aws_iam_role.lambda_exec.arn
package_type = "Image"
image_uri = "${aws_ecr_repository.backend.repository_url}:latest"
memory_size = 512
timeout = 60
tracing_config {
mode = "Active"
}
environment {
variables = {
DATABASE_URL = var.database_url
SECRET_KEY = var.secret_key
APP_ENV = var.environment
PORT = "8000"
PYTHONUNBUFFERED = "1"
AWS_LWA_INVOKE_MODE = "buffered"
OTEL_EXPORTER_OTLP_ENDPOINT = var.otel_exporter_otlp_endpoint
OTEL_EXPORTER_OTLP_HEADERS = var.otel_exporter_otlp_headers
}
}
lifecycle {
ignore_changes = [image_uri]
}
depends_on = [
aws_cloudwatch_log_group.lambda_logs,
aws_ecr_repository_policy.backend_lambda
]
}
resource "aws_lambda_function_url" "backend_url" {
function_name = aws_lambda_function.backend.function_name
authorization_type = "NONE"
cors {
allow_origins = ["*"]
allow_methods = ["*"]
allow_headers = ["*"]
max_age = 86400
}
}
resource "aws_lambda_permission" "allow_public_function_url" {
statement_id = "FunctionURLAllowPublicAccess"
action = "lambda:InvokeFunctionUrl"
function_name = aws_lambda_function.backend.function_name
principal = "*"
function_url_auth_type = "NONE"
}
resource "aws_lambda_permission" "allow_public_function_invoke" {
statement_id = "FunctionURLAllowPublicInvoke"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.backend.function_name
principal = "*"
}