Skip to content
← Blog
Technical field note
5 min read

How to Secure Ceph RGW Buckets Without Relying on Luck

There is no single “secure bucket” switch. Safe buckets come from the endpoint, identity, policy, encryption, versioning, logging and recovery controls working together.

Operator note: Ceph RGW features and supported policy/API behavior vary by release. Check the documentation for your deployed version before turning an example into production policy.

To secure S3 buckets on Ceph RGW properly, treat it as three layers:

  1. Harden the RGW endpoint
  2. Use least-privilege identities and bucket policies
  3. Turn on data-protection features per bucket

Here’s the practical baseline.

1) Secure the RGW endpoint first

Never expose RGW over plain HTTP. Use HTTPS only. Ceph’s RGW supports TLS with the Beast frontend, and cephadm documents HTTPS setup for RGW services. Also, Ceph’s encryption docs explicitly note that requests involving server-side encryption must use HTTPS so secrets are not sent in plaintext.

Do this:

  • Terminate TLS on RGW itself or on a trusted reverse proxy/load balancer
  • Disable/avoid plaintext listeners
  • Restrict inbound access with firewall rules to trusted networks, apps, or gateways
  • Keep Ceph on a supported, patched release because RGW security fixes do land in point releases and past RGW vulnerabilities have required upgrades.

2) Do not use broad S3 credentials

Use separate users/roles per app, not shared cluster-wide access keys. Ceph RGW supports accounts, users, IAM-style policies, and roles; account users start with no permissions by default, which is exactly what you want for least privilege. Temporary credentials via roles/STS are preferable to long-lived static keys where your app stack can support them.

Good pattern

  • One app = one IAM user or role
  • One environment = separate credentials
  • Prefer temporary creds for workloads
  • Rotate long-lived keys regularly
  • Never let applications use the account root identity except for administration

3) Block public access by policy, not by assumption

Ceph RGW supports bucket policies through standard S3 operations. Use them to explicitly deny public access unless a bucket is intentionally public.

Baseline rule:

  • No wildcard Principal: "*" unless the bucket is intentionally public
  • No anonymous read/write
  • No bucket ACL sprawl; prefer bucket policy + IAM policy over ad hoc ACLs

A strong design is:

  • Identity policy grants an app access only to its bucket/prefix
  • Bucket policy adds guardrails, such as denying insecure transport, denying deletes, or restricting to certain principals

4) Enforce encryption at rest

Ceph RGW supports server-side encryption, including SSE with managed keys and SSE-KMS integrations; Ceph also documents KMIP-backed KMS integration for SSE-KMS.

Best practice

  • Require encryption on every object
  • Prefer SSE-KMS when you need tighter key control, auditability, or separation of duties
  • Use separate keys per environment or data class
  • Restrict who can use KMS keys

Why this matters: bucket compromise is less damaging when raw object data is encrypted and key access is separately controlled.

5) Enable versioning on important buckets

Ceph RGW supports S3 bucket versioning. This is one of the most useful controls against accidental overwrite, delete, and many ransomware-like operational failures.

Use versioning for: backups, logs, artifacts, and user-generated content you cannot easily recreate.

Without versioning, a delete or overwrite is final at the bucket layer.

6) Use Object Lock for immutable data

Ceph RGW supports S3 Object Lock and retention/legal hold APIs. On current docs, Ceph also notes newer behavior allowing PutObjectLockConfiguration on an existing versioning-enabled bucket in newer releases, while older behavior required object lock at bucket creation time.

Use Object Lock for: backups, audit logs, compliance archives, and anything you must make WORM-like.

Important detail: Object Lock depends on versioning. In older RGW behavior, you had to create the bucket with object lock enabled; newer releases relaxed this. So check your exact Ceph release before designing the rollout.

7) Keep CORS extremely narrow

RGW has had a past CORS-related vulnerability, and in general CORS is a common bucket exposure point. Keep allowed origins, methods, and headers as tight as possible.

Do this:

  • exact origins only, not *, for sensitive buckets
  • only needed methods (GET, PUT, etc.)
  • minimal exposed headers
  • separate browser-facing buckets from private app buckets

8) Turn on bucket logging and auditability

Ceph documents bucket logging, including the option for the log bucket itself to use object lock/retention.

Good pattern

  • send access logs to a separate dedicated log bucket
  • restrict write/read permissions tightly
  • enable retention or object lock on log buckets
  • monitor for anonymous access, policy changes, and delete spikes

9) Separate tenants, buckets, and prefixes cleanly

Do not build a multi-tenant design where many unrelated apps share one broad bucket and one broad credential.

Safer pattern

  • separate accounts or users per team/app
  • separate buckets per sensitivity class
  • separate prefixes only when bucket split is impractical
  • give each principal only the prefix it truly needs

This limits blast radius when one credential is leaked.

10) Prefer explicit deny guardrails

On sensitive buckets, add explicit deny statements for things you never want:

  • deny requests not using TLS
  • deny deletes except backup/admin roles
  • deny object uploads without encryption headers
  • deny access outside approved principals

This is usually more reliable than relying only on allows.

11) Patch level matters

This is not optional. Ceph publishes security advisories and multiple RGW fixes have shipped in point releases. Running old RGW releases is a real security risk.

A baseline I would be comfortable starting from

For a production private bucket on RGW, I’d set this as the default:

  • HTTPS only
  • Dedicated IAM user/role per app
  • No public bucket policy
  • Least-privilege access to one bucket or one prefix
  • Server-side encryption required
  • Versioning enabled
  • Object Lock enabled for backups/logs/critical data
  • Narrow CORS or none
  • Access logging enabled
  • Regular key rotation
  • Ceph kept on supported patched release

Mistakes worth checking twice

  • Using one access key for many apps
  • Leaving buckets private “by convention” with no explicit policy guardrails
  • No versioning on backup buckets
  • Enabling permissive CORS
  • Exposing RGW over HTTP internally because “it’s only inside the network”
  • Treating Ceph RGW root/admin credentials like normal app credentials

The short version

Properly securing Ceph RGW S3 buckets means: HTTPS + least-privilege IAM + deny-public bucket policies + encryption + versioning + object lock where needed + logging + patching.

Keep policy examples release-specific

RGW supports a subset of the S3 policy language and that subset can differ by release. Verify the actions and condition keys you depend on against the Ceph bucket-policy documentation.