sh-openswe-traces/terraform/s3.tf
Adam Moussa 5f430d9dfd
feat(infra): convert sh-openswe-traces to HCP Terraform (#8)
Freeze SAM CD and add terraform/ for seahaven-prod with account-suffixed
buckets so HCP owns deploy before mgmt cutover. Suppress CKV_AWS_40 for
the LangSmith export IAM user with documented mitigations.
2026-08-05 18:33:03 -04:00

219 lines
4.5 KiB
HCL

resource "aws_s3_bucket" "logs" {
bucket = local.logs_bucket_name
tags = {
role = "s3-access-logs"
}
lifecycle {
prevent_destroy = true
}
}
resource "aws_s3_bucket_public_access_block" "logs" {
bucket = aws_s3_bucket.logs.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_s3_bucket_ownership_controls" "logs" {
bucket = aws_s3_bucket.logs.id
rule {
object_ownership = "BucketOwnerEnforced"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "logs" {
bucket = aws_s3_bucket.logs.id
rule {
apply_server_side_encryption_by_default {
# SSE-S3 only: S3 log delivery cannot write to an SSE-KMS bucket.
sse_algorithm = "AES256"
}
}
}
resource "aws_s3_bucket_lifecycle_configuration" "logs" {
bucket = aws_s3_bucket.logs.id
rule {
id = "expire-access-logs"
status = "Enabled"
filter {}
expiration {
days = 365
}
}
}
resource "aws_s3_bucket_policy" "logs" {
bucket = aws_s3_bucket.logs.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "S3ServerAccessLogsWrite"
Effect = "Allow"
Principal = {
Service = "logging.s3.amazonaws.com"
}
Action = "s3:PutObject"
Resource = "${aws_s3_bucket.logs.arn}/s3-access/*"
Condition = {
ArnLike = {
"aws:SourceArn" = aws_s3_bucket.traces.arn
}
StringEquals = {
"aws:SourceAccount" = local.account_id
}
}
},
{
Sid = "DenyInsecureTransport"
Effect = "Deny"
Principal = "*"
Action = "s3:*"
Resource = [
aws_s3_bucket.logs.arn,
"${aws_s3_bucket.logs.arn}/*",
]
Condition = {
Bool = {
"aws:SecureTransport" = "false"
}
}
}
]
})
}
resource "aws_s3_bucket" "traces" {
bucket = local.traces_bucket_name
lifecycle {
prevent_destroy = true
}
}
resource "aws_s3_bucket_public_access_block" "traces" {
bucket = aws_s3_bucket.traces.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_s3_bucket_ownership_controls" "traces" {
bucket = aws_s3_bucket.traces.id
rule {
object_ownership = "BucketOwnerEnforced"
}
}
resource "aws_s3_bucket_versioning" "traces" {
bucket = aws_s3_bucket.traces.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "traces" {
bucket = aws_s3_bucket.traces.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
kms_master_key_id = aws_kms_key.traces.arn
}
bucket_key_enabled = true
}
}
resource "aws_s3_bucket_lifecycle_configuration" "traces" {
bucket = aws_s3_bucket.traces.id
rule {
id = "archive-exports-to-deep-archive"
status = "Enabled"
filter {
prefix = var.export_prefix
}
transition {
days = 90
storage_class = "DEEP_ARCHIVE"
}
}
rule {
id = "expire-noncurrent-versions"
status = "Enabled"
filter {}
noncurrent_version_expiration {
noncurrent_days = 90
}
}
rule {
id = "abort-incomplete-multipart"
status = "Enabled"
filter {}
abort_incomplete_multipart_upload {
days_after_initiation = 7
}
}
}
resource "aws_s3_bucket_logging" "traces" {
bucket = aws_s3_bucket.traces.id
target_bucket = aws_s3_bucket.logs.id
target_prefix = "s3-access/"
depends_on = [aws_s3_bucket_policy.logs]
}
resource "aws_s3_bucket_policy" "traces" {
bucket = aws_s3_bucket.traces.id
# No SSE-header enforcement Deny. LangSmith's exporter does not send an
# "aws:kms" SSE header, so a "must be aws:kms" Deny blocks its writes — and
# StringNotEqualsIfExists on a Deny also blocks header-less puts. Encryption
# is guaranteed by the bucket DEFAULT (SSE-KMS with our CMK).
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "DenyInsecureTransport"
Effect = "Deny"
Principal = "*"
Action = "s3:*"
Resource = [
aws_s3_bucket.traces.arn,
"${aws_s3_bucket.traces.arn}/*",
]
Condition = {
Bool = {
"aws:SecureTransport" = "false"
}
}
}
]
})
}