DEV Community

Wakeup Flower
Wakeup Flower

Posted on

S3 Bucket policy encryption key enforcement

Restatement

The requirement is:

Update the bucket policy so that any PutObject request will be denied unless it includes the x-amz-server-side-encryption header.

This is AWS S3 bucket policy enforcement to require server-side encryption for all objects uploaded.


Why this is needed

  • By default, anyone with permission to upload to a bucket can upload data without encryption.
  • Security best practice often requires all objects to be encrypted.
  • Enforcing via a bucket policy prevents users from bypassing encryption requirements.

How it works

When you upload an object to S3 (PutObject), you can include headers that control encryption, such as:

x-amz-server-side-encryption: AES256
Enter fullscreen mode Exit fullscreen mode

or

x-amz-server-side-encryption: aws:kms
Enter fullscreen mode Exit fullscreen mode

A bucket policy can check for this header and deny the upload if it’s missing.


Example Bucket Policy

Here’s a sample policy that enforces server-side encryption:

{
  "Version": "2012-10-17",
  "Id": "EnforceSSE",
  "Statement": [
    {
      "Sid": "DenyUnencryptedObjectUploads",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::my-bucket-name/*",
      "Condition": {
        "StringNotEquals": {
          "s3:x-amz-server-side-encryption": "AES256"
        }
      }
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Breaking this policy down

Field Meaning
"Effect": "Deny" Denies the action if the condition matches
"Principal": "*" Applies to all users
"Action": "s3:PutObject" Applies to object uploads
"Resource": "arn:aws:s3:::my-bucket-name/*" Applies to all objects in the bucket
"Condition" Specifies the requirement
"StringNotEquals" Deny if the header does not equal "AES256"
"s3:x-amz-server-side-encryption" The encryption header

Example in Practice

Allowed request

PUT /my-object HTTP/1.1
Host: my-bucket-name.s3.amazonaws.com
x-amz-server-side-encryption: AES256
Enter fullscreen mode Exit fullscreen mode

✅ Allowed — encryption header is present.

Denied request

PUT /my-object HTTP/1.1
Host: my-bucket-name.s3.amazonaws.com
Enter fullscreen mode Exit fullscreen mode

❌ Denied — encryption header missing.


Key points for exams

  • The Condition key s3:x-amz-server-side-encryption enforces encryption headers.
  • Bucket policies are evaluated before IAM policies — so this is a powerful enforcement tool.
  • This is often asked in SAA exam scenarios where compliance and security policies are involved.

Top comments (1)

Collapse
 
scsoi profile image
疏影 •

KMS encryption enforcement at the bucket policy layer is the cleanest pattern we have for compliance, but three production gotchas to watch for:

  1. Deny-without-explicit-Deny — operators frequently confuse Deny + not-Deny with implicit Deny. Once SSE-KMS is required, every request without the right header gets blocked. Mount layers that synthesize their own client (drive-letter S3 mounts) often skip the header silently, so admin-side mounts suddenly stop working after the policy ships.

  2. Cross-account key access — when buckets move to a centralized KMS key, the policy on the key itself has to allow the bucket account. S3 policy says yes, KMS policy says no — failures look like a 403 with no clue which side rejected.

  3. PutObject alone is not enough — GetObject also has to enforce the same key, otherwise a no-SSE object lands via multipart upload and survives any read-side check. Pair the bucket policy with a lifecycle rule that aborts incomplete multipart uploads within 7 days — that one alone saved us from a few surprise storage bills.

Mount layer: ScsDriver