Overview
S3 Inventory produces daily or weekly CSV, ORC, or Parquet reports listing every object (or every current-version object) in a bucket, along with optional metadata fields such as size, storage class, encryption status, and replication status. Inventory reports are useful for auditing, compliance, cost analysis, and batch operations.
The inventory_configuration variable
variable "inventory_configuration" {
description = "Map containing S3 inventory configuration."
type = any
default = {}
}
The map key becomes the name of the aws_s3_bucket_inventory resource. Each value supports the following fields:
| Field | Type | Description |
|---|
included_object_versions | string | "All" or "Current" |
frequency | string | "Daily" or "Weekly" |
enabled | bool | Whether this inventory configuration is enabled. Defaults to true |
optional_fields | list(string) | Additional metadata columns to include in the report |
filter.prefix | string | Limit inventory to objects with this key prefix |
bucket | string | Source bucket ID when the source differs from the module bucket |
destination.bucket_arn | string | ARN of the destination bucket. Defaults to the source bucket’s ARN |
destination.format | string | Report format: "CSV", "ORC", or "Parquet" |
destination.account_id | string | Account ID of the destination bucket owner |
destination.prefix | string | Key prefix for inventory files in the destination bucket |
destination.encryption.encryption_type | string | "sse_kms" or "sse_s3" |
destination.encryption.kms_key_id | string | KMS key ARN when encryption_type = "sse_kms" |
Optional fields reference
Common values for optional_fields:
Size
LastModifiedDate
StorageClass
ETag
IsMultipartUploaded
ReplicationStatus
EncryptionStatus
ObjectLockRetainUntilDate
ObjectLockMode
ObjectLockLegalHoldStatus
IntelligentTieringAccessTier
BucketKeyStatus
ChecksumAlgorithm
How the resource is created
For each entry in inventory_configuration the module creates one aws_s3_bucket_inventory resource:
resource "aws_s3_bucket_inventory" "this" {
for_each = { for k, v in var.inventory_configuration : k => v if local.create_bucket && !var.is_directory_bucket }
name = each.key
bucket = try(each.value.bucket, aws_s3_bucket.this[0].id)
included_object_versions = each.value.included_object_versions
enabled = try(each.value.enabled, true)
optional_fields = try(each.value.optional_fields, null)
destination {
bucket {
bucket_arn = try(each.value.destination.bucket_arn, aws_s3_bucket.this[0].arn)
format = try(each.value.destination.format, null)
account_id = try(each.value.destination.account_id, null)
prefix = try(each.value.destination.prefix, null)
dynamic "encryption" {
for_each = length(try(flatten([each.value.destination.encryption]), [])) == 0 ? [] : [true]
content {
dynamic "sse_kms" {
for_each = each.value.destination.encryption.encryption_type == "sse_kms" ? [true] : []
content {
key_id = try(each.value.destination.encryption.kms_key_id, null)
}
}
dynamic "sse_s3" {
for_each = each.value.destination.encryption.encryption_type == "sse_s3" ? [true] : []
content {}
}
}
}
}
}
schedule {
frequency = each.value.frequency
}
dynamic "filter" {
for_each = length(try(flatten([each.value.filter]), [])) == 0 ? [] : [true]
content {
prefix = try(each.value.filter.prefix, null)
}
}
}
Cross-account inventory delivery
When the inventory destination bucket is in a different account, the destination bucket needs a policy that allows the S3 service to write inventory reports. The module provides the following variables for this:
| Variable | Type | Description |
|---|
attach_inventory_destination_policy | bool | Set to true on the destination bucket |
inventory_source_bucket_arn | string | ARN of the bucket being inventoried |
inventory_source_account_id | string | Account ID that owns the source bucket |
inventory_self_source_destination | bool | Set to true when source and destination are the same bucket |
Examples
Daily inventory, same bucket
Weekly inventory, all versions
Multiple configurations
Cross-account delivery
A daily CSV inventory of current-version objects in the documents/ prefix, stored in the same bucket with SSE-KMS encryption.module "bucket" {
source = "terraform-aws-modules/s3-bucket/aws"
bucket = "my-bucket"
attach_policy = true
attach_inventory_destination_policy = true
inventory_self_source_destination = true
inventory_configuration = {
daily = {
included_object_versions = "Current"
destination = {
format = "CSV"
encryption = {
encryption_type = "sse_kms"
kms_key_id = module.kms.key_arn
}
}
filter = {
prefix = "documents/"
}
frequency = "Daily"
}
}
}
A weekly CSV inventory of all versions of all objects with no destination encryption (SSE-S3 via bucket default).module "bucket" {
source = "terraform-aws-modules/s3-bucket/aws"
bucket = "my-bucket"
attach_policy = true
attach_inventory_destination_policy = true
inventory_self_source_destination = true
inventory_configuration = {
weekly = {
included_object_versions = "All"
destination = {
format = "CSV"
}
frequency = "Weekly"
}
}
}
Multiple inventory configurations on one bucket, each with different settings. This matches the pattern from the examples/s3-inventory/ example.module "multi_inventory_configurations_bucket" {
source = "terraform-aws-modules/s3-bucket/aws"
bucket = "my-bucket"
force_destroy = true
attach_policy = true
attach_inventory_destination_policy = true
inventory_self_source_destination = true
versioning = {
status = true
mfa_delete = false
}
inventory_configuration = {
# Same source and destination, SSE-KMS, filtered to documents/
daily = {
included_object_versions = "Current"
destination = {
format = "CSV"
encryption = {
encryption_type = "sse_kms"
kms_key_id = module.kms.key_arn
}
}
filter = {
prefix = "documents/"
}
frequency = "Daily"
}
# Same source and destination, no encryption specified
weekly = {
included_object_versions = "All"
destination = {
format = "CSV"
}
frequency = "Weekly"
}
# Different destination bucket, Parquet format, SSE-S3
destination_other = {
included_object_versions = "All"
destination = {
bucket_arn = module.inventory_destination_bucket.s3_bucket_arn
format = "Parquet"
encryption = {
encryption_type = "sse_s3"
}
}
frequency = "Weekly"
optional_fields = ["Size", "EncryptionStatus", "StorageClass", "ChecksumAlgorithm"]
}
# Different source bucket, ORC format
source_other = {
included_object_versions = "Current"
bucket = module.inventory_source_bucket.s3_bucket_id
destination = {
format = "ORC"
encryption = {
encryption_type = "sse_s3"
}
}
frequency = "Daily"
}
}
}
The source bucket sends inventory to a destination bucket in a different account.# Source bucket — no special inventory destination policy needed here
module "inventory_source_bucket" {
source = "terraform-aws-modules/s3-bucket/aws"
bucket = "my-source-bucket"
force_destroy = true
}
# Destination bucket — needs the inventory destination policy
module "inventory_destination_bucket" {
source = "terraform-aws-modules/s3-bucket/aws"
bucket = "my-inventory-destination"
force_destroy = true
attach_policy = true
attach_inventory_destination_policy = true
inventory_source_bucket_arn = module.inventory_source_bucket.s3_bucket_arn
inventory_source_account_id = data.aws_caller_identity.current.id
}
Destination encryption
The destination.encryption block supports two encryption types:
Encrypt inventory files with a customer-managed KMS key. The key must grant kms:GenerateDataKey to the s3.amazonaws.com service principal scoped to the source bucket ARN and account.destination = {
format = "CSV"
encryption = {
encryption_type = "sse_kms"
kms_key_id = "arn:aws:kms:eu-west-1:123456789012:key/mrk-..."
}
}
Encrypt inventory files with the Amazon S3-managed key (SSE-S3). No additional key configuration is required.destination = {
format = "Parquet"
encryption = {
encryption_type = "sse_s3"
}
}
When using SSE-KMS for inventory encryption, you must add a key policy statement that grants kms:GenerateDataKey to the s3.amazonaws.com service principal. Without this, the S3 service cannot encrypt the inventory files and the configuration will fail. See the examples/s3-inventory/main.tf KMS module configuration for the required policy structure.
Inventory configuration is not supported on S3 Directory Buckets. The aws_s3_bucket_inventory resource is skipped automatically when is_directory_bucket = true.