Model/deployment/terraform/lambda/ara_export/main.tf
Khalim Conn-Kowlessar 30c7133b9a Add ara_export Lambda + SQS terraform module 🟩
Self-contained root module mirroring bulk_document_download (4GB memory per
ADR-0065, exports-bucket-only IAM). Cross-module wiring (shared ECR/state,
fast-api remote_state + ARA_EXPORT_SQS_URL env, CI image build) still needs a
terraform plan review — unverifiable in this environment.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 09:38:07 +00:00

84 lines
3.1 KiB
HCL

############################################
# ara_export Lambda (ADR-0065) — builds one branded sheet-per-scenario .xlsx
# from persisted modelling data, uploads it to the exports bucket, and emails a
# presigned link. Reads only the DB (no source-bucket reads, unlike
# bulk_document_download), so the role needs only exports-bucket write/presign.
############################################
data "aws_secretsmanager_secret_version" "db_credentials" {
secret_id = "${var.stage}/assessment_model/db_credentials"
}
data "aws_secretsmanager_secret_version" "ses_smtp" {
secret_id = "${var.stage}/ses/smtp_credentials"
}
locals {
db_credentials = jsondecode(data.aws_secretsmanager_secret_version.db_credentials.secret_string)
ses_smtp = jsondecode(data.aws_secretsmanager_secret_version.ses_smtp.secret_string)
document_exports_bucket = "retrofit-document-exports-${var.stage}"
}
############################################
# Lambda + SQS queue + trigger
############################################
module "lambda" {
source = "../../modules/lambda_with_sqs"
name = var.lambda_name
stage = var.stage
image_uri = local.image_uri
reserved_concurrent_executions = var.reserved_concurrent_executions
batch_size = var.batch_size
maximum_concurrency = var.maximum_concurrency
timeout = 900
# Normal-mode openpyxl holds the workbook in memory (ADR-0065); 4 GB covers the
# 100k-property ceiling. Raise here (then switch to write_only) if it OOMs.
memory_size = 4096
environment = {
STAGE = var.stage
LOG_LEVEL = "info"
POSTGRES_USERNAME = local.db_credentials.db_assessment_model_username
POSTGRES_PASSWORD = local.db_credentials.db_assessment_model_password
POSTGRES_HOST = var.db_host
POSTGRES_DATABASE = var.db_name
POSTGRES_PORT = var.db_port
DOCUMENT_EXPORTS_BUCKET = local.document_exports_bucket
# SES SMTP — IAM-user credentials sourced from Secrets Manager (modules/ses).
SES_SMTP_HOST = "email-smtp.eu-west-2.amazonaws.com"
SES_SMTP_PORT = "587"
SES_SMTP_USERNAME = local.ses_smtp.username
SES_SMTP_PASSWORD = local.ses_smtp.password
SES_SMTP_FROM_ADDRESS = var.ses_from_address
}
}
############################################
# IAM: write + presign-read the workbook on the dedicated exports bucket.
# GetObject is required so the Lambda-signed presigned GET URL resolves.
############################################
module "s3_exports" {
source = "../../modules/s3_iam_policy"
policy_name = "AraExportS3Exports-${var.stage}"
policy_description = "Allow ara_export Lambda to write and presign-read Scenario Exports on the exports bucket"
bucket_arns = ["arn:aws:s3:::${local.document_exports_bucket}"]
actions = ["s3:PutObject", "s3:GetObject"]
resource_paths = ["/*"]
}
resource "aws_iam_role_policy_attachment" "s3_exports" {
role = module.lambda.role_name
policy_arn = module.s3_exports.policy_arn
}
# NOTE: no ses:* on the role — the handler sends over SMTP with the SES IAM-user
# credentials injected above.