Architecture Document — Production-Grade AWS S3 Bucket Module
Terraform ≥ 1.5.0AWS Provider ≥ 5.20.0MIT License
This Terraform module provisions production-grade AWS S3 buckets with comprehensive security controls aligned to CIS AWS Foundations Benchmark and AWS Security Hub best practices. It manages encryption (SSE-S3/SSE-KMS), versioning with MFA Delete, public access blocking, TLS enforcement, lifecycle management with intelligent tiering, cross-region replication, Object Lock (WORM), CORS configuration, static website hosting, event notifications (Lambda/SQS/SNS), S3 Access Points with VPC restriction, and custom bucket policies.
Bucket, versioning, encryption, public access, logging, lifecycle, replication, object lock, CORS, website, notifications, access points, policy, ownership
Bucket config, encryption, versioning, lifecycle, replication, object lock, CORS, website, events, access points, policy
Bucket ID, ARN, domain name, regional domain, hosted zone ID
Encryption, TLS enforcement, public access block, versioning, logging, lifecycle
| Resource | Purpose |
|---|---|
aws_s3_bucket.this | Core bucket with optional object lock, name or prefix-based naming |
aws_s3_bucket_ownership_controls.this | BucketOwnerEnforced ownership (disables ACLs) |
aws_s3_bucket_versioning.this | Versioning with optional MFA Delete for data protection |
aws_s3_bucket_server_side_encryption_configuration.this | SSE-KMS (with bucket key) or AES-256 encryption at rest |
aws_s3_bucket_public_access_block.this | All four public access block settings for CIS compliance |
aws_s3_bucket_logging.this | Server access logging to target bucket with configurable prefix |
aws_s3_bucket_lifecycle_configuration.this | Lifecycle rules with transitions, expiration, noncurrent version management |
aws_s3_bucket_replication_configuration.this | Cross-region/same-region replication with delete marker handling |
aws_s3_bucket_object_lock_configuration.this | WORM protection in Governance or Compliance mode with retention period |
aws_s3_bucket_cors_configuration.this | CORS rules for browser-based access (headers, methods, origins, max age) |
aws_s3_bucket_website_configuration.this | Static website hosting with index and error documents |
aws_s3_bucket_notification.this | Event notifications to Lambda, SQS, and SNS with prefix/suffix filters |
aws_s3_access_point.this | Named access points with optional VPC restriction and custom policies |
aws_s3_bucket_policy.this | Custom bucket policy merged with auto-generated TLS enforcement policy |
| Control | Description | Default |
|---|---|---|
| 2.1.1 | S3 bucket server-side encryption enabled | Enabled (SSE-S3 or SSE-KMS) |
| 2.1.2 | S3 bucket policy denies HTTP requests | Enforced (enforce_tls = true) |
| 2.1.5 | S3 buckets with Block Public Access | Enabled (all four settings) |
| 3.6 | S3 bucket access logging enabled | Configurable (enable_logging) |
Block public access enabled at bucket level (all four settings default to true).
Server-side encryption enabled by default. Supports SSE-KMS with customer-managed keys.
TLS enforcement via bucket policy. Denies requests over HTTP and TLS versions below 1.2.
Server access logging configurable with target bucket and prefix for audit trails.
Lifecycle policies for versioned objects with transitions and noncurrent version expiration.
Event notifications to Lambda, SQS, and SNS with object-level event filters.
| Industry | Use Case | Configuration Focus |
|---|---|---|
| Financial Services | Regulatory document retention | Object Lock (COMPLIANCE mode), KMS CMK, versioning, 7-year lifecycle, access logging |
| Healthcare | HIPAA-compliant medical records | KMS encryption, TLS enforced, no public access, access logging, MFA Delete |
| Media / Entertainment | Video asset storage and delivery | Intelligent Tiering, CORS for web players, CloudFront integration, lifecycle to Glacier |
| Data Engineering | Data lake landing zone | Event notifications (Lambda), VPC access points, lifecycle tiering, replication for DR |
| E-Commerce | Static website and asset hosting | Website hosting enabled, CORS, CloudFront alias, lifecycle rules for logs |
| Compliance / Audit | Immutable audit log storage | Object Lock (GOVERNANCE), versioning, access logging, cross-region replication |
| Variable | Type | Default | Description |
|---|---|---|---|
bucket_name | string | null | Globally unique bucket name (3-63 chars) |
bucket_prefix | string | null | Prefix for auto-generated unique name |
force_destroy | bool | false | Allow destroying non-empty buckets |
enable_versioning | bool | true | Enable object versioning |
mfa_delete | bool | false | Require MFA for version deletes |
enable_encryption | bool | true | Enable server-side encryption |
kms_key_arn | string | null | KMS key ARN (null = AES-256) |
block_public_access | bool | true | Enable all 4 public access block settings |
enforce_tls | bool | true | Deny HTTP via bucket policy |
enable_logging | bool | false | Enable access logging |
lifecycle_rules | list(object) | [] | Transitions, expiration, noncurrent version management |
enable_replication | bool | false | Enable cross-region replication |
enable_object_lock | bool | false | Enable WORM (must be set at creation) |
object_lock_mode | string | GOVERNANCE | GOVERNANCE or COMPLIANCE |
object_lock_days | number | 30 | Default retention period in days |
enable_website | bool | false | Enable static website hosting |
event_notifications | object | {} | Lambda, SQS, SNS notification targets |
access_points | map(object) | {} | Named access points with VPC config |
| Output | Description |
|---|---|
bucket_id | The name of the bucket |
bucket_arn | ARN in format arn:aws:s3:::bucket-name |
bucket_domain_name | bucket-name.s3.amazonaws.com |
bucket_regional_domain_name | bucket-name.s3.REGION.amazonaws.com |
bucket_hosted_zone_id | Route 53 Hosted Zone ID for the bucket region |
| Feature | Approximate Cost |
|---|---|
| S3 Standard Storage | ~$0.023/GB/month (us-east-1) |
| Intelligent Tiering | $0.0025 per 1,000 objects monitoring fee |
| Standard-IA | ~$0.0125/GB/month |
| Glacier Instant Retrieval | ~$0.004/GB/month |
| Glacier Flexible | ~$0.0036/GB/month |
| Deep Archive | ~$0.00099/GB/month |
| KMS Encryption | $1/month/key + $0.03 per 10K requests |
# Minimal - secure defaults
module "s3_bucket" {
source = "github.com/kogunlowo123/terraform-aws-s3-bucket"
bucket_name = "my-secure-bucket"
tags = { Environment = "production" }
}
# Full-featured
module "s3_bucket" {
source = "github.com/kogunlowo123/terraform-aws-s3-bucket"
bucket_name = "my-app-data"
enable_encryption = true
kms_key_arn = aws_kms_key.s3.arn
enable_logging = true
logging_target_bucket = "my-logs-bucket"
lifecycle_rules = [
{
id = "tiering"
enabled = true
transitions = [
{ days = 30, storage_class = "STANDARD_IA" },
{ days = 90, storage_class = "GLACIER" },
{ days = 365, storage_class = "DEEP_ARCHIVE" },
]
noncurrent_version_expiration = { days = 180 }
},
]
enable_replication = true
replication_role_arn = aws_iam_role.replication.arn
replication_rules = [{
id = "replicate-all"
status = "Enabled"
priority = 1
destination_bucket = module.replica.bucket_arn
}]
tags = { Environment = "production" }
}
terraform init terraform plan terraform apply