AWS SCPs evaluate S3 request headers before bucket default KMS encryption
This review details a common AWS security pitfall where Service Control Policies (SCPs) enforce encryption headers before S3's default server-side encryption applies, leading to unexpected access…
This review details a common AWS security pitfall where Service Control Policies (SCPs) enforce encryption headers before S3's default server-side encryption applies, leading to unexpected access denials.
TL;DR
Best for: AWS Organizations users implementing strict data residency or encryption policies via SCPs, especially those using S3 bucket default encryption.
Skip if: You are not using AWS Organizations or are not enforcing server-side encryption at the OU/account level.
Bottom line: AWS SCPs evaluate S3 PutObject request headers for encryption before S3 applies bucket default encryption, requiring clients to explicitly send KMS key IDs.
METHODOLOGY
This v0 review draws on zero_backend_bro's published claims on Reddit, detailing a multi-hour debugging process for an S3 AccessDenied error. The review covers the specific SCP JSON, aws s3 cp commands, and cfn-guard unit test described in the source. We observed AWS Service Control Policies (SCPs) and S3 behavior as described on 2026-05-19. This review does not include independent performance benchmarks, long-term workflow impacts, or broader edge case analysis. Our update cadence dictates re-testing when claims diverge from observed behavior.
WHAT IT DOES
Service Control Policies (SCPs) enforce guardrails
SCPs are a feature of AWS Organizations, allowing administrators to centralize policy management and enforce guardrails across member accounts. zero_backend_bro encountered an explicit deny in a service control policy at the ou-prod-secured Organizational Unit (OU) level. This SCP specifically targeted s3:PutObject operations in the prod-workloads account, preventing uploads that did not meet specific encryption criteria.
S3 default encryption automates object security
Amazon S3 buckets can be configured with default server-side encryption, automatically encrypting objects upon upload. In the prod-workloads account, the acme-prod-artifacts bucket was configured to require aws:kms with a specific Customer Master Key (CMK). This setup is designed to simplify encryption for clients, as they can upload objects without explicitly specifying encryption headers, relying on the bucket's default settings.
Policy evaluation order creates a pitfall
The core issue identified is the order in which AWS evaluates policies. SCPs evaluate the s3:PutObject request headers, including s3:x-amz-server-side-encryption-aws-kms-key-id, before S3 applies the bucket's default encryption settings. The problematic SCP contained a Deny block for s3:PutObject if the s3:x-amz-server-side-encryption-aws-kms-key-id header was Null. Since the build process was relying on bucket default encryption, it did not send this header, resulting in a Null value from the SCP's perspective and a terminal AccessDenied error, despite the bucket being configured for default KMS encryption.
WHAT'S INTERESTING / WHAT'S NOT
What's interesting here is the explicit detail on AWS's policy evaluation order, which is critical for security architects and DevOps engineers. The fact that CloudTrail errorMessage truncates in the Console event view, requiring aws cloudtrail lookup-events for the full string, highlights a common debugging friction point. This detail alone can save hours of investigation. The concrete solution of forcing aws s3 cp to explicitly send --sse-kms-key-id or setting AWS_S3_SSE_KMS_KEY_ID in buildspec.yml is an actionable workaround. The inclusion of an aws:ViaAWSService exception block for legitimate service-internal calls and a cfn-guard unit test demonstrates robust, proactive policy management, moving beyond reactive debugging.
What's not particularly interesting are the initial debugging steps (checking bucket policy, object ownership, ACLs, KMS key policy, VPC endpoint policy). While necessary for AccessDenied errors, they represent standard troubleshooting and do not reveal novel insights beyond the specific SCP interaction. The general concept that
Every claim ties to a primary source. See our methodology.