Terraform S3 module patterns operate on two distinct but related planes. One plane is the provisioning of AWS S3 buckets through a Terraform module that encapsulates the Terraform AWS provider capabilities. The other plane is the distribution of Terraform modules themselves via Amazon S3 as a private module source. Both planes converge on the use of S3 as a central artifact store and on the need for consistent, repeatable configuration. Organizations that already run on AWS find S3 module hosting practical because it eliminates the need for a public Terraform Registry or a separate Git server and allows IAM to govern access to module artifacts. The bucket provisioning module exposes a broad feature surface for static website hosting, access logging, versioning, CORS, lifecycle rules, server-side encryption, object locking, Cross-Region Replication, log delivery bucket policies, account-level Public Access Block, S3 Directory Bucket, S3 Table Bucket, and S3 Vectors. The S3 source pattern uses the s3:: prefix to instruct Terraform to download a zip archive from an S3 object, extract it, and use the contents as module code. The enterprise oriented alternative module emphasizes security first design with encryption by default, least privilege IAM, automatic cleanup of incomplete multipart uploads, TLS enforcement, and Checkov compliance scoring.
Terraform AWS S3 Bucket Module Feature Surface
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 feature surface is explicit and extensive.
- static web-site hosting
- access logging
- versioning
- CORS
- lifecycle rules
- server-side encryption
- object locking
- Cross-Region Replication
- 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 presence of static web-site hosting support means teams can provision buckets that serve objects directly to browsers without an additional web tier. Access logging support allows the module to configure server access logs to a separate bucket, which creates an audit trail for object access events. Versioning support enables retention of multiple versions of an object, which reduces accidental deletion risk and supports point-in-time recovery. CORS support allows browsers to perform cross-origin requests to bucket objects, which is required for web applications that load assets from S3. Lifecycle rules support provides automated transition and expiration of objects, which controls storage costs. Server-side encryption support ensures data at rest is protected. Object locking support provides WORM compliance for regulated workloads. Cross-Region Replication support enables durability and low-latency access across regions. ELB, ALB/NLB, and WAF log delivery bucket policies allow the module to attach the precise policies required for AWS load balancer and WAF log delivery. Account-level Public Access Block can be enforced to prevent accidental public exposure. S3 Directory Bucket, S3 Table Bucket, and S3 Vectors support reflects AWS’s newer data storage classes.
A feature table summarizes the capabilities:
| Feature Category | Supported Capabilities |
| S3 Website and Access | static web-site hosting, access logging, CORS |
| Data Protection | versioning, server-side encryption, object locking |
| Lifecycle and Cost | lifecycle rules |
| Replication | Cross-Region Replication |
| Log Delivery Policies | ELB log delivery bucket policy, ALB/NLB log delivery bucket policy, WAF log delivery bucket policy |
| Security Controls | Account-level Public Access Block |
| New Storage Classes | S3 Directory Bucket, S3 Table Bucket, S3 Vectors |
Object Ownership Controls and Versioning Configuration
Object ownership controls are expressed through controlobjectownership and objectownership parameters. The example configuration sets controlobjectownership to true and objectownership to ObjectWriter. This combination ensures proper object ownership controls, while versioning enables keeping multiple versions of an object.
The practical impact for users is that ACLs can be disabled in favor of bucket owner enforced ownership, which simplifies permission management and prevents permission-related errors during cross-account replication. Versioning enabled with controlobjectownership ensures that new objects and versions are written with consistent ownership semantics. In production environments, this reduces support tickets related to access denied errors and ensures that log delivery and replication processes succeed without additional ACL grants.
A typical secure bucket declaration uses these parameters together:
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
}
}
Log Delivery Bucket Policies and Force Destroy
Log delivery use cases are common for S3 buckets. The module supports dedicated configurations for ELB, ALB/NLB, and WAF logs. The log delivery bucket requires a specific ACL and policy attachment.
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
}
Force destroy set to true allows deletion of a non-empty bucket, which is important for ephemeral environments and automated test teardown. The log-delivery-write ACL grants the necessary write permissions for AWS services to deliver logs. Control object ownership with ObjectWriter ensures the bucket owner retains control over delivered objects.
A variant for ALB/NLB logs adds both ELB and LB policy attachments:
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
}
The attachlblogdeliverypolicy is required for ALB/NLB logs. The module abstracts the complex bucket policy documents that AWS requires for log delivery, reducing manual error.
A WAF log bucket example is initiated with:
module "s3_bucket_for_waf_logs" {
source = "terraform-aws-modules/s3-bucket/aws"
bucket =
The truncation in the reference indicates further parameters would follow for WAF specific configuration.
S3-Hosted Terraform Modules Packaging and Referencing
Storing Terraform modules in S3 buckets is a practical choice for organizations invested in AWS and wanting a simple private module distribution mechanism. You do not need a Terraform Registry or Git server. Just package your module as a zip file, upload it to S3, and reference it in your configuration. AWS IAM handles authentication, and S3 versioning can help protect module objects from accidental overwrites or deletions.
How S3 module sources work is that Terraform can download modules from S3 buckets using the s3:: prefix. When it encounters this source, it downloads the archive from S3, extracts it, and uses the contents as the module code. Terraform expects the S3 object to be a zip archive containing the module's .tf files.
A basic S3 module source declaration is:
module "vpc" {
source = "s3::https://my-terraform-modules.s3.amazonaws.com/vpc/v1.0.0.zip"
vpc_cidr = "10.0.0.0/16"
environment = "production"
}
Packaging a module for S3 requires creating a zip archive of the module. The archive must contain the .tf files that define the module. After packaging, the zip is uploaded to an S3 bucket with a version-based path, and referenced with the s3:: prefix in the module source. For teams already running on AWS, this approach requires zero additional infrastructure.
The author Nawaz Dhandala published guidance on this pattern on Feb 23 2026, noting that for alternative hosting options, see How to Call a Module from a GCS Bucket in Terraform and How to Call a Module from the Terraform Registry.
S3 Module Source URL Formats and Directory Structure
A good directory structure in S3 looks like this:
myorg-terraform-modules/
vpc/
v1.0.0.zip
v1.1.0.zip
v2.0.0.zip
ecs-service/
v1.0.0.zip
v1.0.1.zip
rds/
v1.0.0.zip
Versioned paths enable pinning to a specific module version and allow safe upgrades. Listing a bucket confirms artifact presence:
```
s3 ls s3://myorg-terraform-modules/vpc/
2026-02-23 10:00:00 12345 v1.0.0.zip
2026-02-23 11:00:00 13456 v1.1.0.zip
```
There are two URL formats you can use. The S3 URL format uses the s3:: prefix with the S3 URL:
module "vpc" {
source = "s3::https://myorg-terraform-modules.s3.amazonaws.com/vpc/v1.0.0.zip"
vpc_cidr = "10.0.0.0/16"
environment = "production"
}
The regional S3 endpoint format is used when the bucket is in a specific region:
module "vpc" {
source = "s3::https://myorg-terraform-modules.s3.us-east-1.amazonaws.com/vpc/v1.0.0.zip"
vpc_cidr = "10.0.0.0/16"
environment = "production"
}
The regional endpoint avoids redirect latency and ensures Terraform retrieves the module from the correct region.
Authentication and IAM for S3 Module Retrieval
Terraform's module installer checks for AWS credentials to authenticate with S3. Authentication is handled via the standard AWS credential chain, which allows the same IAM roles and profiles used for Terraform provider authentication to be reused for module downloads. This means organizations can enforce module access through IAM policies, bucket policies, and VPC endpoints.
S3 versioning can protect module objects from accidental overwrites or deletions. If a module zip is overwritten, versioning retains prior versions, enabling rollback to a known good module artifact. IAM handles authentication, and a simple naming convention handles versioning.
Enterprise Security Module with Checkov Compliance
An alternative module, jcalles/terraform-s3-module, is described as a comprehensive Terraform module for creating and managing AWS S3 buckets with advanced security, lifecycle management, and access control features.
The module emphasizes:
- Security First: Encryption by default, secure bucket policies, and IAM integration
- Multi-Bucket Support: Create and manage multiple S3 buckets with different configurations
- Lifecycle Management: Automated object transitions and deletion policies
- Access Control: Support for bucket policies, access points, and CORS configuration
- Consistent Naming: Integration with cloudposse/terraform-null-label for standardized resource naming
- Monitoring Ready: CloudTrail and CloudWatch integration capabilities
- Highly Configurable: Extensive customization options for different use cases
Enterprise-grade security claims include:
- Perfect Security Score: 227/227 Checkov security checks passed
- Zero Vulnerabilities: No failed security checks
- Enterprise Ready: CIS Benchmarks, PCI-DSS, HIPAA compliant
- Encryption by Default: AES256 or KMS encryption for all buckets
- Secure Access Controls: Least privilege IAM policies, no hardcoded credentials
- Automatic Cleanup: 7-day default for incomplete multipart uploads
- TLS Enforcement: Secure transport required for all operations
Validation of security compliance can be performed with:
checkov -d
This command runs Checkov against the module directory and confirms the stated security score.
Naming Consistency, Lifecycle Automation, and Monitoring
Integration with cloudposse/terraform-null-label provides consistent naming across resources. Consistent naming reduces human error in resource identification and supports automated cost allocation tagging. Lifecycle management with automated object transitions and deletion policies controls storage costs by moving data to cheaper tiers and removing obsolete data.
Access control support for bucket policies, access points, and CORS configuration enables fine-grained permission models without manual policy authoring. Monitoring readiness for CloudTrail and CloudWatch integration capabilities allows teams to observe bucket access patterns and detect anomalies.
Static Website Hosting, Encryption, and Access Controls
The getting started guide for the terraform-aws-s3-bucket module covers basic setup, common usage patterns, and essential configurations. For comprehensive feature details, see Features and Capabilities. For advanced usage scenarios, refer to Advanced Usage Patterns.
Before using this module, ensure you have the prerequisites listed in README.md130-136. The guide notes that the terraform-aws-s3-bucket module integrates with Terraform configuration and AWS, and provides a diagram illustrating that integration.
The simplest way to use the module is to create a basic S3 bucket. For a more secure configuration with versioning enabled, controlobjectownership and object_ownership parameters ensure proper object ownership controls, while versioning enables keeping multiple versions of an object.
S3 buckets are commonly used for storing logs from various AWS services. Secure your S3 bucket with encryption, access controls, and security policies. For more comprehensive security configurations, refer to Security Configurations.
Configure your S3 bucket for static website hosting. Configure lifecycle rules to automatically transition or expire objects.
You can conditionally create a bucket using the create_bucket parameter. This is useful when you need to manage bucket creation based on environment variables or other conditions.
Multi-Bucket Patterns with for_each and Wrappers
You can create multiple similar buckets in two ways: for_each meta-argument. Refer to the wrappers directory in the module repository for detailed implementation.
Using for_each allows teams to define a map of bucket configurations and instantiate them from a single module block, reducing duplication. The wrappers directory provides reference implementations for common patterns such as creating a set of buckets with shared policies and different names.
After mastering the basics, you can explore advanced usage patterns. The guide points to Features and Capabilities for comprehensive details and Advanced Usage Patterns for complex scenarios.