|
| 1 | +# Stores encrypted package blobs out-of-band from Postgres so the API can |
| 2 | +# return short presigned URLs instead of streaming hundreds of MB through |
| 3 | +# Lambda + API Gateway (which is slow and capped at 6MB). |
| 4 | +# |
| 5 | +# The blob itself is encrypted client-key-derived AES-CBC by the worker, so |
| 6 | +# there's no privacy concern about the bucket holding it — only the holder |
| 7 | +# of the UPN can decrypt it. |
| 8 | + |
| 9 | +resource "aws_s3_bucket" "package_data" { |
| 10 | + bucket = "${local.name}-package-data" |
| 11 | +} |
| 12 | + |
| 13 | +resource "aws_s3_bucket_server_side_encryption_configuration" "package_data" { |
| 14 | + bucket = aws_s3_bucket.package_data.id |
| 15 | + |
| 16 | + rule { |
| 17 | + apply_server_side_encryption_by_default { |
| 18 | + sse_algorithm = "AES256" |
| 19 | + } |
| 20 | + } |
| 21 | +} |
| 22 | + |
| 23 | +resource "aws_s3_bucket_public_access_block" "package_data" { |
| 24 | + bucket = aws_s3_bucket.package_data.id |
| 25 | + |
| 26 | + block_public_acls = true |
| 27 | + block_public_policy = true |
| 28 | + ignore_public_acls = true |
| 29 | + restrict_public_buckets = true |
| 30 | +} |
| 31 | + |
| 32 | +resource "aws_s3_bucket_versioning" "package_data" { |
| 33 | + bucket = aws_s3_bucket.package_data.id |
| 34 | + versioning_configuration { |
| 35 | + status = "Disabled" |
| 36 | + } |
| 37 | +} |
| 38 | + |
| 39 | +resource "aws_s3_bucket_lifecycle_configuration" "package_data" { |
| 40 | + bucket = aws_s3_bucket.package_data.id |
| 41 | + |
| 42 | + rule { |
| 43 | + id = "expire-blobs" |
| 44 | + status = "Enabled" |
| 45 | + |
| 46 | + filter {} |
| 47 | + |
| 48 | + expiration { |
| 49 | + days = var.package_data_retention_days |
| 50 | + } |
| 51 | + |
| 52 | + abort_incomplete_multipart_upload { |
| 53 | + days_after_initiation = 1 |
| 54 | + } |
| 55 | + } |
| 56 | +} |
| 57 | + |
| 58 | +# CORS so the frontend (web.dumpus.app and dev) can fetch the presigned URL |
| 59 | +# from the browser. Only GET is allowed. |
| 60 | +resource "aws_s3_bucket_cors_configuration" "package_data" { |
| 61 | + bucket = aws_s3_bucket.package_data.id |
| 62 | + |
| 63 | + cors_rule { |
| 64 | + allowed_methods = ["GET"] |
| 65 | + allowed_origins = ["*"] |
| 66 | + allowed_headers = ["*"] |
| 67 | + expose_headers = ["ETag", "Content-Length"] |
| 68 | + max_age_seconds = 300 |
| 69 | + } |
| 70 | +} |
| 71 | + |
| 72 | +# VPC gateway endpoint for S3 so worker uploads (potentially hundreds of MB) |
| 73 | +# don't go through fck-nat. Gateway endpoints are free, route table-based. |
| 74 | +resource "aws_vpc_endpoint" "s3" { |
| 75 | + vpc_id = aws_vpc.main.id |
| 76 | + service_name = "com.amazonaws.${var.region}.s3" |
| 77 | + vpc_endpoint_type = "Gateway" |
| 78 | + route_table_ids = [aws_route_table.private.id] |
| 79 | + |
| 80 | + tags = { Name = "${local.name}-s3-endpoint" } |
| 81 | +} |
0 commit comments