# Private, versioned, KMS-encrypted bucket with access logging and an expiry rule for old versions. # Checkov CKV_AWS_144 (cross-region replication) and CKV2_AWS_62 (event notifications) are skipped # with a reason: both are per-workload decisions made by the caller, not by this module. resource "aws_s3_bucket" "this" { #checkov:skip=CKV_AWS_144:Cross-region replication is configured by callers that need it #checkov:skip=CKV2_AWS_62:Event notifications are wired up by the consuming service bucket = var.name tags = var.tags lifecycle { prevent_destroy = true } } resource "aws_s3_bucket_ownership_controls" "this" { bucket = aws_s3_bucket.this.id rule { object_ownership = "BucketOwnerEnforced" } } resource "aws_s3_bucket_public_access_block" "this" { bucket = aws_s3_bucket.this.id block_public_acls = true block_public_policy = true ignore_public_acls = true restrict_public_buckets = true } resource "aws_s3_bucket_versioning" "this" { bucket = aws_s3_bucket.this.id versioning_configuration { status = "Enabled" } } resource "aws_s3_bucket_server_side_encryption_configuration" "this" { bucket = aws_s3_bucket.this.id rule { apply_server_side_encryption_by_default { sse_algorithm = "aws:kms" kms_master_key_id = var.kms_key_arn } bucket_key_enabled = true } } resource "aws_s3_bucket_logging" "this" { bucket = aws_s3_bucket.this.id target_bucket = var.log_bucket target_prefix = "s3/${var.name}/" } resource "aws_s3_bucket_lifecycle_configuration" "this" { bucket = aws_s3_bucket.this.id rule { id = "expire-noncurrent" status = "Enabled" filter {} noncurrent_version_expiration { noncurrent_days = var.noncurrent_days } abort_incomplete_multipart_upload { days_after_initiation = 7 } } depends_on = [aws_s3_bucket_versioning.this] } data "aws_iam_policy_document" "tls_only" { statement { sid = "DenyInsecureTransport" effect = "Deny" actions = ["s3:*"] resources = [ aws_s3_bucket.this.arn, "${aws_s3_bucket.this.arn}/*", ] principals { type = "*" identifiers = ["*"] } condition { test = "Bool" variable = "aws:SecureTransport" values = ["false"] } } } resource "aws_s3_bucket_policy" "tls_only" { bucket = aws_s3_bucket.this.id policy = data.aws_iam_policy_document.tls_only.json depends_on = [aws_s3_bucket_public_access_block.this] }