CephXLVI · RGW Users and CredentialsRGW Users and Credentials
Bucket policies: the general access control mechanism
What you'll learn
- Write bucket policies for common requirements
- Explain the policy evaluation order
- Use conditions to constrain access
- Debug a policy that is not behaving as intended
Prerequisites
None — start here.
Verified against Ceph Tentacle 20.2.x · Ceph Squid 19.2.x (supported previous) · cephadm matches the verified Ceph release · podman 4.x · csi-rbd and csi-cephfs current · RBD / CephFS / RGW current (matches Ceph release) · Linux kernel 5.15+ (5.10 minimum) · Ubuntu 24.04 LTS (Ceph host baseline) · Debian 12 (Bookworm) (Ceph host baseline) · Rocky Linux / RHEL / AlmaLinux 9.x (Ceph host baseline) · Proxmox VE 9.x (cross-course integration) · Kubernetes 1.31+ (cross-course integration) · 2026-08-18
Why this matters in production
Bucket policies are the only mechanism in RGW that expresses fine-grained access control, and their evaluation model — explicit deny always wins — is what makes them safe to layer. Getting the model right is most of getting policies right.
Structure
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "AllowReportingRead",
"Effect": "Allow",
"Principal": {"AWS": ["arn:aws:iam:::user/reporting"]},
"Action": ["s3:GetObject", "s3:ListBucket"],
"Resource": [
"arn:aws:s3:::reports",
"arn:aws:s3:::reports/*"
]
}]
}
Note the two resources: ListBucket acts on the bucket, GetObject acts
on objects within it. Omitting either ARN is the most common policy
mistake.
aws --endpoint-url $EP s3api put-bucket-policy --bucket reports --policy file://policy.json
aws --endpoint-url $EP s3api get-bucket-policy --bucket reports
aws --endpoint-url $EP s3api delete-bucket-policy --bucket reports
Evaluation
1. Explicit Deny anywhere → denied, always
2. Explicit Allow → allowed
3. Neither → denied (default)
An explicit Deny cannot be overridden by any Allow. That is what makes
a guardrail policy reliable: adding a deny statement bounds everything
else regardless of what other statements or ACLs grant.
Common patterns
Require encryption:
{"Effect": "Deny", "Principal": "*", "Action": "s3:PutObject",
"Resource": "arn:aws:s3:::sensitive/*",
"Condition": {"StringNotEquals": {"s3:x-amz-server-side-encryption": "aws:kms"}}}
Restrict to a network:
{"Effect": "Deny", "Principal": "*", "Action": "s3:*",
"Resource": ["arn:aws:s3:::internal", "arn:aws:s3:::internal/*"],
"Condition": {"NotIpAddress": {"aws:SourceIp": "10.20.0.0/16"}}}
Enforce TLS:
{"Effect": "Deny", "Principal": "*", "Action": "s3:*",
"Resource": ["arn:aws:s3:::data", "arn:aws:s3:::data/*"],
"Condition": {"Bool": {"aws:SecureTransport": "false"}}}
Public read for a website bucket:
{"Effect": "Allow", "Principal": "*", "Action": "s3:GetObject",
"Resource": "arn:aws:s3:::website/*"}
Debugging
| Symptom | Likely cause |
|---|---|
| Access denied despite an Allow | an explicit Deny elsewhere matches |
| ListBucket denied, GetObject works | bucket ARN missing from Resource |
| Policy accepted but no effect | Principal ARN does not match the actual user |
| Condition never matches | key name or value case mismatch |
# what is actually applied?
aws --endpoint-url $EP s3api get-bucket-policy --bucket reports | jq -r '.Policy' | jq .
# raise gateway logging for the request
ceph config set client.rgw debug_rgw 10
Quiz
Knowledge check · 4 questions
Q1. A bucket policy grants a user s3:GetObject and s3:ListBucket with only `arn:aws:s3:::data/*` as the resource. What happens?
Q2. A Deny statement written today constrains Allow statements added to the same bucket policy months later.
Q3. Enforce encryption and network restrictions on a sensitive bucket.
A bucket holds regulated data. The requirements are that objects must be uploaded with KMS encryption, access must come from the corporate network, and all access must use TLS. Several teams have existing Allow grants on the bucket.
Q4. Why express security requirements as Deny statements rather than by restricting Allow statements?
Passing score: 75%. Answers are checked in this browser.
Production discipline
Express security requirements as Deny statements with negated conditions so they bound every present and future grant on the bucket. Include both the bucket ARN and the object ARN in read policies — omitting one produces the specific and confusing symptom of listing failing while direct gets succeed.
Cross-course references
- Kubernetes: admission webhooks act as the same kind of absolute guardrail over RBAC grants
- Linux: a deny rule in a firewall chain ordered before allows serves the identical purpose