Skip to main content
RunBook Academy

CephXLVI · RGW Users and CredentialsRGW Users and Credentials

Bucket policies: the general access control mechanism

Advanced⏱ ~18 minaws

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

Not yet marked complete on this device.

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

SymptomLikely cause
Access denied despite an Allowan explicit Deny elsewhere matches
ListBucket denied, GetObject worksbucket ARN missing from Resource
Policy accepted but no effectPrincipal ARN does not match the actual user
Condition never matcheskey 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

  1. Q1. A bucket policy grants a user s3:GetObject and s3:ListBucket with only `arn:aws:s3:::data/*` as the resource. What happens?

  2. Q2. A Deny statement written today constrains Allow statements added to the same bucket policy months later.

  3. 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.

  4. 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