terraform-aws-s3-bucket

Architecture Document — Production-Grade AWS S3 Bucket Module

Terraform ≥ 1.5.0AWS Provider ≥ 5.20.0MIT License

Executive Summary

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.

Overview

14

Resources Managed

Bucket, versioning, encryption, public access, logging, lifecycle, replication, object lock, CORS, website, notifications, access points, policy, ownership

21

Input Variables

Bucket config, encryption, versioning, lifecycle, replication, object lock, CORS, website, events, access points, policy

5

Outputs

Bucket ID, ARN, domain name, regional domain, hosted zone ID

6

CIS Controls

Encryption, TLS enforcement, public access block, versioning, logging, lifecycle

Architecture Diagram

S3 Bucket Core Configuration

S3 Bucket
Versioning
SSE-KMS / AES-256
Encryption
Public Access
Block (All 4)
TLS Enforced
Bucket Policy

Lifecycle & Storage Tiering

Standard
Standard-IA
(30 days)
Glacier
(90 days)
Deep Archive
(365 days)

Event-Driven & Replication

S3 Events
Lambda
SQS Queue
SNS Topic
Source Bucket
Cross-Region
Replication
Destination
Bucket

Access Control

Access Points
VPC-Restricted
Object Lock
(WORM)
Governance
Compliance

Component Breakdown

ResourcePurpose
aws_s3_bucket.thisCore bucket with optional object lock, name or prefix-based naming
aws_s3_bucket_ownership_controls.thisBucketOwnerEnforced ownership (disables ACLs)
aws_s3_bucket_versioning.thisVersioning with optional MFA Delete for data protection
aws_s3_bucket_server_side_encryption_configuration.thisSSE-KMS (with bucket key) or AES-256 encryption at rest
aws_s3_bucket_public_access_block.thisAll four public access block settings for CIS compliance
aws_s3_bucket_logging.thisServer access logging to target bucket with configurable prefix
aws_s3_bucket_lifecycle_configuration.thisLifecycle rules with transitions, expiration, noncurrent version management
aws_s3_bucket_replication_configuration.thisCross-region/same-region replication with delete marker handling
aws_s3_bucket_object_lock_configuration.thisWORM protection in Governance or Compliance mode with retention period
aws_s3_bucket_cors_configuration.thisCORS rules for browser-based access (headers, methods, origins, max age)
aws_s3_bucket_website_configuration.thisStatic website hosting with index and error documents
aws_s3_bucket_notification.thisEvent notifications to Lambda, SQS, and SNS with prefix/suffix filters
aws_s3_access_point.thisNamed access points with optional VPC restriction and custom policies
aws_s3_bucket_policy.thisCustom bucket policy merged with auto-generated TLS enforcement policy

Data Flow

  1. Object upload is encrypted at rest using SSE-KMS (with bucket key) or AES-256 depending on configuration
  2. Bucket policy enforces TLS 1.2+ for all requests, denying any HTTP connections
  3. Public access block prevents any public ACLs or policies from being applied
  4. Versioning maintains all versions of objects; MFA Delete requires two-factor for deletions
  5. Lifecycle rules automatically transition objects through storage tiers and expire old versions
  6. Event notifications trigger Lambda functions, SQS queues, or SNS topics on object events
  7. Replication asynchronously copies objects to destination bucket(s) across regions
  8. Access points provide named network endpoints with per-point permissions and optional VPC restriction
  9. Object Lock prevents object deletion/modification for the configured retention period
  10. Access logging records all requests to a separate target bucket for audit trails

Security Controls

CIS AWS Foundations Benchmark Alignment

ControlDescriptionDefault
2.1.1S3 bucket server-side encryption enabledEnabled (SSE-S3 or SSE-KMS)
2.1.2S3 bucket policy denies HTTP requestsEnforced (enforce_tls = true)
2.1.5S3 buckets with Block Public AccessEnabled (all four settings)
3.6S3 bucket access logging enabledConfigurable (enable_logging)

AWS Security Hub Controls

S3.1 / S3.8

Block public access enabled at bucket level (all four settings default to true).

S3.4

Server-side encryption enabled by default. Supports SSE-KMS with customer-managed keys.

S3.5

TLS enforcement via bucket policy. Denies requests over HTTP and TLS versions below 1.2.

S3.9

Server access logging configurable with target bucket and prefix for audit trails.

S3.10 / S3.13

Lifecycle policies for versioned objects with transitions and noncurrent version expiration.

S3.11

Event notifications to Lambda, SQS, and SNS with object-level event filters.

Industry Adaptation

IndustryUse CaseConfiguration Focus
Financial ServicesRegulatory document retentionObject Lock (COMPLIANCE mode), KMS CMK, versioning, 7-year lifecycle, access logging
HealthcareHIPAA-compliant medical recordsKMS encryption, TLS enforced, no public access, access logging, MFA Delete
Media / EntertainmentVideo asset storage and deliveryIntelligent Tiering, CORS for web players, CloudFront integration, lifecycle to Glacier
Data EngineeringData lake landing zoneEvent notifications (Lambda), VPC access points, lifecycle tiering, replication for DR
E-CommerceStatic website and asset hostingWebsite hosting enabled, CORS, CloudFront alias, lifecycle rules for logs
Compliance / AuditImmutable audit log storageObject Lock (GOVERNANCE), versioning, access logging, cross-region replication

Production Readiness Checklist

Configuration Reference

Key Variables

VariableTypeDefaultDescription
bucket_namestringnullGlobally unique bucket name (3-63 chars)
bucket_prefixstringnullPrefix for auto-generated unique name
force_destroyboolfalseAllow destroying non-empty buckets
enable_versioningbooltrueEnable object versioning
mfa_deleteboolfalseRequire MFA for version deletes
enable_encryptionbooltrueEnable server-side encryption
kms_key_arnstringnullKMS key ARN (null = AES-256)
block_public_accessbooltrueEnable all 4 public access block settings
enforce_tlsbooltrueDeny HTTP via bucket policy
enable_loggingboolfalseEnable access logging
lifecycle_ruleslist(object)[]Transitions, expiration, noncurrent version management
enable_replicationboolfalseEnable cross-region replication
enable_object_lockboolfalseEnable WORM (must be set at creation)
object_lock_modestringGOVERNANCEGOVERNANCE or COMPLIANCE
object_lock_daysnumber30Default retention period in days
enable_websiteboolfalseEnable static website hosting
event_notificationsobject{}Lambda, SQS, SNS notification targets
access_pointsmap(object){}Named access points with VPC config

Outputs

OutputDescription
bucket_idThe name of the bucket
bucket_arnARN in format arn:aws:s3:::bucket-name
bucket_domain_namebucket-name.s3.amazonaws.com
bucket_regional_domain_namebucket-name.s3.REGION.amazonaws.com
bucket_hosted_zone_idRoute 53 Hosted Zone ID for the bucket region

Cost Estimation

FeatureApproximate 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

Deployment

# 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

Links