Creating and managing object storage with Terraform turns ad-hoc console clicks into repeatable, versioned infrastructure. Terraform create bucket workflows cover both AWS S3 and Google Cloud Storage, with provider-native resources and community modules that expose the full feature set of modern buckets. The reference material shows concrete module usage for AWS S3, GCP bucket creation with object upload, and step-by-step command sequences that are used in practice.
AWS S3 Bucket Module Capabilities
The terraform-aws-modules/terraform-aws-s3-bucket module creates an S3 bucket on AWS with all or almost all features provided by the Terraform AWS provider. The module supports configurations that map directly to production requirements.
Supported features include:
- static web-site hosting
- access logging
- versioning
- CORS
- lifecycle rules
- server-side encryption
- object locking
- Cross-Region Replication (CRR)
- ELB log delivery bucket policy
- ALB/NLB log delivery bucket policy
- WAF log delivery bucket policy
- Account-level Public Access Block
- S3 Directory Bucket
- S3 Table Bucket
- S3 Vectors
The module exposes parameters that control creation and ownership.
| Parameter | Type | Description | Default |
|---|---|---|---|
| bucket | string | The name of the bucket. If omitted, Terraform will assign a random, unique name | null |
| bucket_namespace | string | Namespace for the bucket. Determines bucket naming scope. Valid values: account-regional, global. Defaults to global | null |
| bucket_prefix | string | Creates a unique bucket name beginning with the specified prefix. Conflicts with bucket | null |
| controlobjectownership | bool | Whether to manage S3 Bucket Ownership Controls on this bucket | false |
| cors_rule | any | List of maps containing rules for Cross-Origin Resource Sharing | [] |
| create_bucket | bool | Controls if S3 bucket should be created | true |
| createmetadataconfiguration | bool | Whether to create metadata configuration resource | false |
| data_redundancy | string | Data redundancy. Valid values: SingleAvailabilityZone | null |
| expectedbucketowner | string | The account ID of the expected bucket owner | null |
| force_destroy | bool | A boolean that indicates all objects should be deleted from the bucket so that the bucket can be destroyed without error. These objects are not recoverable | false |
| grant | any | An ACL policy grant. Conflicts with acl | [] |
| ignorepublicacls | bool | Whether Amazon S3 should ignore public ACLs for this bucket |
Standard Module Usage
A basic private bucket with versioning enabled can be declared as:
hcl
module "s3_bucket" {
source = "terraform-aws-modules/s3-bucket/aws"
bucket = "my-s3-bucket"
acl = "private"
control_object_ownership = true
object_ownership = "ObjectWriter"
versioning = {
enabled = true
}
}
For log delivery buckets, ownership controls and specific ACLs are required. An ELB log delivery example:
hcl
module "s3_bucket_for_logs" {
source = "terraform-aws-modules/s3-bucket/aws"
bucket = "my-s3-bucket-for-logs"
acl = "log-delivery-write"
force_destroy = true
control_object_ownership = true
object_ownership = "ObjectWriter"
attach_elb_log_delivery_policy = true
}
A combined ELB and ALB/NLB log delivery configuration:
hcl
module "s3_bucket_for_logs" {
source = "terraform-aws-modules/s3-bucket/aws"
bucket = "my-s3-bucket-for-logs"
force_destroy = true
control_object_ownership = true
object_ownership = "ObjectWriter"
attach_elb_log_delivery_policy = true
attach_lb_log_delivery_policy = true
}
A WAF log delivery bucket is created similarly with the module source and bucket name parameters.
Terraform Workflow for AWS S3
The canonical three-step workflow is used across examples.
- $ terraform init
This is the first command. It initializes the working directory and downloads the AWS provider.
- $ terraform plan
The second command would be to run a Terraform plan. This command shows the bucket, public access block, and ownership controls that Terraform is about to create.
- $ terraform apply
Apply the Terraform configuration using the terraform apply command, which will eventually create an S3 bucket in AWS.
Note: These screenshots reflect an earlier version of the example. The updated code in this article uses current Terraform AWS provider patterns, so resource names and plan/apply output may differ slightly.
After the apply completes, you should see a new S3 bucket named spacelift-test1-s3 in your AWS account.
A simpler native resource example uses an explicit bucket name and tags:
hcl
resource "aws_s3_bucket" "my_s3_bucket"{
bucket = "my-s3-test-bucket02"
tags = {
Name = "My bucket"
Enviroment ="Dev"
}
}
After this run terraform plan command. The plan command determines the deltas between the current configuration and prior state data.
terraform apply
This command will start create S3 bucket in aws console. After few minutes the bucket has been created.
Step 5 : To confirm that your S3 bucket has been created, head over to the AWS management console then go to S3 then Buckets. You will see that our bucket "my-s3-test-bucket02" has been created.
Step 6: If you’d like to clean up this S3 bucket you can run the command terraform destroy in the terminal.
terraform destroy
Uploading Objects to S3
In the previous step, we created an S3 bucket with Terraform. In this step, we will upload files to that bucket using the awss3bucket_object resource.
If you are working from older examples, you may still see awss3bucket_object, but that resource has been deprecated.
The current approach uses awss3object for uploads.
Google Cloud Storage Bucket Creation
Terraform can create a Google Cloud Storage bucket and upload an object in the same configuration.
Define the infrastructure in the Terraform configuration file:
Open the main.tf file. Copy the following sample to the main.tf file.
```hcl
Create new storage bucket in the US # location with Standard Storage
resource "googlestoragebucket" "static" {
name = "BUCKETNAME"
location = "US"
storageclass = "STANDARD"
uniformbucketlevel_access = true
}
Upload a text file as an object # to the storage bucket
resource "googlestoragebucketobject" "default" {
name = "OBJECTNAME"
source = "OBJECTPATH"
contenttype = "text/plain"
bucket = googlestoragebucket.static.id
}
```
Replace:
- BUCKET_NAME with the name of the bucket you want to create. For example, my-bucket
- OBJECTNAME with the name of the object you want to upload. For this quickstart, enter the name samplefile.txt
- OBJECT_PATH with the path to the object you want to upload
When you apply the changes, Terraform creates a storage bucket and uploads sample_file.txt to the bucket.
bash
terraform apply
Example output:
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create
Terraform will perform the following actions:
googlestoragebucket.static will be created
- resource "googlestoragebucket" "static" {
- forcedestroy = false
- id = (known after apply)
- location = "US"
- name = "my-bucket"
- project = "my-project"
- publicaccessprevention = (known after apply)
- selflink = (known after apply)
- storageclass = "STANDARD"
- uniformbucketlevelaccess = true
- url = (known after apply)
- versioning {
- enabled = (known after apply)
}
- enabled = (known after apply)
- website {
- mainpagesuffix = (known after apply)
- notfoundpage = (known after apply)
}
}
googlestoragebucket_object.default will be created
- resource "googlestoragebucketobject" "default" {
- bucket = (known after apply)
- content
- crc32c = (known after apply)
- detectmd5hash = "different hash"
- id = (known after apply)
- kmskeyname = (known after apply)
- md5hash = (known after apply)
- medialink = (known after apply)
- name = "samplefile.txt"
- outputname = (known after apply)
- selflink = (known after apply)
- source = "samplefile.txt"
- storage_class = (known after apply)
}
Plan: 2 to add, 0 to change, 0 to destroy
Practical Project Notes
A hands-on project demonstrates the workflow in practice.
Project Link: View Project
Author: Abdulrahman Abdulkadir
Email: [email protected]
In this project, I will demonstrate how to create S3 buckets using Terraform. The goal is to automate the provisioning of AWS S3 storage by writing Infrastructure as Code, ensuring consistency, repeatability, and easy management of bucket configurations such as versioning, access policies, and lifecycle rules.
Services I used were AWS S3 for storage and the AWS CLI for managing credentials and verifying resources. Key concepts I learnt include infrastructure as code, Terraform providers, resource blocks, state management, the sequence of terraform init, plan, and apply, as well as automating the creation and configuration of cloud resources, applying access controls, and uploading objects to S3 buckets in a repeatable and consistent way.
This project took me approximately 3 to 4 hours to complete. The most challenging part was correctly configuring AWS credentials and ensuring Terraform had the proper access to create and manage resources. It was most rewarding to see the S3 bucket and objects successfully deployed and managed automatically through Terraform, demonstrating the power of infrastructure as code.
I did this project today to gain hands-on experience with Terraform and understand how to automate the creation and management of AWS resources like S3 buckets
Conclusion
Terraform create bucket patterns converge on a small set of commands and a growing set of module features. For AWS S3, the terraform-aws-modules/s3-bucket module covers static web hosting, access logging, versioning, CORS, lifecycle rules, server-side encryption, object locking, Cross-Region Replication, and log delivery policies for ELB, ALB/NLB, and WAF, plus modern bucket types such as Directory Bucket, Table Bucket, and Vectors. Ownership controls and force_destroy behavior are exposed for safe automation.
For Google Cloud, the googlestoragebucket resource creates a bucket with location, storage class, uniform bucket level access, versioning, and website configuration, while googlestoragebucketobject uploads samplefile.txt with content type text/plain.
The workflow remains init, plan, apply, and destroy, with credential setup being the most common friction point in practice. Using modules for AWS and native resources for GCP gives repeatable, auditable bucket provisioning across clouds.