Skip to main content
RunBook Academy

CephCIV · Multi-Tenancy in PracticeMulti-Tenancy in Practice

RGW multi-tenancy in operation

Advanced⏱ ~18 minradosgw-adminceph

What you'll learn

  • Enable and read RGW usage accounting
  • Manage per-tenant access keys
  • Understand RGW quota consistency
  • Handle a tenant exceeding their quota

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

RGW tenancy is billed and audited more often than block or file tenancy, which makes its accounting the part that gets scrutinised.

Usage accounting

ceph config get client.rgw rgw_enable_usage_log
ceph config set client.rgw rgw_enable_usage_log true
Usage logging is off by default. Without it there is no per-user
operation record, and enabling it later does not backfill.
radosgw-admin usage show --uid='acme$acme-prod' --show-log-entries=false
{
    "summary": [{
        "user": "acme$acme-prod",
        "total": { "bytes_sent": 91827364, "bytes_received": 4736251,
                   "ops": 18422, "successful_ops": 18401 }
    }]
}
# per-user storage, which is separate from operation counts
radosgw-admin user stats --uid='acme$acme-prod' --sync-stats
radosgw-admin bucket stats --uid='acme$acme-prod' | python3 -c '
import sys,json
for b in json.load(sys.stdin):
    u = b.get("usage", {}).get("rgw.main", {})
    print("%-28s %10.2f GiB  %8d objects" %
          (b["bucket"], u.get("size_actual",0)/1024**3, u.get("num_objects",0)))'
--sync-stats recalculates from the bucket indices rather than reading
the cached figure, which is what makes a billing number defensible.

Key lifecycle

radosgw-admin key create --uid='acme$acme-prod' --key-type=s3 --gen-access-key
radosgw-admin user info --uid='acme$acme-prod' | python3 -c '
import sys,json
for k in json.load(sys.stdin).get("keys", []):
    print(k["access_key"])'
OLD_ACCESS_KEY=report.pdf
radosgw-admin key rm --uid='acme$acme-prod' --key-type=s3 \
  --access-key=${OLD_ACCESS_KEY}
A user can hold several access keys, which makes RGW key rotation
genuinely incremental: add the new key, move the tenant, remove the old.
That is a property cephx does not have.
radosgw-admin user suspend --uid='acme$acme-prod'
radosgw-admin user enable --uid='acme$acme-prod'

Quota consistency

radosgw-admin quota set --quota-scope=user --uid='acme$acme-prod' \
  --max-size=5T --max-objects=10000000
radosgw-admin quota enable --quota-scope=user --uid='acme$acme-prod'
ceph config get client.rgw rgw_bucket_quota_ttl
ceph config get client.rgw rgw_user_quota_bucket_sync_interval
RGW caches quota state, so a tenant can exceed a quota briefly before
enforcement catches up. The window is governed by those intervals.
SettingEffect
Shorter sync intervaltighter enforcement, more index reads
Longer sync intervallooser enforcement, less overhead
Defaultovershoot is possible and bounded by the interval
So an RGW quota is a soft ceiling by design. Sizing it with headroom
below the hard capacity limit is the correct response, not tuning the
interval to zero.

A tenant exceeding quota

radosgw-admin user stats --uid='acme$acme-prod' --sync-stats
radosgw-admin quota show --quota-scope=user --uid='acme$acme-prod'
The S3 client receives 403 QuotaExceeded on writes. Reads and deletes
continue, which lets the tenant recover by deleting.

Quiz

Knowledge check · 4 questions

  1. Q1. Why can an RGW tenant briefly exceed their quota?

  2. Q2. Enabling RGW usage logging today tells you nothing about what a tenant did last month.

  3. Q3. Rotate an RGW tenant's access key.

    A tenant's S3 access key may have been exposed. They have production workloads using it.

  4. Q4. Why use `--sync-stats` when reading RGW user statistics for billing?

Passing score: 75%. Answers are checked in this browser.

Production discipline

Rotate RGW keys incrementally — a user can hold several access keys at once, so add, migrate, verify, remove with no window where nothing works. Enable rgw_enable_usage_log before you need it; it does not backfill. Use --sync-stats for any figure that will be billed.

Cross-course references

  • Kubernetes: multiple valid credentials are what make rotation non-disruptive anywhere
  • Linux: cached enforcement trades exactness for throughput deliberately