CephXLVIII · RGW TroubleshootingRGW Troubleshooting
Working an AccessDenied to its source
What you'll learn
- Enumerate the mechanisms that can deny access
- Check each in the correct order
- Diagnose policy and ACL interactions
- Verify a grant actually works
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
AccessDenied is emitted by four independent mechanisms, and they
interact. Checking them in a fixed order — cheapest and most decisive
first — resolves it in minutes instead of by trial and error.
The four mechanisms
| Mechanism | Scope | Overrides |
|---|---|---|
| User suspension | everything the user does | everything |
| Bucket policy explicit Deny | the bucket | any Allow |
| Bucket policy Allow / no match | the bucket | default deny |
| Bucket and object ACLs | the bucket or object | policy may already have allowed |
| Subuser access level | the parent user’s whole scope | limits what the credential can do |
The order to check
1. Is the user suspended?
radosgw-admin user info --uid=analytics | jq '.suspended'
One field, and it overrides everything. Check it first.
2. Is there an explicit Deny in the bucket policy?
aws --endpoint-url $EP s3api get-bucket-policy --bucket data | jq -r '.Policy' | jq .
Look for "Effect": "Deny" and check whether its conditions match the
failing request. A deny cannot be overridden.
3. Does the policy grant what is being attempted?
Check both the action and the resource ARN. ListBucket needs the bucket
ARN; GetObject needs the object ARN.
4. Do the ACLs permit it?
aws --endpoint-url $EP s3api get-bucket-acl --bucket data
aws --endpoint-url $EP s3api get-object-acl --bucket data --key file.txt
Objects carry their own ACL, so an object uploaded by a different user may be inaccessible even where the bucket permits it.
5. Is the credential a subuser with a limiting access level?
radosgw-admin user info --uid=analytics | jq '.subusers'
The cross-user object case
aws --endpoint-url $EP s3api put-object --bucket shared --key f.txt --body f.txt \
--acl bucket-owner-full-control
When user A uploads to user B’s bucket, the object is owned by A by
default and B cannot read it despite owning the bucket. The
bucket-owner-full-control ACL at upload time is the fix, and a bucket
policy can require it:
{"Effect": "Deny", "Principal": "*", "Action": "s3:PutObject",
"Resource": "arn:aws:s3:::shared/*",
"Condition": {"StringNotEquals": {"s3:x-amz-acl": "bucket-owner-full-control"}}}
Verifying a grant
# as the granted credential, attempt the specific operation
AWS_ACCESS_KEY_ID=$K AWS_SECRET_ACCESS_KEY=$S \
aws --endpoint-url $EP s3api get-object --bucket data --key file.txt /tmp/out
# and confirm the denial still holds where it should
AWS_ACCESS_KEY_ID=$K AWS_SECRET_ACCESS_KEY=$S \
aws --endpoint-url $EP s3api get-object --bucket other --key file.txt /tmp/out
Quiz
Knowledge check · 4 questions
Q1. A bucket owner receives AccessDenied on an object in their own bucket, uploaded by another user. Why?
Q2. Checking user suspension should come first when investigating AccessDenied.
Q3. Resolve access failures in a shared bucket.
Several teams upload to a shared bucket. The bucket owner can list all objects but receives AccessDenied when reading objects uploaded by other teams. The bucket policy grants the owner full access.
Q4. Why do ACLs and bucket policies both exist rather than one replacing the other?
Passing score: 75%. Answers are checked in this browser.
Production discipline
Check the four denial mechanisms in order — suspension, explicit
deny, policy grant, ACLs — rather than guessing; the order is by cost and
decisiveness. Require bucket-owner-full-control on shared buckets
through a policy, since object ownership is the mechanism that most often
produces confusing denials.
Cross-course references
- Kubernetes: RBAC plus admission plus PodSecurity all denying independently is the same layered model
- Linux: POSIX permissions plus ACLs plus MAC labels each denying separately follows the same pattern