# 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 }