Terraform module for creating production-oriented Amazon S3 resources. The module is implemented directly with HashiCorp AWS provider resources and does not wrap another S3 module.
The module supports:
- General purpose S3 buckets, including global and account-regional namespaces, and S3 Express One Zone directory buckets
- AES256, AWS KMS, and dual-layer AWS KMS server-side encryption, with optional SSE-C upload blocking
- Public access blocking, object ownership controls, optional ACLs, bucket policies, and bucket ABAC
- Versioning, Object Lock default retention, lifecycle rules, server access logging, and replication
- Intelligent-Tiering, Inventory, Analytics, request metrics, and S3 Metadata tables
- CORS, EventBridge, Lambda, SNS, and SQS notifications
- Static website configuration and redirects
- Public or VPC-scoped S3 access points
The root module does not create KMS keys, IAM roles, notification destinations, destination buckets, VPCs, or provider configuration. Callers supply those dependencies when enabling the related capability.
module "artifacts" {
source = "native-cube/s3/aws"
version = "~> 1.0"
bucket_name = "acme-production-artifacts"
versioning = "Enabled"
sse_algorithm = "aws:kms"
kms_key_id = var.artifacts_kms_key_arn
enable_bucket_key = true
lifecycle_rules = [{
id = "archive"
status = "Enabled"
filter = {
prefix = "releases/"
}
transition = [{
days = 30
storage_class = "STANDARD_IA"
}]
noncurrent_version_expiration = {
noncurrent_days = 90
}
}]
tags = {
Environment = "production"
Service = "artifacts"
}
}Version 1.x requires Terraform 1.5 or newer and HashiCorp AWS provider 6.61 or newer within major version 6. The minimum and latest supported combinations are exercised separately in CI.
This module follows semantic versioning. Pin a compatible module version in production and review CHANGELOG.md before upgrading. Major releases may contain breaking changes; minor and patch releases preserve the documented 1.x interface.
- Server-side encryption is always configured for a general purpose bucket. AES256 is the default; select
aws:kmsoraws:kms:dsseto use an optional caller-managed KMS key. - All four public-access-block settings default to
true, ownership defaults toBucketOwnerEnforced, and ACL management is disabled. To use an ACL, explicitly enable it, select compatible object ownership, and provide exactly one canned or detailed ACL. force_destroydefaults tofalse. Enabling it allows Terraform to delete bucket contents during destroy, and those objects are not recoverable; Object Lock retention can still prevent deletion.- Bucket policy JSON is validated syntactically, but callers remain responsible for least-privilege statements and correct principals, resources, and conditions.
- Set
blocked_encryption_types = ["SSE-C"]to reject uploads encrypted with customer-provided keys while retaining the module's configured bucket-default encryption. - Object Lock must be enabled when the bucket is created. Setting
object_lock_configurationenables it automatically and supportsGOVERNANCEorCOMPLIANCEdefault retention in days or years. Per-object retention and legal holds remain caller responsibilities.
- Lifecycle rules support prefix, single-tag, multi-tag, and object-size filters; incomplete multipart upload cleanup; current-object transitions and expiration; and noncurrent-version transitions and expiration.
- Intelligent-Tiering, Inventory, Analytics, and request metrics use maps keyed by stable configuration names, so individual configurations have stable Terraform addresses.
- Inventory and Analytics destination buckets and their policies are caller managed. S3 Metadata availability, account prerequisites, and supported Regions should be confirmed before enabling
metadata_configuration. abac_status = "Enabled"enables bucket attribute-based access control. Review existing IAM policies before adopting tag-based authorization.
- Replication, including existing-object replication, requires
versioning = "Enabled", an existing destination bucket with versioning enabled, and an IAM role that Amazon S3 can assume. - Notification destination policies and Lambda invoke permissions are intentionally managed by callers. Configure them before applying the bucket notification resource.
- Access points inherit the module tags, block public access by default, can target the module's general purpose or directory bucket, and can optionally be restricted to an existing VPC.
- Website configuration does not make a bucket public. Prefer CloudFront with origin access control, or deliberately configure a tightly scoped bucket policy if direct S3 website access is required.
- Server access logging defaults to
logs/<source-bucket-name>/in the caller-supplied logging bucket. The prefix and simple or date-partitioned object-key format are configurable; the destination bucket must permit S3 log delivery.
Set create_bucket = false and create_directory_bucket = true for directory-only mode. Supply a location-specific directory_bucket_name, the matching Availability Zone or Local Zone ID in location_name, and the appropriate location_type. General purpose bucket features such as policies, lifecycle rules, notifications, and website hosting do not apply to directory buckets through this interface.
examples/s3-bucket- encrypted, versioned general purpose bucket.examples/s3-website- static website configuration with public access still blocked.examples/s3-cors- browser upload and download CORS rule.examples/s3-notification- EventBridge, Lambda, SNS, and SQS notifications.examples/s3-access-point- VPC-scoped S3 access point.examples/s3-directory-bucket- S3 Express One Zone directory bucket.examples/s3-replication- versioned replication source bucket.examples/s3-advanced- Object Lock, lifecycle cleanup, logging, data-management configurations, ABAC, and S3 Metadata.
Run make check to verify formatting, generated documentation, initialization, native Terraform tests, and every example. Run make docs after changing inputs, outputs, resources, or version constraints. make release-check additionally requires TFLint and Trivy and runs the complete pre-release gate. See RELEASING.md for the maintainer checklist.
| Name | Version |
|---|---|
| terraform | >= 1.5.0 |
| aws | >= 6.61.0, < 7.0.0 |
| Name | Version |
|---|---|
| aws | >= 6.61.0, < 7.0.0 |
| Name | Type |
|---|---|
| aws_s3_access_point.main | resource |
| aws_s3_bucket.main | resource |
| aws_s3_bucket_abac.main | resource |
| aws_s3_bucket_acl.main | resource |
| aws_s3_bucket_analytics_configuration.main | resource |
| aws_s3_bucket_cors_configuration.main | resource |
| aws_s3_bucket_intelligent_tiering_configuration.main | resource |
| aws_s3_bucket_inventory.main | resource |
| aws_s3_bucket_lifecycle_configuration.main | resource |
| aws_s3_bucket_logging.main | resource |
| aws_s3_bucket_metadata_configuration.main | resource |
| aws_s3_bucket_metric.main | resource |
| aws_s3_bucket_notification.main | resource |
| aws_s3_bucket_object_lock_configuration.main | resource |
| aws_s3_bucket_ownership_controls.main | resource |
| aws_s3_bucket_policy.main | resource |
| aws_s3_bucket_public_access_block.main | resource |
| aws_s3_bucket_replication_configuration.main | resource |
| aws_s3_bucket_server_side_encryption_configuration.main | resource |
| aws_s3_bucket_versioning.main | resource |
| aws_s3_bucket_website_configuration.main | resource |
| aws_s3_directory_bucket.main | resource |
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| abac_status | Optional attribute-based access control status for the general purpose bucket. Null leaves S3 bucket ABAC unmanaged. | string |
null |
no |
| access_control_policy | Optional detailed access control policy for the general purpose bucket. Use this instead of acl when enable_acl is true. | object({ |
null |
no |
| access_points | S3 access points to create when enable_access_points is true. Access point names must be unique and may target the module-created general purpose or directory bucket. | list(object({ |
[] |
no |
| acl | Optional canned ACL to apply when enable_acl is true. Conflicts with access_control_policy. | string |
null |
no |
| analytics_configurations | S3 Analytics configurations for the general purpose bucket, keyed by a stable configuration name. | map(object({ |
{} |
no |
| block_public_acls | Whether Amazon S3 should block public ACLs for the general purpose bucket. | bool |
true |
no |
| block_public_policy | Whether Amazon S3 should block public bucket policies for the general purpose bucket. | bool |
true |
no |
| blocked_encryption_types | Optional server-side encryption types to reject for object uploads. Set to ["SSE-C"] to block customer-provided encryption keys; null leaves the provider default. | set(string) |
null |
no |
| bucket_name | Name of the general purpose S3 bucket. When null, Amazon S3 generates a name unless bucket_prefix is selected. | string |
null |
no |
| bucket_namespace | Optional namespace for the general purpose bucket. Valid values are global and account-regional. Null uses the AWS global namespace default. | string |
null |
no |
| bucket_policy | Optional S3 bucket policy JSON document used when configure_policy is true. | string |
null |
no |
| bucket_prefix | Prefix from which Amazon S3 generates the general purpose bucket name when use_bucket_prefix is true. | string |
null |
no |
| configure_policy | Whether to attach bucket_policy to the general purpose bucket. | bool |
false |
no |
| cors_rules | Cross-Origin Resource Sharing rules for the general purpose bucket. | list(object({ |
[] |
no |
| create_bucket | Whether to create a general purpose S3 bucket. | bool |
true |
no |
| create_directory_bucket | Whether to create an S3 directory bucket in addition to any general purpose bucket. | bool |
false |
no |
| data_redundancy | Data redundancy for the directory bucket. | string |
"SingleAvailabilityZone" |
no |
| directory_bucket_name | Name of the S3 directory bucket. The name must include the location-specific suffix required by Amazon S3. | string |
null |
no |
| enable_access_points | Whether to create the access points declared in access_points. | bool |
false |
no |
| enable_acl | Whether to manage an ACL for the general purpose bucket. ACLs require an object ownership mode other than BucketOwnerEnforced. | bool |
false |
no |
| enable_bucket_key | Whether to use an S3 Bucket Key for KMS-based server-side encryption. | bool |
false |
no |
| enable_replication_configuration | Whether to configure replication for the general purpose bucket. | bool |
false |
no |
| enable_s3_notification | Whether to manage EventBridge, Lambda, SNS, and SQS notifications for the general purpose bucket. | bool |
false |
no |
| enable_website_configuration | Whether to configure static website hosting or redirection for the general purpose bucket. | bool |
false |
no |
| error_document | Object key returned for website errors. | string |
null |
no |
| eventbridge | Whether to send bucket events to Amazon EventBridge when notifications are enabled. | bool |
false |
no |
| force_destroy | Whether Terraform may delete bucket objects when destroying a bucket. Deleted objects are not recoverable, and Object Lock retention can still prevent deletion. | bool |
false |
no |
| ignore_public_acls | Whether Amazon S3 should ignore public ACLs for the general purpose bucket. | bool |
true |
no |
| index_document | Object suffix used as the website index document. | string |
null |
no |
| intelligent_tiering_configurations | S3 Intelligent-Tiering configurations for the general purpose bucket, keyed by a stable configuration name. | map(object({ |
{} |
no |
| inventory_configurations | S3 Inventory configurations for the general purpose bucket, keyed by a stable configuration name. | map(object({ |
{} |
no |
| kms_key_id | Optional KMS key ARN or ID used when sse_algorithm is aws:kms or aws:kms:dsse. | string |
null |
no |
| lambda_notifications | Lambda function notification destinations. Callers must grant Amazon S3 permission to invoke each function. | list(object({ |
[] |
no |
| lifecycle_configuration_timeouts | Optional create and update timeouts for the S3 lifecycle configuration. | object({ |
null |
no |
| lifecycle_rules | Lifecycle rules for current and noncurrent objects in the general purpose bucket. | list(object({ |
[] |
no |
| lifecycle_transition_default_minimum_object_size | Optional default minimum object-size behavior for lifecycle transitions. | string |
null |
no |
| location_name | Availability Zone ID or Local Zone ID in which to create the directory bucket. | string |
null |
no |
| location_type | Location type for the directory bucket. | string |
"AvailabilityZone" |
no |
| logging_bucket_name | Destination bucket name for S3 server access logs. | string |
null |
no |
| logging_enabled | Whether to deliver server access logs for the general purpose bucket. | bool |
false |
no |
| logging_target_object_key_format | Optional server access log object-key format. Set exactly one partitioned_prefix or simple_prefix option. Null uses the S3 default simple format. | object({ |
null |
no |
| logging_target_prefix | Optional prefix for server access log object keys. Null uses logs//. | string |
null |
no |
| metadata_configuration | Optional S3 Metadata inventory and journal table configuration for the general purpose bucket. | object({ |
null |
no |
| metric_configurations | S3 request metrics configurations for the general purpose bucket, keyed by a stable configuration name. | map(object({ |
{} |
no |
| object_lock_configuration | Optional Object Lock default retention configuration for the general purpose bucket. Requires versioning to be Enabled. | object({ |
null |
no |
| object_lock_enabled | Whether to enable S3 Object Lock on the general purpose bucket at creation time. object_lock_configuration also enables it automatically. | bool |
false |
no |
| object_ownership | Object ownership mode for the general purpose bucket. BucketOwnerEnforced disables ACLs. | string |
"BucketOwnerEnforced" |
no |
| redirect_all_requests_to | Optional website redirect target. This conflicts with index, error, and routing rule configuration. | object({ |
null |
no |
| region | Optional AWS Region in which the module manages S3 resources. Defaults to the Region configured by the caller's AWS provider. | string |
null |
no |
| replication_configuration | Replication role and rules used when enable_replication_configuration is true. | object({ |
null |
no |
| restrict_public_buckets | Whether Amazon S3 should restrict public bucket policies for the general purpose bucket. | bool |
true |
no |
| routing_rule | Structured website routing rules. Use this or routing_rules, but not both. | list(object({ |
[] |
no |
| routing_rules | JSON-encoded website routing rules. Use an empty string when unused. Conflicts with routing_rule. | string |
"" |
no |
| sns_notifications | SNS topic notification destinations. Callers must configure each topic policy to permit delivery from Amazon S3. | list(object({ |
[] |
no |
| sqs_notifications | SQS queue notification destinations. Callers must configure each queue policy to permit delivery from Amazon S3. | list(object({ |
[] |
no |
| sse_algorithm | Server-side encryption algorithm for the general purpose bucket. | string |
"AES256" |
no |
| tags | Tags to apply to all module-created buckets and access points. | map(string) |
{} |
no |
| use_bucket_prefix | Whether to generate the general purpose bucket name from bucket_prefix instead of using bucket_name. | bool |
false |
no |
| versioning | Optional versioning status for the general purpose bucket: Enabled, Suspended, or Disabled. Null leaves versioning unmanaged. | string |
null |
no |
| Name | Description |
|---|---|
| access_points | Details for access points created by the module, keyed by access point name. |
| bucket_arn | Amazon Resource Name (ARN) of the created general purpose S3 bucket, or null when creation is disabled. |
| bucket_domain_name | Bucket domain name of the created general purpose S3 bucket, or null when creation is disabled. |
| bucket_hosted_zone_id | Route 53 hosted zone ID of the created general purpose S3 bucket, or null when creation is disabled. |
| bucket_id | ID and name of the created general purpose S3 bucket, or null when creation is disabled. |
| bucket_region | AWS Region of the created general purpose S3 bucket, or null when creation is disabled. |
| bucket_regional_domain_name | Regional domain name of the created general purpose S3 bucket, or null when creation is disabled. |
| directory_bucket_arn | Amazon Resource Name (ARN) of the created S3 directory bucket, or null when creation is disabled. |
| directory_bucket_name | Name of the created S3 directory bucket, or null when creation is disabled. |
| website_domain | Domain of the configured S3 bucket website, or null when website configuration is disabled. |
| website_endpoint | Endpoint of the configured S3 bucket website, or null when website configuration is disabled. |