CephCI · Security HardeningSecurity Hardening
Running a repeatable hardening audit
What you'll learn
- Build a repeatable audit
- Produce evidence rather than assertions
- Interpret and triage the findings
- Track remediation over time
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
An audit that produces a document is read once. An audit that produces comparable output every month is what shows whether posture is improving.
The audit
#!/bin/bash
# ceph-hardening-audit.sh — run from an admin host
set -u
echo "=== ceph hardening audit $(hostname -s) ==="
echo "--- cephx enforcement"
for k in auth_cluster_required auth_service_required auth_client_required; do
printf '%-24s %s\n' "$k" "$(ceph config get global "$k" 2>/dev/null)"
done
echo "--- wire modes"
for k in ms_cluster_mode ms_service_mode ms_client_mode ms_bind_msgr1; do
printf '%-24s %s\n' "$k" "$(ceph config get global "$k" 2>/dev/null)"
done
echo "--- monmap address families"
ceph mon dump 2>/dev/null | grep -oE 'v[12]:' | sort | uniq -c
echo "--- entities with unrestricted caps"
ceph auth ls --format json 2>/dev/null | python3 -c '
import sys,json
n = 0
for e in json.load(sys.stdin)["auth_dump"]:
if any("allow *" in v for v in e.get("caps", {}).values()):
print(" ", e["entity"]); n += 1
print(" total:", n)'
echo "--- networks"
printf '%-24s %s\n' public_network "$(ceph config get global public_network)"
printf '%-24s %s\n' cluster_network "$(ceph config get global cluster_network)"
echo "--- encrypted OSDs"
ceph osd metadata --format json 2>/dev/null | python3 -c '
import sys,json
d = json.load(sys.stdin)
enc = sum(1 for o in d if o.get("osd_objectstore") and o.get("bluestore_bdev_type"))
crypt = sum(1 for o in d if str(o.get("devices","")).find("dm-") >= 0)
print(" osds:", len(d), " with dm mapping:", crypt)'
echo "--- dashboard exposure"
ceph mgr services --format json 2>/dev/null | python3 -c '
import sys,json
for k, v in json.load(sys.stdin).items(): print(" %-12s %s" % (k, v))'
bash ceph-hardening-audit.sh > "audit-$(date +%Y%m%d).txt"
Per-host checks
#!/bin/bash
# run on each Ceph host
echo "=== host $(hostname -s) ==="
stat -c ' %a %U:%G %n' /etc/ceph/*.keyring 2>/dev/null
grep -E '^(PermitRootLogin|PasswordAuthentication)' /etc/ssh/sshd_config \
| sed 's/^/ /'
getenforce 2>/dev/null | sed 's/^/ selinux: /'
ss -ltn | awk 'NR>1 {print " listening: " $4}' | sort -u
ls -l /run/podman/podman.sock 2>/dev/null | sed 's/^/ /'
Interpreting findings
| Finding | Severity | Action |
|---|---|---|
auth_*_required not cephx | critical | fix immediately |
Entities with allow * beyond admin | high | narrow |
v1: in the monmap | medium | plan msgr1 removal |
Mode list includes crc | medium | plan strict secure |
| Admin keyring readable beyond root | high | fix permissions |
| No cluster network | low | design decision, record it |
| Dashboard on a broad interface | high | restrict |
Severity should reflect what the finding enables, not how easy it is
to fix.
Tracking over time
diff "audit-$(date -d '1 month ago' +%Y%m).txt" "audit-$(date +%Y%m%d).txt"
# a single posture number, for trend
grep -c 'allow \*' "audit-$(date +%Y%m%d).txt"
The value is the diff. A finding that appears in twelve consecutive
audits is a decision that was never made, and naming it as such is more
useful than repeating the finding.
Quiz
Knowledge check · 4 questions
Q1. Why should audit output be stored as comparable text rather than a written report?
Q2. Audit findings should be ranked by how quickly they can be remediated.
Q3. Build a hardening audit programme.
A team has run a one-off hardening review producing a document. They want it to be ongoing.
Q4. Which audit finding is critical severity, and why?
Passing score: 75%. Answers are checked in this browser.
Production discipline
Produce audit output as fixed-format dated text so each run is a diff — the diff is what answers whether posture is improving. Rank findings by what each enables rather than by remediation effort; ranking by effort leaves the real exposures permanently below the fold.
Cross-course references
- Kubernetes: CIS benchmark runs are valuable as a trend, not a snapshot
- Linux: audits ranked by effort systematically defer the expensive findings