S3 encryption: SSE-S3, SSE-KMS, Bucket Keys, SSE-C and TLS

Every object is encrypted at rest by default (SSE-S3). What each server-side option requires of the caller, how Bucket Keys change KMS behaviour, the April 2026 SSE-C default, and how to require HTTPS and a minimum TLS version.

markdownreferencev4YVKG-Q7G2stage: referencetrust: officialservice: s3service: kmsinterface: anySSE-S3SSE-KMSaws/s3 keykms:GenerateDataKeykms:DecryptBucket Keysencryption contextSSE-CBlockedEncryptionTypesPutBucketEncryptionaws:SecureTransports3:TlsVersionTLS 1.3

Created 18 Oct 2026 · Modified 23 Oct 2026 · 4 versions

S3 encryption

Every object is encrypted at rest; you choose who holds the key. S3 applies SSE-S3 (S3-managed keys) to every bucket by default. Choosing SSE-KMS adds a KMS key policy as a second gate on every read and write. SSE-C has been blocked by default since April 2026.

At rest: what each option asks of the caller

OptionCaller needs, beyond S3 permissionsNotes
SSE-S3 (default)NothingBase level for every bucket
SSE-KMS, customer managed keykms:GenerateDataKey to upload; kms:Decrypt to download and for multipart uploads — allowed by the key policy and the caller's IAM policy (both sides when cross-account)The key policy is a separate policy that must name the caller
SSE-KMS, AWS managed key (aws/s3)The caller must be in the account that owns the keyCannot be shared cross-account: use a customer managed key for cross-account data
SSE-C (customer-provided key)Sends the key with each requestBlocked by default (below)

Check what a bucket and an object use:

aws s3api get-bucket-encryption --bucket <bucket>
aws s3api head-object --bucket <bucket> --key <key>

KMS errors from S3 (400): KMS.DisabledException, KMS.NotFoundException, KMS.KMSInvalidStateException, KMS.InvalidKeyUsageException (reference/s3/bucket-and-object-errors.md).

Destinations such as SNS topics and SQS queues encrypted with an AWS managed key (aws/sns, aws/sqs) cannot receive S3 event notifications; use a customer managed key that allows s3.amazonaws.com (patterns/s3-to-lambda.md).

Bucket Keys (SSE-KMS)

A Bucket Key lets S3 derive data keys from a short-lived bucket-level key instead of calling KMS for every object, cutting KMS request costs (AWS cites up to 99%).

  • Encryption context becomes the bucket ARN, not the object ARN. IAM or key policies that condition on the object ARN in the encryption context stop matching. Update them before enabling.
  • CloudTrail shows fewer KMS events, logged with the bucket ARN; access is still recorded at least once per requester.
  • Requests served from the bucket-level key do not re-check the KMS key policy each time.
  • Applies only to new objects; re-encrypt existing ones with CopyObject. Not supported with DSSE-KMS.

Enable as the bucket default:

aws s3api put-bucket-encryption --bucket <bucket> --server-side-encryption-configuration '{
  "Rules": [{
    "ApplyServerSideEncryptionByDefault": { "SSEAlgorithm": "aws:kms", "KMSMasterKeyID": "<key ARN>" },
    "BucketKeyEnabled": true
  }]
}'

Or per object with --bucket-key-enabled (header x-amz-server-side-encryption-bucket-key-enabled), which overrides the bucket setting. CloudFormation: BucketKeyEnabled on AWS::S3::Bucket.

SSE-C blocked by default (April 2026)

From 2026-04-06, rolling out across Regions over several weeks:

  • New general purpose buckets: SSE-C blocked.
  • Existing buckets in accounts with no SSE-C objects: SSE-C blocked.
  • Accounts that already had SSE-C objects in any bucket: existing buckets keep SSE-C.

A blocked SSE-C write (PutObject, CopyObject, POST, multipart, replication) returns 403 AccessDenied ending because this bucket has blocked upload requests that specify Server Side Encryption with Customer provided keys (SSE-C). Please specify a different server-side encryption type.

The control is BlockedEncryptionTypes in the bucket's encryption configuration (PutBucketEncryption, needs s3:PutEncryptionConfiguration): SSE-C blocks, NONE allows. Templates and scripts that depend on SSE-C must set it explicitly on new buckets.

In transit

S3 supports TLS 1.2 and TLS 1.3 on all API endpoints; clients negotiate the strongest both support. TLS 1.3 is not available on AWS PrivateLink for S3 or Multi-Region Access Points. Server access logs and CloudTrail record the TLS version per request.

Enforce with explicit Deny statements in the bucket policy (also possible in SCPs, RCPs and VPC endpoint policies), each with Principal "*", Action s3:*, and both the bucket ARN and <bucket ARN>/* as resources:

  • HTTPS only: deny when aws:SecureTransport is false (Bool).
  • Minimum TLS version: deny when s3:TlsVersion is numerically less than 1.2 (or 1.3).

Because these are Deny statements, they override every Allow, including the caller's own.

Read this document as markdown — the same bytes an agent receives.