Skip to main content

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:
FieldTypeDescription
included_object_versionsstring"All" or "Current"
frequencystring"Daily" or "Weekly"
enabledboolWhether this inventory configuration is enabled. Defaults to true
optional_fieldslist(string)Additional metadata columns to include in the report
filter.prefixstringLimit inventory to objects with this key prefix
bucketstringSource bucket ID when the source differs from the module bucket
destination.bucket_arnstringARN of the destination bucket. Defaults to the source bucket’s ARN
destination.formatstringReport format: "CSV", "ORC", or "Parquet"
destination.account_idstringAccount ID of the destination bucket owner
destination.prefixstringKey prefix for inventory files in the destination bucket
destination.encryption.encryption_typestring"sse_kms" or "sse_s3"
destination.encryption.kms_key_idstringKMS 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:
VariableTypeDescription
attach_inventory_destination_policyboolSet to true on the destination bucket
inventory_source_bucket_arnstringARN of the bucket being inventoried
inventory_source_account_idstringAccount ID that owns the source bucket
inventory_self_source_destinationboolSet to true when source and destination are the same bucket

Examples

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

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