Skip to content
AWS aws storage 5 min read

S3 Encryption

Amazon S3 (Simple Storage Service, AWS’s object storage) can automatically scramble your data so that anyone who somehow reads the raw bytes on disk sees nothing useful. This is called encryption at rest. The good news: every S3 bucket already does this for you by default, so your data is never stored unencrypted. The interesting question is which kind of encryption to use, because the choice affects who can decrypt your data, how much you pay, and how fast high-traffic buckets run. This page compares the three options and the gotchas that trip people up.

What “encryption at rest” actually means

Encryption at rest protects data while it sits stored on disk. When an object is written, S3 encrypts it with a data key; when an object is read, S3 decrypts it before sending it back. This is separate from encryption in transit (TLS, the https:// you use to upload), which protects data while it moves over the network. You almost always want both.

Since January 2023, AWS applies server-side encryption by default to every new and existing bucket. So you are never choosing whether to encrypt — you are only choosing which key protects your objects. There are three server-side encryption (SSE) modes.

The three modes: SSE-S3, SSE-KMS, SSE-C

  • SSE-S3 — AWS owns and manages the encryption keys for you. This is the default. You see nothing, manage nothing, and pay nothing extra. It uses AES-256 (Advanced Encryption Standard, a strong industry-standard cipher).
  • SSE-KMS — Encryption keys live in AWS KMS (Key Management Service, AWS’s managed key store). You control the key’s access policy, you get an audit trail of every decrypt in AWS CloudTrail, and you can rotate or disable the key. This is the choice for regulated, sensitive, or audited data.
  • SSE-C — You supply your own raw encryption key on every request. AWS uses it to encrypt/decrypt but never stores it. If you lose the key, the data is gone forever. This is rare and only for teams that must hold keys outside AWS entirely.

All three encrypt the object bytes the same strong way (AES-256). The real difference is who controls the keys and who can see the audit log, not how strong the math is.

When to use which

ModeWho manages keysAudit + access controlExtra costUse when
SSE-S3AWSNo per-key controlFreeDefault; logs, backups, general data with no compliance need
SSE-KMSYou (in KMS)Full CloudTrail audit + key policyKMS request + key feesSensitive/regulated data, need to revoke access or prove who decrypted
SSE-CYou (off-AWS)You build your ownFree in S3, but you carry all key riskYou must keep keys entirely outside AWS

For most teams: start with SSE-S3, and move to SSE-KMS the moment you have compliance, audit, or “who can read this” requirements.

Setting default encryption on a bucket

Every bucket has a default encryption setting that applies to objects uploaded without their own encryption header. Setting it once means you never have to remember per-upload.

Console steps (SSE-KMS):

  1. Open the S3 console and click your bucket name.
  2. Go to the Properties tab.
  3. Find Default encryption and click Edit.
  4. Choose Server-side encryption with AWS Key Management Service keys (SSE-KMS).
  5. Pick Choose from your AWS KMS keys and select your key, or enter its ARN.
  6. Turn Bucket Key to Enable (this is important — see below).
  7. Click Save changes.

AWS CLI equivalent:

aws s3api put-bucket-encryption \
  --bucket my-app-data-2026 \
  --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
    }]
  }'

To verify:

aws s3api get-bucket-encryption --bucket my-app-data-2026

Output:

{
    "ServerSideEncryptionConfiguration": {
        "Rules": [
            {
                "ApplyServerSideEncryptionByDefault": {
                    "SSEAlgorithm": "aws:kms",
                    "KMSMasterKeyID": "arn:aws:kms:us-east-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"
                },
                "BucketKeyEnabled": true
            }
        ]
    }
}

Encrypting a single upload

You can also set encryption per object, which overrides the bucket default for that one upload.

# SSE-S3 on one object
aws s3 cp report.pdf s3://my-app-data-2026/report.pdf \
  --sse AES256

# SSE-KMS on one object
aws s3 cp report.pdf s3://my-app-data-2026/report.pdf \
  --sse aws:kms \
  --sse-kms-key-id arn:aws:kms:us-east-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab

The big gotcha: SSE-KMS throttling and cost

With SSE-KMS, S3 normally calls the KMS API on every single PUT and GET to wrap or unwrap the data key. On a high-throughput bucket this becomes a real problem:

  • KMS has a per-region request quota (e.g. tens of thousands of requests per second). Hammer it and your reads/writes get throttled with ThrottlingException errors.
  • Each KMS request costs money: $0.03 per 10,000 requests. A bucket serving 100 million reads a month would add roughly $300/month in KMS calls alone — for data S3 already stores.

The fix is S3 Bucket Keys. When enabled, S3 asks KMS for a short-lived bucket-level key and uses it to encrypt many objects, cutting KMS API calls by up to 99%. That slashes both throttling risk and cost. There is no downside for nearly all workloads, so enable it whenever you use SSE-KMS (note the "BucketKeyEnabled": true in the example above).

A second SSE-KMS trap: the KMS key policy is a separate gate. Even if your S3 bucket policy says “Alice can read this object,” Alice still gets AccessDenied if the KMS key policy doesn’t grant her kms:Decrypt. Access requires both the bucket/IAM permission and the KMS key permission. This is the number-one cause of “I have S3 access but still can’t read the file.”

Best Practices

  • Leave default encryption on for every bucket — it already is, so don’t disable it.
  • Use SSE-S3 for general data; switch to SSE-KMS for anything sensitive, regulated, or that needs an audit trail.
  • Always enable S3 Bucket Keys with SSE-KMS to avoid throttling and runaway KMS request costs.
  • Remember the dual gate: grant kms:Decrypt in the KMS key policy and the read permission in IAM/bucket policy.
  • Prefer a customer-managed KMS key over the AWS-managed aws/s3 key when you need rotation control and cross-account access.
  • Avoid SSE-C unless you have a hard requirement to keep keys outside AWS — losing the key means losing the data.
  • Enforce encryption in transit too by adding a bucket policy that denies requests where aws:SecureTransport is false.
Last updated June 15, 2026
Was this helpful?