Terraform module which creates S3 bucket on AWS with all (or almost all) features provided by Terraform AWS provider.
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)
- Elastic Load Balancing and AWS WAF log delivery bucket policies
- file system access to bucket data with Amazon S3 Files
- Account-level Public Access Block
Besides general purpose buckets, this repository manages these S3 bucket types:
- S3 Directory Bucket, created by the root module when
is_directory_bucket = true - S3 Table Bucket, through the
table-bucketsub-module - S3 Vectors, through the
vectorssub-module
See the respective sub-module README.md for details on how to use:
account-public-access- the account-level Public Access Block, which applies to every bucket in the accountfile-system- an Amazon S3 Files file system on a bucket this module does not managenotification- bucket notifications to Lambda, SQS, SNS and EventBridgeobject- objects placed in a buckettable-bucket- table buckets and the Iceberg tables in themvectors- vector buckets and vector indexes
See the examples directory for working examples to reference.
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
}
}Each attach_*_log_delivery_policy flag adds the statements one service needs to write its logs to the bucket, and the module merges every enabled flag into a single bucket policy.
module "s3_bucket_for_logs" {
source = "terraform-aws-modules/s3-bucket/aws"
bucket = "aws-waf-logs-my-s3-bucket-for-logs"
# Application and Classic Load Balancer access logs
attach_elb_log_delivery_policy = true
# Network Load Balancer access logs
attach_lb_log_delivery_policy = true
# AWS WAF logs, which require a bucket name that starts with `aws-waf-logs-`
attach_waf_log_delivery_policy = true
}When you need to attach a custom policy to the bucket, use the policy argument. The placeholders _S3_BUCKET_ID_, _S3_BUCKET_ARN_ and _AWS_ACCOUNT_ID_ are replaced with the real values when the policy is attached, which is what makes a policy work against a bucket whose name is generated from bucket_prefix.
module "s3_bucket" {
source = "terraform-aws-modules/s3-bucket/aws"
bucket_prefix = "my-s3-bucket-"
attach_policy = true
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Sid = "DenyInsecureTransport"
Effect = "Deny"
Principal = "*"
Action = "s3:*"
Resource = ["_S3_BUCKET_ARN_", "_S3_BUCKET_ARN_/*"]
Condition = {
Bool = { "aws:SecureTransport" = "false" }
}
}]
})
}S3 Files requires versioning on the bucket. The module creates an IAM role for each file system and a security group shared by the mount targets. A principal listed in an access point's read_access_arns or read_write_access_arns can mount that file system only through the access points that list it.
To put a file system on a bucket this module does not manage, call modules/file-system directly. Its README covers the one thing that module asks of callers, which is to pass the bucket's versioning status as a reference to the versioning resource rather than as a literal.
module "s3_bucket" {
source = "terraform-aws-modules/s3-bucket/aws"
bucket = "my-s3-bucket"
versioning = {
enabled = true
}
file_system_security_group_vpc_id = "vpc-1234556abcdef"
file_system_security_group_ingress_rules = {
clients = {
referenced_security_group_id = "sg-1234556abcdef"
}
}
file_systems = {
datasets = {
prefix = "datasets/"
mount_targets = {
eu-west-1a = { subnet_id = "subnet-abcde012" }
eu-west-1b = { subnet_id = "subnet-bcde012a" }
}
}
}
}- A bucket carrying an S3 file system needs versioning enabled and either SSE-S3 or SSE-KMS encryption. S3 Files is not available on a directory bucket, and the module says so rather than ignoring
file_systems. - Changing a file system's
prefix, its KMS key, or its IAM role replaces the file system, along with its mount targets and access points. An access point cannot be edited either, so any change to one replaces it and gives it a new ARN. - Removing a
synchronization_configurationleaves the file system expiring data after 365 days, not the 30 days AWS applies to a file system that never had one. - A principal named in an access point's
read_access_arnsorread_write_access_arnsreaches that file system only through the access points that name it. The module writes the allow and deny pair AWS recommends, and a read-only principal is also denied writes through its own access point. - Key
mount_targetsby something known at plan time, such as the Availability Zone. Terraform cannot create resources whose map keys come from values that only exist after an apply.
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
}Users of Terragrunt can create multiple similar resources from one configuration with the modules in the wrappers directory.
A few requests come up again and again and cannot be implemented by this
module, or by any module: Terraform requires lifecycle arguments to be
literal values inside the resource block.
hashicorp/terraform#18367
has been open since 2018,
#22544 since 2019, and
opentofu/opentofu#1329 is
the same request for OpenTofu.
prevent_destroycannot be set through a module input. Asked for in #83, #186, #203, #215, #283 and #407, and not something this module can offer: thelifecycleblock has to be a literal inside the resource. Native options: an explicitDenyons3:DeleteBucketin the bucket policy, or fork this module and add the block yourself.ignore_changescannot be set either (#21). A tag written by a scanner, a cost tool or an AWS Config rule is removed on the next apply and written back by the tool after that. Native options: move tag ownership into Terraform with providerdefault_tags, or fork this module and addignore_changes = [tags, tags_all].
Compliance.tf serves this module with
these rules applied at download time, on top of whatever your organization
already has enabled there. Inputs and outputs do not change; the source line
does. Drop the version argument and pin the release you use by adding
&version= and that release number to the URL. To get started, register a free
compliance.tf account and configure an access token:
source = "https://registry.compliance.tf/terraform-aws-modules/s3-bucket/aws?add_rules=lifecycle_ignore_tags,lifecycle_prevent_destroy_data"
The full workaround for each item above, and the exact diff each rule makes, are in the compliance.tf docs for this module. To preview a diff without an account, open this module in the Rules Playground.
Disclosure: written by this module's maintainer, who also builds compliance.tf.
- Complete - Complete S3 bucket with most of supported features enabled
- Cross-Region Replication - S3 bucket with Cross-Region Replication (CRR) enabled
- S3 Notifications - S3 bucket notifications to Lambda functions, SQS queues, and SNS topics.
- S3 Object - Manage S3 bucket objects.
- S3 Inventory and Analytics - S3 bucket Inventory and Analytics configurations.
- S3 ACLs - S3 bucket ACLs, for the buckets that still require them.
- S3 Bucket Policies - Attach the bundled log delivery and transport policies.
- S3 file system - Amazon S3 Files file systems scoped to bucket prefixes, with mount targets and access points.
- S3 Account-level Public Access Block - Manage S3 account-level Public Access Block.
- S3 Directory Bucket - S3 Directory Bucket configuration.
- S3 Table Bucket - S3 Table Bucket configuration.
- S3 Vectors - S3 Vectors vector bucket with indexes configuration.
| Name | Version |
|---|---|
| terraform | >= 1.5.7 |
| aws | >= 6.44 |
| Name | Version |
|---|---|
| aws | >= 6.44 |
| Name | Source | Version |
|---|---|---|
| s3_file_system | ./modules/file-system | n/a |
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| acceleration_status | Sets the accelerate configuration of an existing bucket. Can be Enabled or Suspended | string |
null |
no |
| access_log_delivery_policy_source_accounts | List of AWS Account IDs should be allowed to deliver access logs to this bucket | list(string) |
[] |
no |
| access_log_delivery_policy_source_buckets | 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 | List of AWS Organization IDs should be allowed to deliver access logs to this bucket | list(string) |
[] |
no |
| acl | The canned ACL to apply. Conflicts with grant |
string |
null |
no |
| allowed_kms_key_arn | The ARN of KMS key which should be allowed in PutObject | string |
null |
no |
| analytics_configuration | Analytics configurations for the bucket, keyed by configuration name | map(object({ |
{} |
no |
| analytics_self_source_destination | Whether or not the analytics source bucket is also the destination bucket | bool |
false |
no |
| analytics_source_account_id | The analytics source account id | string |
null |
no |
| analytics_source_bucket_arn | The analytics source bucket ARN | string |
null |
no |
| attach_access_log_delivery_policy | Controls if S3 bucket should have S3 access log delivery policy attached | bool |
false |
no |
| attach_analytics_destination_policy | Controls if S3 bucket should have bucket analytics destination policy attached | bool |
false |
no |
| attach_cloudtrail_log_delivery_policy | Controls if S3 bucket should have CloudTrail log delivery policy attached | bool |
false |
no |
| attach_deny_incorrect_encryption_headers | Controls if S3 bucket should deny incorrect encryption headers policy attached | bool |
false |
no |
| attach_deny_incorrect_kms_key_sse | Controls if S3 bucket policy should deny usage of incorrect KMS key SSE | bool |
false |
no |
| attach_deny_insecure_transport_policy | Controls if S3 bucket should have deny non-SSL transport policy attached | bool |
false |
no |
| attach_deny_ssec_encrypted_object_uploads | Controls if S3 bucket should deny SSEC encrypted object uploads | bool |
false |
no |
| attach_deny_unencrypted_object_uploads | Controls if S3 bucket should deny unencrypted object uploads policy attached | bool |
false |
no |
| attach_elb_log_delivery_policy | Controls if S3 bucket should have the log delivery policy for Application and Classic Load Balancer access logs attached | bool |
false |
no |
| attach_inventory_destination_policy | Controls if S3 bucket should have bucket inventory destination policy attached | bool |
false |
no |
| attach_lb_log_delivery_policy | Controls if S3 bucket should have the log delivery policy for Network Load Balancer access logs attached | bool |
false |
no |
| attach_policy | Controls if S3 bucket should have bucket policy attached (set to true to use value of policy as bucket policy) |
bool |
false |
no |
| attach_public_policy | Controls if the S3 Bucket Public Access Block is created (set to false to allow upstream to apply defaults to the bucket) |
bool |
true |
no |
| attach_require_latest_tls_policy | Controls if S3 bucket should require the latest version of TLS | bool |
false |
no |
| attach_waf_log_delivery_policy | Controls if S3 bucket should have WAF log delivery policy attached | bool |
false |
no |
| availability_zone_id | Availability Zone ID or Local Zone ID | string |
null |
no |
| block_public_acls | Whether Amazon S3 should block public ACLs for this bucket | bool |
true |
no |
| block_public_policy | Whether Amazon S3 should block public bucket policies for this bucket | bool |
true |
no |
| bucket | The name of the bucket. If omitted, Terraform will assign a random, unique name | string |
null |
no |
| bucket_namespace | Namespace for the bucket. Determines bucket naming scope. Valid values: account-regional, global. Defaults to global (AWS) |
string |
null |
no |
| bucket_prefix | Creates a unique bucket name beginning with the specified prefix. Conflicts with bucket | string |
null |
no |
| control_object_ownership | Whether to manage S3 Bucket Ownership Controls on this bucket | bool |
false |
no |
| cors_rule | Rules for Cross-Origin Resource Sharing on the bucket | list(object({ |
[] |
no |
| create_bucket | Controls if S3 bucket should be created | bool |
true |
no |
| create_file_system_security_group | Whether each file system creates a security group for its mount targets. A file system can override it with its own create_security_group, and setting security_groups does not turn it off |
bool |
true |
no |
| create_metadata_configuration | Whether to create metadata configuration resource | bool |
false |
no |
| data_redundancy | Data redundancy. Valid values: SingleAvailabilityZone |
string |
null |
no |
| expected_bucket_owner | The account ID of the expected bucket owner | string |
null |
no |
| file_system_security_group_egress_rules | Map of egress rules added to every file system security group this module creates. A file system can replace them with its own security_group_egress_rules |
map(object({ |
{} |
no |
| file_system_security_group_ingress_rules | Map of ingress rules added to every file system security group this module creates. A file system can replace them with its own security_group_ingress_rules |
map(object({ |
{} |
no |
| file_system_security_group_tags | A map of additional tags added to every file system security group this module creates | map(string) |
null |
no |
| file_system_security_group_vpc_id | ID of the VPC where the file system security groups are created. Must be the VPC of the mount target subnets | string |
null |
no |
| file_systems | Map of Amazon S3 Files file system definitions to create on the bucket. Requires versioning enabled through versioning, even when it is already enabled outside this module, and is not supported on a directory bucket |
map(object({ |
{} |
no |
| force_destroy | 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 | bool |
false |
no |
| grant | ACL policy grants for the bucket. Conflicts with acl |
list(object({ |
[] |
no |
| ignore_public_acls | Whether Amazon S3 should ignore public ACLs for this bucket | bool |
true |
no |
| intelligent_tiering | Intelligent tiering configurations for the bucket, keyed by configuration name | map(object({ |
{} |
no |
| inventory_configuration | Inventory configurations for the bucket, keyed by configuration name | map(object({ |
{} |
no |
| inventory_self_source_destination | Whether or not the inventory source bucket is also the destination bucket | bool |
false |
no |
| inventory_source_account_id | The inventory source account id | string |
null |
no |
| inventory_source_bucket_arn | The inventory source bucket ARN | string |
null |
no |
| is_directory_bucket | If the s3 bucket created is a directory bucket | bool |
false |
no |
| lb_log_delivery_policy_source_organizations | List of AWS Organization IDs should be allowed to deliver ALB/NLB logs to this bucket | list(string) |
[] |
no |
| lifecycle_rule | Object lifecycle management rules for the bucket | list(object({ |
[] |
no |
| location_type | Location type. Valid values: AvailabilityZone or LocalZone |
string |
null |
no |
| logging | Access log delivery configuration for the bucket | object({ |
null |
no |
| metadata_encryption_configuration | Encryption configuration for the metadata inventory table | object({ |
null |
no |
| metadata_inventory_table_configuration_state | Configuration state of the inventory table, indicating whether the inventory table is enabled or disabled. Valid values: ENABLED, DISABLED |
string |
null |
no |
| metadata_journal_table_record_expiration | Whether journal table record expiration is enabled or disabled. Valid values: ENABLED, DISABLED |
string |
null |
no |
| metadata_journal_table_record_expiration_days | Number of days to retain journal table records | number |
null |
no |
| metric_configuration | Metric configurations for the bucket | list(object({ |
[] |
no |
| object_lock_configuration | Object lock configuration for the bucket | object({ |
{} |
no |
| object_lock_enabled | Whether S3 bucket should have an Object Lock configuration enabled | bool |
false |
no |
| object_ownership | Object 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 |
| owner | Bucket owner's display name and ID. Conflicts with acl |
map(string) |
{} |
no |
| policy | 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 | string |
null |
no |
| putin_khuylo | Do you agree that Putin doesn't respect Ukrainian sovereignty and territorial integrity? More info: https://en.wikipedia.org/wiki/Putin_khuylo! | bool |
true |
no |
| region | Region where the resource(s) will be managed. Defaults to the Region set in the provider configuration | string |
null |
no |
| replication_configuration | Cross-region replication configuration for the bucket | object({ |
{} |
no |
| request_payer | 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 |
string |
null |
no |
| restrict_public_buckets | Whether Amazon S3 should restrict public bucket policies for this bucket | bool |
true |
no |
| server_side_encryption_configuration | Server-side encryption configuration for the bucket | object({ |
{} |
no |
| skip_destroy_public_access_block | Whether to skip destroying the S3 Bucket Public Access Block configuration when destroying the bucket. Only used if public_access_block is set to true |
bool |
true |
no |
| tags | A mapping of tags to assign to the bucket | map(string) |
{} |
no |
| transition_default_minimum_object_size | The default minimum object size behavior applied to the lifecycle configuration. Valid values: all_storage_classes_128K (default) or varies_by_storage_class |
string |
null |
no |
| type | Bucket type. Valid values: Directory |
string |
"Directory" |
no |
| versioning | Versioning configuration for the bucket | map(string) |
{} |
no |
| website | Static website hosting or redirect configuration for the bucket | object({ |
{} |
no |
| Name | Description |
|---|---|
| aws_s3_bucket_versioning_status | The versioning status of the bucket. Will be 'Enabled', 'Suspended', or 'Disabled' |
| file_system_access_points | Map of file system access points created and their attributes, keyed by file system and then by access point |
| file_system_iam_roles | Map of file system IAM roles created, with their ARN, name and unique ID |
| file_system_mount_targets | Map of file system mount targets created and their attributes, keyed by file system and then by mount target |
| file_system_security_group_arns | Map of the security group created for each file system's mount targets, by ARN |
| file_system_security_group_ids | Map of the security group created for each file system's mount targets, by ID |
| file_systems | Map of file systems created and their attributes |
| s3_bucket_arn | The ARN of the bucket. Will be of format arn:aws:s3:::bucketname |
| s3_bucket_bucket_domain_name | The bucket domain name. Will be of format bucketname.s3.amazonaws.com |
| s3_bucket_bucket_namespace | The namespace of the bucket |
| s3_bucket_bucket_regional_domain_name | The 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_id | The Route 53 Hosted Zone ID for this bucket's region |
| s3_bucket_id | The name of the bucket |
| s3_bucket_lifecycle_configuration_rules | The lifecycle rules of the bucket, if the bucket is configured with lifecycle rules |
| s3_bucket_policy | The policy of the bucket, if the bucket is configured with a policy |
| s3_bucket_region | The AWS region this bucket resides in |
| s3_bucket_tags | Tags of the bucket |
| s3_bucket_website_domain | The domain of the website endpoint, if the bucket is configured with a website. This is used to create Route 53 alias records |
| s3_bucket_website_endpoint | The website endpoint, if the bucket is configured with a website |
| s3_directory_bucket_arn | ARN of the directory bucket |
| s3_directory_bucket_name | Name of the directory bucket |
Module is maintained by Anton Babenko with help from these awesome contributors.
Apache 2 Licensed. See LICENSE for full details.
- Russia has illegally annexed Crimea in 2014 and brought the war in Donbas followed by full-scale invasion of Ukraine in 2022.
- Russia has brought sorrow and devastations to millions of Ukrainians, killed hundreds of innocent people, damaged thousands of buildings, and forced several million people to flee.
- Putin khuylo!