AWS S3 bucket Terraform module

May 29, 2026 ยท View on GitHub

Terraform module which creates S3 bucket on AWS with all (or almost all) features provided by Terraform AWS provider.

SWUbanner

These features of S3 bucket configurations are supported:

  • 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

Usage

Private bucket with versioning enabled

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
  }
}

Bucket with ELB access log delivery policy attached

module "s3_bucket_for_logs" {
  source = "terraform-aws-modules/s3-bucket/aws"

  bucket = "my-s3-bucket-for-logs"
  acl    = "log-delivery-write"

  # Allow deletion of non-empty bucket
  force_destroy = true

  control_object_ownership = true
  object_ownership         = "ObjectWriter"

  attach_elb_log_delivery_policy = true
}

Bucket with ALB/NLB access log delivery policy attached

module "s3_bucket_for_logs" {
  source = "terraform-aws-modules/s3-bucket/aws"

  bucket = "my-s3-bucket-for-logs"

  # Allow deletion of non-empty bucket
  force_destroy = true

  control_object_ownership = true
  object_ownership         = "ObjectWriter"

  attach_elb_log_delivery_policy = true  # Required for ALB logs
  attach_lb_log_delivery_policy  = true  # Required for ALB/NLB logs
}

Bucket with WAF log delivery policy attached

module "s3_bucket_for_waf_logs" {
  source = "terraform-aws-modules/s3-bucket/aws"

  bucket = "my-s3-bucket-for-waf-logs"

  # Allow deletion of non-empty bucket
  force_destroy = true

  control_object_ownership = true
  object_ownership         = "ObjectWriter"

  attach_waf_log_delivery_policy = true  # Required for WAF logs
}

Bucket with a custom policy attached

When you need to attach a custom policy to the bucket, you can use the policy argument. To keep bucket policy with correct S3 bucket and AWS account properties, you can use the placeholders _S3_BUCKET_ID_, _S3_BUCKET_ARN_, and _AWS_ACCOUNT_ID_ in the policy document. Those values will be replaced with the actual values during the policy attachment. This is especially useful when using bucket prefixes.

Conditional creation

Sometimes you need to have a way to create S3 resources conditionally but Terraform does not allow to use count inside module block, so the solution is to specify argument create_bucket.

# This S3 bucket will not be created
module "s3_bucket" {
  source = "terraform-aws-modules/s3-bucket/aws"

  create_bucket = false
  # ... omitted
}

Terragrunt and variable "..." { type = any }

There is a bug #1211 in Terragrunt related to the way how the variables of type any are passed to Terraform.

This module solves this issue by supporting jsonencode()-string in addition to the expected type (list or map).

In terragrunt.hcl you can write:

inputs = {
  bucket    = "foobar"            # `bucket` has type `string`, no need to jsonencode()
  cors_rule = jsonencode([...])   # `cors_rule` has type `any`, so `jsonencode()` is required
}

Module wrappers

Users of this Terraform module can create multiple similar resources by using for_each meta-argument within module block which became available in Terraform 0.13.

Users of Terragrunt can achieve similar results by using modules provided in the wrappers directory, if they prefer to reduce amount of configuration files.

Examples:

Requirements

NameVersion
terraform>= 1.5.7
aws>= 6.42

Providers

NameVersion
aws>= 6.42

Modules

No modules.

Resources

NameType
aws_s3_bucket.thisresource
aws_s3_bucket_accelerate_configuration.thisresource
aws_s3_bucket_acl.thisresource
aws_s3_bucket_analytics_configuration.thisresource
aws_s3_bucket_cors_configuration.thisresource
aws_s3_bucket_intelligent_tiering_configuration.thisresource
aws_s3_bucket_inventory.thisresource
aws_s3_bucket_lifecycle_configuration.thisresource
aws_s3_bucket_logging.thisresource
aws_s3_bucket_metadata_configuration.thisresource
aws_s3_bucket_metric.thisresource
aws_s3_bucket_object_lock_configuration.thisresource
aws_s3_bucket_ownership_controls.thisresource
aws_s3_bucket_policy.thisresource
aws_s3_bucket_public_access_block.thisresource
aws_s3_bucket_replication_configuration.thisresource
aws_s3_bucket_request_payment_configuration.thisresource
aws_s3_bucket_server_side_encryption_configuration.thisresource
aws_s3_bucket_versioning.thisresource
aws_s3_bucket_website_configuration.thisresource
aws_s3_directory_bucket.thisresource
aws_caller_identity.currentdata source
aws_canonical_user_id.thisdata source
aws_iam_policy_document.access_log_deliverydata source
aws_iam_policy_document.cloudtrail_log_deliverydata source
aws_iam_policy_document.combineddata source
aws_iam_policy_document.deny_incorrect_encryption_headersdata source
aws_iam_policy_document.deny_incorrect_kms_key_ssedata source
aws_iam_policy_document.deny_insecure_transportdata source
aws_iam_policy_document.deny_ssec_encrypted_object_uploadsdata source
aws_iam_policy_document.deny_unencrypted_object_uploadsdata source
aws_iam_policy_document.elb_log_deliverydata source
aws_iam_policy_document.inventory_and_analytics_destination_policydata source
aws_iam_policy_document.lb_log_deliverydata source
aws_iam_policy_document.require_latest_tlsdata source
aws_iam_policy_document.waf_log_deliverydata source
aws_partition.currentdata source
aws_region.currentdata source

Inputs

NameDescriptionTypeDefaultRequired
acceleration_status(Optional) Sets the accelerate configuration of an existing bucket. Can be Enabled or Suspended.stringnullno
access_log_delivery_policy_source_accounts(Optional) List of AWS Account IDs should be allowed to deliver access logs to this bucket.list(string)[]no
access_log_delivery_policy_source_buckets(Optional) List of S3 bucket ARNs which should be allowed to deliver access logs to this bucket.list(string)[]no
access_log_delivery_policy_source_organizations(Optional) List of AWS Organization IDs should be allowed to deliver access logs to this bucket.list(string)[]no
acl(Optional) The canned ACL to apply. Conflicts with grantstringnullno
allowed_kms_key_arnThe ARN of KMS key which should be allowed in PutObjectstringnullno
analytics_configurationMap containing bucket analytics configuration.any{}no
analytics_self_source_destinationWhether or not the analytics source bucket is also the destination bucket.boolfalseno
analytics_source_account_idThe analytics source account id.stringnullno
analytics_source_bucket_arnThe analytics source bucket ARN.stringnullno
attach_access_log_delivery_policyControls if S3 bucket should have S3 access log delivery policy attachedboolfalseno
attach_analytics_destination_policyControls if S3 bucket should have bucket analytics destination policy attached.boolfalseno
attach_cloudtrail_log_delivery_policyControls if S3 bucket should have CloudTrail log delivery policy attachedboolfalseno
attach_deny_incorrect_encryption_headersControls if S3 bucket should deny incorrect encryption headers policy attached.boolfalseno
attach_deny_incorrect_kms_key_sseControls if S3 bucket policy should deny usage of incorrect KMS key SSE.boolfalseno
attach_deny_insecure_transport_policyControls if S3 bucket should have deny non-SSL transport policy attachedboolfalseno
attach_deny_ssec_encrypted_object_uploadsControls if S3 bucket should deny SSEC encrypted object uploads.boolfalseno
attach_deny_unencrypted_object_uploadsControls if S3 bucket should deny unencrypted object uploads policy attached.boolfalseno
attach_elb_log_delivery_policyControls if S3 bucket should have ELB log delivery policy attachedboolfalseno
attach_inventory_destination_policyControls if S3 bucket should have bucket inventory destination policy attached.boolfalseno
attach_lb_log_delivery_policyControls if S3 bucket should have ALB/NLB log delivery policy attachedboolfalseno
attach_policyControls if S3 bucket should have bucket policy attached (set to true to use value of policy as bucket policy)boolfalseno
attach_public_policyControls if a user defined public bucket policy will be attached (set to false to allow upstream to apply defaults to the bucket)booltrueno
attach_require_latest_tls_policyControls if S3 bucket should require the latest version of TLSboolfalseno
attach_waf_log_delivery_policyControls if S3 bucket should have WAF log delivery policy attachedboolfalseno
availability_zone_idAvailability Zone ID or Local Zone IDstringnullno
block_public_aclsWhether Amazon S3 should block public ACLs for this bucket.booltrueno
block_public_policyWhether Amazon S3 should block public bucket policies for this bucket.booltrueno
bucket(Optional, Forces new resource) The name of the bucket. If omitted, Terraform will assign a random, unique name.stringnullno
bucket_namespaceNamespace for the bucket. Determines bucket naming scope. Valid values: account-regional, global. Defaults to global (AWS)stringnullno
bucket_prefix(Optional, Forces new resource) Creates a unique bucket name beginning with the specified prefix. Conflicts with bucket.stringnullno
control_object_ownershipWhether to manage S3 Bucket Ownership Controls on this bucket.boolfalseno
cors_ruleList of maps containing rules for Cross-Origin Resource Sharing.any[]no
create_bucketControls if S3 bucket should be createdbooltrueno
create_metadata_configurationWhether to create metadata configuration resourceboolfalseno
data_redundancyData redundancy. Valid values: SingleAvailabilityZonestringnullno
expected_bucket_ownerThe account ID of the expected bucket ownerstringnullno
force_destroy(Optional, Default:false ) 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.boolfalseno
grantAn ACL policy grant. Conflicts with aclany[]no
ignore_public_aclsWhether Amazon S3 should ignore public ACLs for this bucket.booltrueno
intelligent_tieringMap containing intelligent tiering configuration.any{}no
inventory_configurationMap containing S3 inventory configuration.any{}no
inventory_self_source_destinationWhether or not the inventory source bucket is also the destination bucket.boolfalseno
inventory_source_account_idThe inventory source account id.stringnullno
inventory_source_bucket_arnThe inventory source bucket ARN.stringnullno
is_directory_bucketIf the s3 bucket created is a directory bucketboolfalseno
lb_log_delivery_policy_source_organizations(Optional) List of AWS Organization IDs should be allowed to deliver ALB/NLB logs to this bucket.list(string)[]no
lifecycle_ruleList of maps containing configuration of object lifecycle management.any[]no
location_typeLocation type. Valid values: AvailabilityZone or LocalZonestringnullno
loggingMap containing access bucket logging configuration.any{}no
metadata_encryption_configurationEncryption configuration blockanynullno
metadata_inventory_table_configuration_stateConfiguration state of the inventory table, indicating whether the inventory table is enabled or disabled. Valid values: ENABLED, DISABLEDstringnullno
metadata_journal_table_record_expirationWhether journal table record expiration is enabled or disabled. Valid values: ENABLED, DISABLEDstringnullno
metadata_journal_table_record_expiration_daysNumber of days to retain journal table recordsnumbernullno
metric_configurationMap containing bucket metric configuration.any[]no
object_lock_configurationMap containing S3 object locking configuration.any{}no
object_lock_enabledWhether S3 bucket should have an Object Lock configuration enabled.boolfalseno
object_ownershipObject ownership. Valid values: BucketOwnerEnforced, BucketOwnerPreferred or ObjectWriter. 'BucketOwnerEnforced': ACLs are disabled, and the bucket owner automatically owns and has full control over every object in the bucket. 'BucketOwnerPreferred': Objects uploaded to the bucket change ownership to the bucket owner if the objects are uploaded with the bucket-owner-full-control canned ACL. 'ObjectWriter': The uploading account will own the object if the object is uploaded with the bucket-owner-full-control canned ACL.string"BucketOwnerEnforced"no
ownerBucket owner's display name and ID. Conflicts with aclmap(string){}no
policy(Optional) A valid bucket policy JSON document. Note that if the policy document is not specific enough (but still valid), Terraform may view the policy as constantly changing in a terraform plan. In this case, please make sure you use the verbose/specific version of the policy. For more information about building AWS IAM policy documents with Terraform, see the AWS IAM Policy Document Guide.stringnullno
putin_khuyloDo you agree that Putin doesn't respect Ukrainian sovereignty and territorial integrity? More info: https://en.wikipedia.org/wiki/Putin_khuylo!booltrueno
regionRegion where the resource(s) will be managed. Defaults to the region set in the provider configurationstringnullno
replication_configurationMap containing cross-region replication configuration.any{}no
request_payer(Optional) Specifies who should bear the cost of Amazon S3 data transfer. Can be either BucketOwner or Requester. By default, the owner of the S3 bucket would incur the costs of any data transfer. See Requester Pays Buckets developer guide for more information.stringnullno
restrict_public_bucketsWhether Amazon S3 should restrict public bucket policies for this bucket.booltrueno
server_side_encryption_configurationMap containing server-side encryption configuration.any{}no
skip_destroy_public_access_blockWhether to skip destroying the S3 Bucket Public Access Block configuration when destroying the bucket. Only used if public_access_block is set to true.booltrueno
tags(Optional) A mapping of tags to assign to the bucket.map(string){}no
transition_default_minimum_object_sizeThe default minimum object size behavior applied to the lifecycle configuration. Valid values: all_storage_classes_128K (default), varies_by_storage_classstringnullno
typeBucket type. Valid values: Directorystring"Directory"no
versioningMap containing versioning configuration.map(string){}no
websiteMap containing static web-site hosting or redirect configuration.any{}no

Outputs

NameDescription
aws_s3_bucket_versioning_statusThe versioning status of the bucket. Will be 'Enabled', 'Suspended', or 'Disabled'.
s3_bucket_arnThe ARN of the bucket. Will be of format arn:aws:s3:::bucketname.
s3_bucket_bucket_domain_nameThe bucket domain name. Will be of format bucketname.s3.amazonaws.com.
s3_bucket_bucket_regional_domain_nameThe bucket region-specific domain name. The bucket domain name including the region name, please refer here for format. Note: The AWS CloudFront allows specifying S3 region-specific endpoint when creating S3 origin, it will prevent redirect issues from CloudFront to S3 Origin URL.
s3_bucket_hosted_zone_idThe Route 53 Hosted Zone ID for this bucket's region.
s3_bucket_idThe name of the bucket.
s3_bucket_lifecycle_configuration_rulesThe lifecycle rules of the bucket, if the bucket is configured with lifecycle rules. If not, this will be an empty string.
s3_bucket_policyThe policy of the bucket, if the bucket is configured with a policy. If not, this will be an empty string.
s3_bucket_regionThe AWS region this bucket resides in.
s3_bucket_tagsTags of the bucket.
s3_bucket_website_domainThe domain of the website endpoint, if the bucket is configured with a website. If not, this will be an empty string. This is used to create Route 53 alias records.
s3_bucket_website_endpointThe website endpoint, if the bucket is configured with a website. If not, this will be an empty string.
s3_directory_bucket_arnARN of the directory bucket.
s3_directory_bucket_nameName of the directory bucket.

Authors

Module is maintained by Anton Babenko with help from these awesome contributors.

License

Apache 2 Licensed. See LICENSE for full details.

Additional information for users from Russia and Belarus