Security8 min readSeptember 28, 2026

Amazon S3 encryption at rest: SSE-S3, SSE-KMS, DSSE-KMS or SSE-C

Every S3 object is already encrypted. What the four server-side encryption types actually change, the KMS permissions that break downloads, S3 Bucket Keys, the April 2026 SSE-C default, and how to re-encrypt what is already there.

JeVaughn Ferguson
Founder, developer
The short version

Your objects are already encrypted; the decision is about control. Keep SSE-S3 where bucket permissions are the whole story, move business files to SSE-KMS with a customer managed key and an S3 Bucket Key, and grant kms:Decrypt and kms:GenerateDataKey by role in the key policy before you flip the default. Re-encrypt existing objects with Inventory and Batch Operations, enforce TLS with aws:SecureTransport, and reserve DSSE-KMS for a requirement that names it and SSE-C for a system that genuinely has to hold its own keys.

Since January 5, 2023, every new object written to Amazon S3 has been encrypted at rest, at no charge and without anyone asking for it. So the question a security questionnaire asks, "is the data encrypted?", has a boring answer. The question worth answering is who holds the key, who can use it, and what shows up in the logs when they do.

That is what the choice between SSE-S3, SSE-KMS, DSSE-KMS and SSE-C decides. This guide covers what each one changes, the permissions that quietly break downloads when you move to KMS, how to keep the KMS bill small, and what to do about the objects that were written before you changed anything.

Check what you already have

The bucket default and the object are separate facts. The bucket’s default encryption applies to new writes that do not ask for something else; every existing object keeps whatever it was written with. Look at both before deciding anything.

In the console, the bucket’s Properties tab shows Default encryption, and an object’s Properties tab shows its Server-side encryption settings. From the CLI, get-bucket-encryption returns the default and head-object returns ServerSideEncryption (AES256 for SSE-S3, aws:kms for SSE-KMS, aws:kms:dsse for DSSE-KMS) plus the KMS key ID and whether an S3 Bucket Key was used. For a whole bucket, S3 Inventory can report the encryption status of every object without calling HeadObject millions of times.

aws s3api get-bucket-encryption --bucket amzn-s3-demo-bucket

aws s3api head-object \
  --bucket amzn-s3-demo-bucket \
  --key finance/2026/q3-forecast.xlsx \
  --query '{sse: ServerSideEncryption, key: SSEKMSKeyId, bucketKey: BucketKeyEnabled}'

The four options, and what each one changes

All four encrypt with AES-256 on the server side, and all four are invisible to an authorised reader: a GET, a listing or a presigned URL works the same way whatever the encryption type. What differs is the key, and therefore the control and the audit trail.

  • SSE-S3: S3 owns and rotates the keys. Every bucket has it by default, it costs nothing, and anyone with s3:GetObject can read the object. There is no separate key permission to grant or revoke, and no per-decrypt log entry.
  • SSE-KMS: each object’s data key is protected by a KMS key, either the AWS managed key aws/s3 or a customer managed key you create. Reading needs kms:Decrypt on that key as well as s3:GetObject, key usage is logged in CloudTrail, and disabling the key makes every object under it unreadable. KMS charges apply.
  • DSSE-KMS: two independent layers of AES-256, one with a KMS data key and one with an S3-managed key. It exists for requirements that name multilayer encryption explicitly. It behaves like SSE-KMS for permissions, costs more, and cannot use S3 Bucket Keys.
  • SSE-C: you send the key with every request, S3 uses it and discards it. Lose the key and the object is gone; every reader and every tool needs the key in hand. Since April 2026 it is disabled by default for new general purpose buckets, and must be switched on deliberately with PutBucketEncryption.

Why most business buckets should move to SSE-KMS

SSE-S3 is real encryption, but its access control is exactly the bucket’s access control. If a policy mistake grants s3:GetObject too widely, the encryption does not help, because S3 decrypts for anyone S3 authorises.

A customer managed KMS key adds a second, independent gate. The key policy decides which roles may decrypt, so a misconfigured bucket policy alone is no longer enough to read the files. You get a CloudTrail record of key use, you can disable the key in an incident and stop all reads at once, and the key policy is the thing a customer or auditor can review to see exactly who can open their data.

Choose a customer managed key rather than aws/s3 as soon as more than one AWS account is involved. Objects encrypted under the AWS managed key cannot be shared cross-account, and the aws/s3 key policy cannot be edited. A customer managed key costs $1 a month plus requests, and its policy is yours to write.

The permissions that break when you switch

The most common SSE-KMS incident is not a breach; it is a role that could read the bucket yesterday getting AccessDenied today. Moving to KMS adds key permissions to every path that touches the objects.

{
  "Sid": "AllowWorkspaceRoleToUseTheKey",
  "Effect": "Allow",
  "Principal": { "AWS": "arn:aws:iam::111122223333:role/file-workspace-access" },
  "Action": ["kms:Decrypt", "kms:GenerateDataKey"],
  "Resource": "*",
  "Condition": {
    "StringEquals": { "kms:ViaService": "s3.us-east-1.amazonaws.com" }
  }
}
  • Downloading needs kms:Decrypt on the key.
  • Uploading needs kms:GenerateDataKey. A multipart upload, which the CLI and SDKs switch to automatically for larger files, needs both kms:GenerateDataKey and kms:Decrypt.
  • Cross-account access needs the permission twice: in the key policy, naming the other account or role, and in that role’s own IAM policy.
  • Specify customer managed keys by full ARN. An alias is resolved in the requester’s account, so a cross-account upload can end up encrypted under the uploader’s key rather than the bucket owner’s.
  • Leave server access logging destinations on SSE-S3. If the destination bucket defaults to SSE-KMS, S3 may deliver log objects encrypted with a key you cannot use.
  • Do not send encryption headers on GET or HEAD for SSE-KMS objects; S3 answers with 400 Bad Request.

Keep the KMS bill small with S3 Bucket Keys

Without a Bucket Key, S3 asks KMS for a data key for every object it encrypts and calls KMS again for every object it decrypts. A folder of ten thousand thumbnails becomes ten thousand KMS requests, which costs money and can press against KMS request quotas.

An S3 Bucket Key is a short-lived bucket-level key that S3 fetches from KMS and uses to create object data keys for a while, which AWS says can cut KMS request costs by up to 99 percent. Enabling it is one setting with no client changes. Two things change with it: the encryption context becomes the bucket ARN instead of the object ARN, so key policies that restrict by object ARN must be updated first; and CloudTrail shows fewer, bucket-level KMS events. S3 still fetches a key at least once per requester, so each role’s use of the key is still recorded.

aws s3api put-bucket-encryption \
  --bucket amzn-s3-demo-bucket \
  --server-side-encryption-configuration '{
    "Rules": [{
      "ApplyServerSideEncryptionByDefault": {
        "SSEAlgorithm": "aws:kms",
        "KMSMasterKeyID": "arn:aws:kms:us-east-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"
      },
      "BucketKeyEnabled": true
    }]
  }'

Re-encrypting the objects you already have

Changing the default encryption, or turning on a Bucket Key, affects new writes only. The object written last year under SSE-S3 stays SSE-S3 until it is rewritten.

For a handful of objects, copy each one onto itself with the new settings. For a real bucket, use S3 Inventory to list the objects that are not yet under the target key and an S3 Batch Operations Copy job to rewrite them; one job can cover billions of objects. Plan for what a copy implies: in a versioned bucket it creates a new version and keeps the old one, so the old SSE-S3 versions remain until lifecycle expires them; the copy counts as a new write for storage-class minimum-duration charges; and single-request copies are limited to 5 GB, beyond which a multipart copy is required.

# One object: rewrite in place under the bucket's KMS key.
aws s3 cp s3://amzn-s3-demo-bucket/contracts/acme-msa.pdf \
          s3://amzn-s3-demo-bucket/contracts/acme-msa.pdf \
  --sse aws:kms \
  --sse-kms-key-id arn:aws:kms:us-east-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab

Encryption in transit is a bucket policy, not a setting

Encryption at rest says nothing about the network. AWS endpoints require TLS 1.2 or later, and SSE-KMS objects can only be read over TLS, but a bucket will still answer plain HTTP for SSE-S3 objects unless a policy says otherwise. The standard control is a Deny on any request where aws:SecureTransport is false, plus s3:TlsVersion if a minimum version is written into your requirements.

Client-side encryption is the remaining option: the application encrypts before upload and S3 only ever stores ciphertext. It gives the strongest separation, and it takes away everything that needs to read the file on the server side, including previews, search and virus scanning. Most business file archives are better served by SSE-KMS with a tight key policy.

What this means for a file workspace on your bucket

Any tool that previews, shares or restores files in your bucket reads the objects, so on an SSE-KMS bucket it needs kms:Decrypt on your key, granted to its role in your key policy. That is a feature rather than a chore: the key policy becomes a second, independent place where you can see and revoke the workspace’s access, and CloudTrail shows its key use next to its S3 requests.

BucketDesk connects through a role in your own AWS account, so the same rule applies: grant the role kms:Decrypt, and kms:GenerateDataKey if people upload, on the specific key, and remove it when you want access to stop.

Try it in BucketDesk

Starter is free. Deploy a scoped role with CloudFormation, sign in, and browse, without handing anyone an access key.

Connect a bucket

Primary sources

Discussion

0 comments · open to guests · moderated
Comments appear after a quick review.

Liked this? Get the next article by email. No schedule, no filler, one click to leave.

Keep reading

All writing →