Terraform AWS S3 Bucket Config Builder
Terraform lets you define cloud infrastructure as version-controlled code. This builder generates HCL for an AWS S3 bucket using the modern resource layout introduced in AWS provider v4, where versioning, encryption, public access, and lifecycle are separate resources that all reference the core bucket. It produces a secure-by-default configuration you can drop into a Terraform module.
Why the resource split matters
Before AWS provider v4, a single aws_s3_bucket block controlled versioning,
encryption, ACLs, website hosting, and more as inline arguments. That made the
resource large and meant changing one sub-feature required touching the whole
block. Provider v4 deprecated all those inline arguments in favour of dedicated
resources:
aws_s3_bucket_versioning— controls object versioning independentlyaws_s3_bucket_server_side_encryption_configuration— sets SSE algorithmaws_s3_bucket_public_access_block— locks down the four public-access flagsaws_s3_bucket_lifecycle_configuration— manages expiration and transition rules
Each companion resource references the core bucket via bucket = aws_s3_bucket.this.id, which also creates an implicit dependency so Terraform creates the bucket first.
Encryption options: AES256 versus aws:kms
AES256 (SSE-S3) uses AWS-managed keys. Objects are encrypted at rest automatically. You do not manage keys and there is no additional cost. It is appropriate for most general-purpose buckets where you do not need audit logs of individual object decryption.
aws:kms (SSE-KMS) uses AWS Key Management Service. You can supply a customer-managed key (CMK) for tighter control, or let AWS manage a KMS key for you. Every decrypt operation is logged in CloudTrail, which is necessary for compliance workloads (SOC 2, HIPAA, PCI DSS). SSE-KMS has a small additional cost per request.
Lifecycle expiration — practical uses
A lifecycle rule that expires objects after N days is useful in several patterns:
| Use case | Recommended expiry |
|---|---|
| Access log bucket | 30–90 days, then delete |
| Temporary build artifacts | 7–14 days |
| Application logs (before archiving) | 90 days, then transition to Glacier |
| Compliance archive | Never expire — instead transition to Glacier Deep Archive |
For compliance archives, combine versioning with lifecycle transitions rather than expiration, so old versions move to cheaper storage rather than disappearing.
How to use the generated HCL
Copy the output and save it as s3.tf (or main.tf) in your Terraform working directory. Run:
terraform init
terraform plan
terraform apply
terraform plan shows you exactly what will be created before anything is provisioned. Review it carefully — in particular check the bucket name, since S3 names are globally unique across all AWS accounts and cannot be changed after creation.
Naming tips
- Use a prefix that makes the bucket globally unique:
mycompany-prod-app-assetsrather thanapp-assets. - Avoid dots in bucket names if you plan to use TLS, since wildcard SSL certificates do not cover dotted names correctly.
- Once a bucket is created, its name cannot be changed — Terraform would destroy and recreate it, which can cause data loss if not planned for.
Always keep public access blocking on unless you are intentionally hosting a public static website via S3. For compliance workloads, prefer aws:kms with a dedicated KMS key so access is logged in CloudTrail.