Control Access & Quotas for COSI Buckets with CephObjectStoreUser (Ceph Driver)
This guide shows Kubernetes administrators how to combine CephObjectStoreUser (COSU), BucketClass/BucketClaim, and BucketAccessClass/BucketAccess to implement least-privileged access and quota enforcement for Ceph RGW-backed COSI buckets.
What you'll build
- A CephObjectStoreUser with explicit capabilities and optional per-user quotas;
- A BucketClass that tells the Ceph COSI driver which COSU credentials to use;
- One or more BucketClaims to provision buckets;
- Fine-grained, per-workload credentials using BucketAccessClass/BucketAccess (read-only, write-only, read-write), with optional anonymous read.
TOC
Prerequisites
- A healthy Ceph cluster with RGW and Rook installed.
- COSI plugins installed.
- Cluster admin privileges (to create cluster-scoped resources).
Step 1 — Create a CephObjectStoreUser (with capabilities & quotas)
CephObjectStoreUser is the service account the driver uses to perform bucket operations in RGW. It must live in the rook-ceph namespace and target your CephObjectStore.
Get the generated access keys (Rook creates a Secret for this user):
These COSU credentials are consumed by the driver (not by your apps) to create/delete buckets on your behalf.
Step 2 — Define a BucketClass bound to the CephObjectStoreUser
BucketClass instructs the driver which COSU Secret to use when provisioning buckets.
deletionPolicycontrols the bucket's physical lifecycle when aBucketClaimis deleted (DeletevsRetain).
Step 3 — Provision a bucket with BucketClaim
Create the bucket in your application namespace by referencing the BucketClass.
Wait until status.bucketReady: true and note status.bucketName for the actual RGW bucket name.
Step 4 — Issue least-privileged credentials with BucketAccessClass/BucketAccess
Define policy templates with BucketAccessClass and mint credentials per workload via BucketAccess. Supported policies: readonly, writeonly, readwrite. Anonymous read is available by setting parameters.anonymous: "true" (string).
Example BucketAccessClass (read-only)
Mint credentials with BucketAccess
The driver writes a Secret named in credentialsSecretName. Decode .data.BucketInfo (base64) to get secretS3.endpoint, accessKeyID, and accessSecretKey for your S3 client.
Tip: Issue distinct credentials per Deployment/Job to simplify rotation and revocation without disrupting other workloads.
Step 5 — Anonymous public read (optional)
If you need public static asset hosting:
Bind it with a BucketAccess to your BucketClaim. Once granted, objects are retrievable via unauthenticated HTTP GET (ensure network exposure as appropriate).
Step 6 — Quota control: where to enforce and how to change
Scope: The quotas block on CephObjectStoreUser applies per user and is enforced by RGW across all buckets owned by that user.
maxBuckets: upper bound on buckets the user can create/own.maxObjects: maximum number of objects the user can store (across buckets).maxSize: total logical size permitted for the user.
Update quotas by editing the COSU resource:
Design choice: Keep COSU quotas relatively tight to bound blast radius. Use least-privilege policies via BAC/BA to limit what a given set of application credentials can do within a bucket.
Operations & troubleshooting
- Namespace placement:
CephObjectStoreUserand its Secret must be inrook-ceph. App-level resources (BucketClaim,BucketAccess) should live in the app namespace. - Policy not applied: confirm
bucketAccessClassNameandparameters.policyin BAC (readonly|writeonly|readwrite). - Anonymous read fails: ensure
anonymous: "true"is a string, not boolean; verify endpoint exposure and HTTP access path (/<bucket>/<object>). - Can't find keys: check the
BucketAccessSecret and decode.data.BucketInfo. - Bucket stays not-ready: check controller/driver logs (e.g.
kubectl -n cpaas-system logs deploy/ceph-cosi-driver -c ceph-cosi-driver). - Rotation: create a new
BucketAccess, roll your workloads to the new Secret, then delete the old Secret/BA.
Cleanup
- Remove a workload credential by deleting its
BucketAccessand the referenced Secret. - Removing a bucket: delete the
BucketClaim(behavior followsBucketClass.deletionPolicy). If the backend refuses deletion because the bucket is not empty, delete objects first.