meal-order-manager/terraform/artifacts.tf
Adam Moussa 40ea4ed898
feat(infra): migrate meal-order-manager to HCP Terraform
Freeze SAM CD and add greenfield Terraform for seahaven-prod so HCP is the sole stack deploy path.
2026-08-07 19:19:51 -04:00

130 lines
3.6 KiB
HCL

# Lambda packaging.
#
# HCP plan and apply run on separate workers, so a zip written during plan is
# not on disk at apply time. The bytes are therefore carried inside the plan as
# content_base64 on aws_s3_object and uploaded at apply, and the functions and
# layer read from S3 rather than from a local file.
#
# The build itself runs during plan through an external data source:
# local-exec provisioners only run on apply, and archive_file needs build/ to
# already exist when the plan is computed.
#
# build_packages.sh deletes boto3, botocore, s3transfer, jmespath and urllib3
# from the layer after pip install. The Python 3.12 runtime ships boto3, and
# leaving it in the layer would push the base64-encoded plan payload into the
# tens of megabytes.
data "external" "package_build" {
program = ["bash", "${path.module}/build_packages_external.sh"]
}
resource "aws_s3_bucket" "artifacts" {
bucket = local.artifacts_bucket_name
tags = {
Purpose = "Lambda deployment packages for meal-order-manager"
}
}
resource "aws_s3_bucket_public_access_block" "artifacts" {
bucket = aws_s3_bucket.artifacts.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_s3_bucket_ownership_controls" "artifacts" {
bucket = aws_s3_bucket.artifacts.id
rule {
object_ownership = "BucketOwnerEnforced"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "artifacts" {
bucket = aws_s3_bucket.artifacts.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
resource "aws_s3_bucket_versioning" "artifacts" {
bucket = aws_s3_bucket.artifacts.id
versioning_configuration {
status = "Enabled"
}
}
# Superseded package versions are only useful for a manual rollback, and the
# function/layer resources always point at the current object.
resource "aws_s3_bucket_lifecycle_configuration" "artifacts" {
bucket = aws_s3_bucket.artifacts.id
rule {
id = "expire-noncurrent-packages"
status = "Enabled"
filter {}
noncurrent_version_expiration {
noncurrent_days = 180
}
}
rule {
id = "abort-incomplete-multipart"
status = "Enabled"
filter {}
abort_incomplete_multipart_upload {
days_after_initiation = 7
}
}
depends_on = [aws_s3_bucket_versioning.artifacts]
}
# ---------------------------------------------------------------------------
# Packages
# ---------------------------------------------------------------------------
data "archive_file" "shared_layer" {
type = "zip"
source_dir = "${path.module}/build/layer"
output_path = "${path.module}/build/packages/shared-layer.zip"
depends_on = [data.external.package_build]
}
data "archive_file" "function" {
for_each = local.function_packages
type = "zip"
source_dir = "${path.module}/build/functions/${each.key}"
output_path = "${path.module}/build/packages/${each.key}.zip"
depends_on = [data.external.package_build]
}
resource "aws_s3_object" "shared_layer" {
bucket = aws_s3_bucket.artifacts.id
key = "layers/meal-order-manager-shared.zip"
content_base64 = filebase64(data.archive_file.shared_layer.output_path)
source_hash = data.archive_file.shared_layer.output_base64sha256
}
resource "aws_s3_object" "function" {
for_each = local.function_packages
bucket = aws_s3_bucket.artifacts.id
key = "functions/${each.key}.zip"
content_base64 = filebase64(data.archive_file.function[each.key].output_path)
source_hash = data.archive_file.function[each.key].output_base64sha256
}