A company stores sensitive data in Amazon S3 and wants to ensure that all objects are encrypted at rest. The security team has enabled default encryption on the S3 bucket using SSE-S3. However, an audit reveals that some objects are stored with SSE-KMS. How can the company enforce that only SSE-S3 is used for all future uploads, while still allowing existing SSE-KMS objects to be read?
Trap 1: Configure a bucket policy that denies s3:PutObject with…
A bucket policy that denies s3:PutObject when the condition key s3:x-amz-server-side-encryption-aws:kms equals "aws:kms" only blocks uploads that explicitly request SSE-KMS; it does not require SSE-S3, because requests with no encryption header or with AES256 would not match the condition and would be permitted. Existing SSE-KMS objects remain readable, so this does not enforce a uniform encryption standard and can even allow unencrypted PUTs if no default encryption is set.
Trap 2: Use an S3 Lifecycle policy to transition existing SSE-KMS objects…
S3 Lifecycle policies only transition the storage class of an object (for example, from S3 Standard to S3 Glacier Deep Archive) and never rewrite or replace the object's encryption settings. To change existing objects from SSE-KMS to SSE-S3, you must programmatically copy each object to itself or to a new key while specifying the desired server-side encryption, then delete the original — a lifecycle rule cannot perform that operation.
Trap 3: Disable SSE-KMS in the AWS KMS key policy to prevent its use.
Disabling the AWS KMS key in its key policy (or via the console) makes the key unusable, which means S3 cannot decrypt any existing objects that were encrypted with that customer-managed key, causing GET calls to fail with an AccessDenied error. This also prevents all new uses of the key, including non-S3 services, and does nothing to require AES256 encryption; instead you would need to re-encrypt objects with a new key or use bucket policy to enforce SSE-S3.
- A
Configure a bucket policy that denies s3:PutObject with s3:x-amz-server-side-encryption-aws:kms.
Why wrong: A bucket policy that denies s3:PutObject when the condition key s3:x-amz-server-side-encryption-aws:kms equals "aws:kms" only blocks uploads that explicitly request SSE-KMS; it does not require SSE-S3, because requests with no encryption header or with AES256 would not match the condition and would be permitted. Existing SSE-KMS objects remain readable, so this does not enforce a uniform encryption standard and can even allow unencrypted PUTs if no default encryption is set.
- B
Use an S3 Lifecycle policy to transition existing SSE-KMS objects to SSE-S3.
Why wrong: S3 Lifecycle policies only transition the storage class of an object (for example, from S3 Standard to S3 Glacier Deep Archive) and never rewrite or replace the object's encryption settings. To change existing objects from SSE-KMS to SSE-S3, you must programmatically copy each object to itself or to a new key while specifying the desired server-side encryption, then delete the original — a lifecycle rule cannot perform that operation.
- C
Apply a bucket policy that denies s3:PutObject unless the x-amz-server-side-encryption header is AES256.
This bucket policy uses the condition key s3:x-amz-server-side-encryption with a StringNotEquals condition equal to "AES256" to deny any s3:PutObject request whose encryption header is not exactly AES256. Because the denial is scoped to PutObject, existing objects and GET/read operations are unaffected, and the policy enforces SSE-S3 for new uploads only; note that without a bucket default encryption, a request with no header would be denied, forcing clients to explicitly set the header.
- D
Disable SSE-KMS in the AWS KMS key policy to prevent its use.
Why wrong: Disabling the AWS KMS key in its key policy (or via the console) makes the key unusable, which means S3 cannot decrypt any existing objects that were encrypted with that customer-managed key, causing GET calls to fail with an AccessDenied error. This also prevents all new uses of the key, including non-S3 services, and does nothing to require AES256 encryption; instead you would need to re-encrypt objects with a new key or use bucket policy to enforce SSE-S3.