Skip to main content
Amazon S3 supports server-side encryption (SSE) transparently — AWS encrypts objects when they are written and decrypts them when they are read. The module exposes the full server_side_encryption_configuration variable so you can choose the algorithm and key.

SSE-S3 (AES-256)

SSE-S3 uses Amazon-managed keys. No additional KMS charges apply.
module "s3_bucket" {
  source = "terraform-aws-modules/s3-bucket/aws"

  bucket = "my-encrypted-bucket"

  server_side_encryption_configuration = {
    rule = {
      apply_server_side_encryption_by_default = {
        sse_algorithm = "AES256"
      }
    }
  }
}

SSE-KMS (aws:kms)

SSE-KMS uses AWS KMS customer managed keys (CMKs). Each object encryption and decryption call generates a KMS API request, which may incur cost at high throughput.
resource "aws_kms_key" "objects" {
  description             = "KMS key is used to encrypt bucket objects"
  deletion_window_in_days = 7
}

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

  bucket = "my-kms-encrypted-bucket"

  server_side_encryption_configuration = {
    rule = {
      apply_server_side_encryption_by_default = {
        kms_master_key_id = aws_kms_key.objects.arn
        sse_algorithm     = "aws:kms"
      }
    }
  }
}

Bucket Key — reducing KMS costs

When bucket_key_enabled = true S3 generates a short-lived bucket-level key from your KMS CMK. Subsequent object-level operations use this bucket key rather than calling KMS directly, reducing API calls — and costs — by up to 99 %.
module "s3_bucket" {
  source = "terraform-aws-modules/s3-bucket/aws"

  bucket = "my-kms-encrypted-bucket"

  server_side_encryption_configuration = {
    rule = {
      apply_server_side_encryption_by_default = {
        kms_master_key_id = aws_kms_key.objects.arn
        sse_algorithm     = "aws:kms"
      }
      bucket_key_enabled = true
    }
  }
}
Enable bucket_key_enabled whenever you use SSE-KMS on buckets with more than a few thousand objects.

Enforcing the correct KMS key

Use attach_deny_incorrect_kms_key_sse together with allowed_kms_key_arn to add a bucket policy that rejects PutObject requests that use a different KMS key:
module "s3_bucket" {
  source = "terraform-aws-modules/s3-bucket/aws"

  bucket = "my-kms-encrypted-bucket"

  server_side_encryption_configuration = {
    rule = {
      apply_server_side_encryption_by_default = {
        kms_master_key_id = aws_kms_key.objects.arn
        sse_algorithm     = "aws:kms"
      }
      bucket_key_enabled = true
    }
  }

  # Enforce the correct KMS key on every upload
  attach_deny_incorrect_kms_key_sse = true
  allowed_kms_key_arn               = aws_kms_key.objects.arn

  # Deny uploads without any server-side encryption header
  attach_deny_unencrypted_object_uploads = true

  # Deny uploads that specify incorrect encryption headers
  attach_deny_incorrect_encryption_headers = true
}

Blocking SSEC (customer-provided keys)

If you want to prevent callers from uploading objects with their own encryption keys (SSE-C), set:
attach_deny_ssec_encrypted_object_uploads = true

Blocked encryption types

The blocked_encryption_types field in the rule block lets you explicitly deny certain algorithms. The complete example blocks SSE-C at the rule level:
server_side_encryption_configuration = {
  rule = {
    apply_server_side_encryption_by_default = {
      kms_master_key_id = aws_kms_key.objects.arn
      sse_algorithm     = "aws:kms"
    }
    blocked_encryption_types = ["SSE-C"]
  }
}

Comparison

FeatureSSE-S3SSE-KMS
Key managementAWS managedCustomer managed CMK
Additional costNoneKMS API call per object
Audit trailNoYes (CloudTrail)
Key rotationAutomaticConfigurable
Bucket Key supportN/AYes (reduces cost)