Ceph Squid und aktuelle Proxmox-VE-Stände machen sichtbar, wenn CephX-Keys noch mit dem alten aes-Key-Typ arbeiten oder wenn alte Cipher weiterhin erlaubt sind. Das ist zunächst nicht automatisch ein Storage-Ausfall. Ein Cluster kann Daten sauber replizieren, alle OSDs up/in haben und trotzdem CephX-Warnungen anzeigen.
Kritisch wird die Migration an zwei Stellen: bei laufenden Consumern und bei externen Clients. Ein reiner Proxmox-/Ceph-Cluster lässt sich mit dem Proxmox-Migrationshelper vergleichsweise geordnet migrieren. Wenn aber zusätzlich ein Kubernetes- oder OKD-Cluster über Rook und Ceph-CSI angebunden ist, müssen dessen CephX-Identitäten und Kubernetes-Secrets separat betrachtet werden.
Dieser Beitrag beschreibt einen real durchgeführten Ablauf auf einem Proxmox-VE-/Ceph-Cluster mit Ceph Squid 19.2.6 und einem extern angebundenen OKD/Rook-Cluster. Er ist keine allgemeingültige Copy-and-paste-Anleitung. Der Output des Proxmox-Migrationshelpers und der tatsächliche Consumer-Bestand des eigenen Clusters bleiben die maßgebliche Entscheidungsgrundlage.
Hinweis: Nicht blind in Produktion kopieren. Vor jedem Schritt müssen Ceph-Health, Backups, externe Consumer, Kubernetes-Secrets, Versionskompatibilität und ein Wiederherstellungsweg geprüft sein.
Beispielsetup
Im beschriebenen Projekt bestand die Umgebung aus:
Proxmox-VE-Cluster mit 4 Nodes
Ceph Squid 19.2.6
4 MONs
4 MGRs
4 MDS-Daemons
16 OSDs
CephFS und RBD
externem OKD/Kubernetes-Cluster
Rook CephCluster im External-Modus
aktivem Ceph-CSI RBD-Provisioning
vorhandenen CephFS-Credentials im Rook-External-Setup
Die externen CephX-Identitäten umfassten unter anderem:
client.csi-rbd-nodeclient.csi-rbd-provisionerclient.csi-cephfs-nodeclient.csi-cephfs-provisionerclient.healthchecker
Das Ziel war ein vollständig migrierter Zustand:
auth_service_cipher: aes256kauth_allowed_ciphers: aes256kauth_preferred_cipher: aes256k
Am Ende stand Ceph auf:
HEALTH_OK16/16 OSD up/in209 PGs active+clean
1. Ausgangszustand prüfen
Vor jeder Rotation steht eine nüchterne Bestandsaufnahme:
ceph -sceph versionspveceph auth status
Wichtig sind dabei nicht nur CephX-Warnungen, sondern der Gesamtzustand:
MON-Quorum vorhanden?
OSDs up und in?
PGs active+clean?
MDS und CephFS gesund?
Welche CephX-Warnungen sind aktiv?
Welche Clients sind noch mit altem Key-Typ oder alten Sessions sichtbar?
Zu Beginn können Warnungen wie diese auftreten:
AUTH_INSECURE_CLIENT_KEY_TYPEAUTH_INSECURE_KEYS_ALLOWEDAUTH_INSECURE_KEYS_CREATABLEAUTH_INSECURE_ROTATING_SERVICE_KEY_TYPEAUTH_INSECURE_SERVICE_KEY_TYPEAUTH_INSECURE_SERVICE_TICKETS
Diese Meldungen bedeuten nicht automatisch, dass Daten degradiert sind. Sie sagen zunächst, dass CephX-Keys, Service-Tickets oder erlaubte Cipher noch nicht im gewünschten Zustand sind. Trotzdem müssen sie ernst genommen werden, weil ein späteres zu frühes Abschalten von aes alte Consumer aussperren kann.
2. Alle Ceph-Daemons zuerst aktualisieren
Die Migration sollte erst starten, wenn MON, MGR, MDS und OSDs auf einer Version laufen, die aes256k unterstützt. Im Projekt wurde Ceph von 19.2.3 auf 19.2.6 aktualisiert.
Nach Upgrade, Dienstneustarts oder Rolling-Reboots erneut prüfen:
ceph versionspveceph auth status
Wichtig war insbesondere:
Monitor quorumaes256k capable: yes
Bei Rolling-Reboots wurde jeweils nur ein Proxmox-Node neu gestartet. Nach jedem Node wurde der Ceph-Zustand erneut geprüft. Erst wenn Quorum, OSDs und PGs wieder sauber waren, kam der nächste Node dran.
3. Proxmox-Migrationshelper verwenden
Der zentrale Einstiegspunkt ist der Proxmox-Helper:
/usr/share/pve-manager/migrations/pve-cephx-rotate-service-keys --verbose
Ohne --apply arbeitet der Helper im Dry-Run. Das ist gewollt. Der Output zeigt, was Proxmox ändern würde, welche Schritte blockiert sind und welche Consumer noch betrachtet werden müssen.
Im konkreten Ablauf plante der Helper unter anderem:
Rotation von MGR-Keys
Rotation von MDS-Keys
Rotation von OSD-Keys
Umstellung der Service-Tickets
temporäres noout
Monitor-Elections
Eine besonders wichtige Warnung betrifft OSD-Lockbox-Keys:
Never rotate a 'client.osd-lockbox' key by hand
Diese Warnung ist ernst gemeint. OSD-Lockbox-Keys hängen nicht nur in der Ceph-Auth-DB, sondern auch an lokalen Metadaten. Wer sie manuell mit ceph auth rotiert, riskiert Inkonsistenzen. Der Helper hält Auth-DB und lokale Metadaten konsistent.
4. Service-Keys migrieren
Wenn der Dry-Run keine Blocker meldet:
/usr/share/pve-manager/migrations/pve-cephx-rotate-service-keys --apply
Danach prüfen:
ceph -spveceph auth status/usr/share/pve-manager/migrations/pve-cephx-rotate-service-keys
Ein gewünschtes Zwischenresultat ist:
PASS: Every service key uses 'aes256k',and so do the service tickets.
Erst danach lohnt sich der Blick auf Cluster-Keys, Bootstrap-Keys und Clients.
5. Cluster-Keys, Bootstrap- und OSD-Lockbox-Keys
Im realen Ablauf gab der Helper für die clusterinternen Keys den nächsten Schritt vor:
/usr/share/pve-manager/migrations/pve-cephx-rotate-service-keys \--apply --rotate-cluster-keys
Darunter fallen nicht nur einfache Client-Keys. Relevant sind unter anderem:
Bootstrap-Keys
client.crash
OSD-Lockbox-Keys
weitere clusterverwaltete Identitäten
Die OSD-Lockbox-Keys sind besonders kritisch. Der Helper aktualisiert nicht nur CephX-Einträge, sondern auch die zugehörigen lokalen Metadaten. Deshalb ist „einfach alle Keys rotieren“ keine sichere Beschreibung dieses Schritts.
6. client.admin ist besonders
client.admin verdient eine eigene Betrachtung. Im Projekt zeigte der Dry-Run:
/usr/share/pve-manager/migrations/pve-cephx-rotate-service-keys \--rotate-admin-key --verbose
mehr als 200 laufende client.admin-Sessions.
Das bedeutet nicht, dass mehr als 200 VMs laufen müssen. QEMU/RBD-Clients können mehrere Ceph-Verbindungen öffnen, und eine laufende VM hält bestehende Ceph-Sessions weiter offen. Die Zahl der Sessions entspricht also nicht eins zu eins der Zahl der VMs.
Die Rotation erfolgt gestaged:
/usr/share/pve-manager/migrations/pve-cephx-rotate-service-keys \--apply --rotate-admin-key
Dabei bleibt der alte Key temporär gültig, während der neue Key verteilt wird. Proxmox-Keyring-Kopien werden aktualisiert. Bestehende Sessions können weiterleben; neue Sessions müssen bereits mit dem neuen Key aufgebaut werden. Erst wenn alle Consumer wirklich refreshed sind, darf der alte Key final entfernt werden.
7. CephFS-Mount kann den client.admin-Refresh blockieren
Im Projekt war der CephFS-Mount auf:
/mnt/pve/cephfs
busy. Diagnose:
fuser -vm /mnt/pve/cephfslsof +D /mnt/pve/cephfs
Die Ursache waren laufende VMs mit eingelegten ISO-Dateien direkt aus CephFS:
/mnt/pve/cephfs/template/iso/...
Die Lösung war nicht, VMs hart zu stoppen. Stattdessen wurden die ISO-Dateien aus den virtuellen CD-ROM-Laufwerken entfernt. Beispiel:
qm set <VMID> --ide2 none,media=cdrom
Der konkrete Slot muss vorher geprüft werden. Nicht jede VM verwendet ide2. Entscheidend ist, dass keine laufende VM mehr ein ISO direkt aus dem CephFS-Mount offen hält.
Danach erneut:
lsof +D /mnt/pve/cephfs
Wenn der Mount nicht mehr busy ist, den Helper erneut ausführen.
8. Laufende QEMU/RBD-Sessions refreshen
Nach dem CephFS-Refresh blieben im Beispiel knapp 200 alte client.admin-Sessions. Diese wurden durch Live-Migration der VMs refreshed:
qm migrate <VMID> <TARGET_NODE> --online
Eine Live-Migration reicht in diesem Kontext, weil auf dem Zielnode ein neuer QEMU-Prozess entsteht und dessen Ceph-Verbindungen mit dem neuen Key aufgebaut werden.
Für größere Umgebungen ist ein einmaliges Skript sinnvoll, das:
laufende VMs erfasst
jede VM genau einmal migriert
erfolgreiche VMIDs in einer State-Datei speichert
Fehler separat protokolliert
Zielnodes anhand aktueller Last oder VM-Anzahl auswählt
nach jeder Migration den CephX-Status prüft
Eine einfache generische Skizze:
#!/usr/bin/env bashset -euo pipefailSTATE=/root/cephx-refreshed-vms.txttouch "$STATE"chmod 600 "$STATE"for vmid in $(qm list | awk 'NR>1 && $3 == "running" {print $1}'); doif grep -qx "$vmid" "$STATE"; thencontinueficurrent_node="$(hostname)"target_node="<choose-target-node>"echo "Migrating VM ${vmid} from ${current_node} to ${target_node}"qm migrate "$vmid" "$target_node" --onlineecho "$vmid" >> "$STATE"/usr/share/pve-manager/migrations/pve-cephx-rotate-service-keysdone
Das ist bewusst nur ein Gerüst. In Produktion muss die Zielnode-Auswahl, Fehlerbehandlung und Wartungslogik zur Umgebung passen.
9. client.admin final bestätigen
Wenn der Helper meldet:
Ready for confirmation: client.admin
dann erst:
/usr/share/pve-manager/migrations/pve-cephx-rotate-service-keys \--apply --confirm-all-clients-refreshed
Vorher müssen auch externe Kopien von client.admin berücksichtigt werden. Das können manuelle Keyring-Kopien, alte Automatisierungen, Backup-Jobs oder andere Integrationen sein.
10. Externe Rook-/OKD-Consumer
Der wichtigste Unterschied zum reinen Proxmox-Cluster: Ein externer Rook-Cluster verwendet eigene CephX-Identitäten. Im Projekt waren das:
client.csi-rbd-nodeclient.csi-rbd-provisionerclient.csi-cephfs-nodeclient.csi-cephfs-provisionerclient.healthchecker
Diese Keys ändert der Proxmox-Helper bewusst nicht automatisch. Im Helper-Output tauchte sinngemäß auf:
Left to whoever manages the client that reads them
Das ist korrekt. Proxmox kennt die in Kubernetes gespeicherten Secrets nicht. Eine CephX-Rotation auf Ceph-Seite ist erst dann vollständig, wenn auch die zugehörigen Kubernetes-Secrets im Consumer-Cluster synchronisiert sind.
11. Rook External Cluster identifizieren
Im OKD-/Kubernetes-Cluster:
oc -n rook-ceph get cephclusteroc get storageclassoc -n rook-ceph get secrets
Im Projekt:
CephCluster EXTERNAL=trueStorageClass rook-ceph-blockProvisioner rook-ceph.rbd.csi.ceph.com
Die RBD-Secrets waren:
rook-csi-rbd-noderook-csi-rbd-provisioner
mit:
userIDuserKey
Wichtig ist der Gleichlauf: CephX-User auf der Ceph-Seite und userKey im Kubernetes-Secret müssen zusammenpassen. Keine Keys in Tickets, Chat, Git oder Logs kopieren.
Vor einer Änderung an Kubernetes-Secrets sollte geprüft werden, ob das Secret durch GitOps oder einen Controller verwaltet wird:
oc -n rook-ceph get secret <SECRET> -o json | jq '.metadata | {ownerReferences, annotations, labels}'
Besonders wichtig sind ownerReferences, ArgoCD-Tracking-Labels und die Annotation kubectl.kubernetes.io/last-applied-configuration. Wenn diese Annotation alte Secret-Werte enthält, kann sie später versehentlich wieder ausgespielt oder in Backups/Exports sichtbar werden. In unserem Ablauf wurden solche Metadaten vor Änderungen geprüft und veraltete last-applied-Annotationen gezielt entfernt.
12. Besonderheit: ceph-csi-Version und AES256K
Ein realer Stolperstein trat direkt bei einem externen RBD-Key auf. Nach Rotation eines RBD-Keys schlug Provisioning zunächst fehl:
connecting failed: rados: ret=-22, Invalid argument
Der Fehler ließ sich auf die AES256K-Kompatibilität des eingesetzten CSI-Stacks eingrenzen. Nach dem Update auf einen kompatiblen Rook-/ceph-csi-Stand funktionierte Provisioning wieder. Der belegte Stand im OKD-Cluster war:
Rook Operator: v1.20.7Ceph-CSI: v3.17.1
Zusätzlich wurden passende CSI-Sidecars verwendet, unter anderem:
csi-provisioner v5.2.0csi-attacher v4.8.1csi-resizer v1.13.2csi-snapshotter v8.2.1csi-node-driver-registrar v2.13.0
Vor der Rotation externer CSI-Keys sollte deshalb geprüft werden, ob die eingesetzte Rook-/ceph-csi-Version den neuen Key-Typ unterstützt. Sonst rotiert man den Key korrekt, sperrt aber den Kubernetes-Consumer aus.
13. RBD-Provisioner-Key rotieren
Auf Ceph-Seite zuerst sichern und dann rotieren:
umask 077ceph auth get client.csi-rbd-provisioner \> /root/client.csi-rbd-provisioner.before-aes256k.keyringceph auth rotate --key-type=aes256k client.csi-rbd-provisioner \> /root/client.csi-rbd-provisioner.aes256k.keyringchmod 600 /root/client.csi-rbd-provisioner*.keyring
Der neue Key wird anschließend sicher in das Kubernetes-Secret übernommen:
rook-csi-rbd-provisioner
Dabei nur den Secret-Wert aktualisieren, nicht den userID. Nach ceph auth rotate ist der alte Key nicht mehr der aktuelle Key; das Secret-Update muss deshalb unmittelbar und kontrolliert folgen, bevor neue Provisioner-Verbindungen getestet werden.
Wichtig: Nach einer Rotation darf nicht aus einer alten lokalen Datei, einem alten Chat-Snippet oder einem vorherigen Secret zurückkopiert werden. Der aktuell gültige Key wird direkt aus Ceph ermittelt:
ceph auth get-key client.csi-rbd-provisioner
Wenn versehentlich zweimal rotiert wird, ist der erste neue Key bereits wieder veraltet. Dann muss exakt der aktuell gültige Key synchronisiert werden, nicht der Key aus dem ersten Rotationsversuch.
Nach dem Update wurde der RBD-Provisioner refreshed und ein neuer PVC provisioniert. Erst wenn ein neuer PVC Bound wird, ist der Provisioner-Pfad praktisch getestet.
14. RBD-Node-Key rotieren
Analog:
ceph auth rotate --key-type=aes256k client.csi-rbd-node
Kubernetes-Secret:
rook-csi-rbd-node
Danach den Node-Plugin-Pfad praktisch testen:
neuer PVC
Pod mountet PVC
Datei schreiben
Datei lesen
Pod löschen
Pod neu erstellen
Datei erneut lesen
Im Projekt war dieser End-to-End-Test erfolgreich. Das ist wichtig: Provisioning alleine beweist noch nicht, dass Node-Stage, Mount und Pod-Zugriff funktionieren.
15. Aktive Sessions kontrollieren
Der funktionierende Weg zur Session-Kontrolle war:
ceph tell mon.<MON-NAME> sessions --format json-pretty
Nicht verwenden:
ceph sessions
Bei mehreren MONs kann ceph tell mon.* sessions mehrere JSON-Ausgaben produzieren. Das ist nicht zwingend direkt jq-freundlich. Besser pro MON prüfen oder die Ausgabe bewusst aufteilen.
Im Projekt konnten aktive RBD-Sessions mit:
auth_key_type: aes256k
beobachtet werden.
Fehlende aktive Sessions sind kein Beweis dafür, dass eine Identity nicht mehr benötigt wird. Provisioner-Accounts können nur bei neuen PVCs erscheinen, CephFS-Credentials können vorbereitet sein, obwohl aktuell keine CephFS-PVCs existieren, und Healthchecker-Zugriffe hängen vom Rook-Operator-Verhalten ab.
16. CephFS-CSI-Keys
Auch diese Accounts wurden rotiert:
client.csi-cephfs-provisionerclient.csi-cephfs-node
Die zugehörigen Secrets:
rook-csi-cephfs-provisionerrook-csi-cephfs-node
wurden aktualisiert.
Im konkreten Cluster gab es zu diesem Zeitpunkt:
keine CephFS-StorageClass
keine CephFS-PVCs
keine laufenden CephFS-CSI-Pods
Trotzdem wurden die Credentials synchronisiert, weil sie Teil des External-Rook-Setups waren. „Aktuell keine aktive Session“ bedeutet nicht automatisch „Credential wird nicht mehr benötigt“. Löschen wäre ein eigener Architekturentscheid, kein Nebenschritt einer Key-Migration.
17. client.healthchecker
Der letzte externe Key war:
client.healthchecker
Er lag im Secret:
rook-ceph-mon
mit den Feldern:
ceph-usernameceph-secret
Der entschlüsselte Username war:
client.healthchecker
Rook verwendet diesen User für External-Cluster-Health- und Monitor-Zugriffe. Das bestätigten die Operator-Logs:
will use "client.healthchecker" to check health and monitor status
Nach Rotation:
ceph auth rotate --key-type=aes256k client.healthchecker
wurde ausschließlich ceph-secret im Secret rook-ceph-mon aktualisiert.
Unmittelbar danach meldete der Rook-CephCluster kurz:
HEALTH_ERRRADOS permission denied
Der laufende Operator hatte den alten Healthchecker-Zugang noch aktiv. Danach war ein gezielter Operator-Refresh nötig:
oc -n rook-ceph rollout restart deployment/rook-ceph-operator
Nach dem Restart war rook-ceph-external wieder:
Synced / Healthy
und die CephCluster-Warnungen reduzierten sich auf die globalen Cipher-Einstellungen.
Vor dem Patch wurde geprüft, dass das Secret nicht über OwnerReferences oder ArgoCD automatisch zurückgesetzt wird. Wenn GitOps dieses Secret verwaltet, muss der neue Wert in der zuständigen Quelle angepasst werden, sonst kann der Cluster den korrekten Key später wieder verlieren.
18. Extern rotierte Keys wieder mit dem Proxmox-Helper abgleichen
Da die fünf externen Keys außerhalb des Proxmox-Skripts rotiert wurden, meldete der Helper, dass einzelne Keys außerhalb des Skripts geändert wurden.
Für jeden externen Consumer wurde zuerst eine Messung angestoßen:
/usr/share/pve-manager/migrations/pve-cephx-rotate-service-keys \--confirm-clients-refreshed <CLIENT> --apply
Beim ersten Lauf kam erwartungsgemäß sinngemäß:
not accepting ... yetcomplete measurement is now recorded
Dieses erste FAIL ist in diesem Kontext nicht automatisch ein Fehlerzustand des Clusters. Der Helper hat für diesen externen Consumer noch keine vollständige Messung und zeichnet sie zunächst auf. Erst nach vollständiger Messung aller relevanten externen Consumer kann der Dry-Run anzeigen, dass die Bestätigung möglich ist.
Wenn der Helper full inventory unavailable meldet, ist die Aussage ebenfalls begrenzt: Dann kann der Helper nicht den gesamten Consumer-Bestand sicher bewerten. In diesem Fall darf man den finalen Lockdown nicht allein aus Teilinformationen ableiten.
Nach der ersten Messung für alle fünf Clients meldete der Dry-Run:
Ready for confirmation:client.csi-cephfs-node,client.csi-cephfs-provisioner,client.csi-rbd-node,client.csi-rbd-provisioner,client.healthchecker
Erst dann war der Helper bereit, die Consumer als refreshed zu bestätigen.
19. AES endgültig deaktivieren
Hinweis: Wichtig: Den finalen Cipher-Lockdown erst ausführen, wenn der Proxmox-Helper ihn nach vollständiger Messung selbst vorschlägt und alle externen Consumer nachweislich mit den neuen Keys arbeiten.
Erst jetzt gab der Helper den finalen Befehl vor:
/usr/share/pve-manager/migrations/pve-cephx-rotate-service-keys \--apply \--confirm-all-clients-refreshed \--restrict-ciphers
Ab diesem Punkt werden alte aes-Keys tatsächlich abgewiesen. Wer externe Consumer übersehen hat, kann sie damit aus Ceph aussperren.
Der erwartete Abschluss:
PASS: only the 'aes256k' cipher is allowed for authentication nowPASS: Cephx migration is complete. Authentication and new keys use only 'aes256k'.
20. Finaler Status
Abschlussprüfung:
pveceph auth statusceph -sceph health detail
Final:
Cephx health checksnone activeauth_service_cipher: aes256kauth_allowed_ciphers: aes256kauth_preferred_cipher: aes256k
und:
HEALTH_OK
Im Beispielsetup:
mon: 4 daemons in quorumosd: 16 up / 16 inmds: healthy209 PGs active+clean
21. Recovery-Journal nicht sofort löschen
Der Helper arbeitet mit einem Journal:
/etc/pve/priv/cephx-key-migration.json
Diese Datei kann Recovery-Informationen und frühere Keys enthalten. Deshalb:
Dateirechte schützen
nicht veröffentlichen
nicht in Repos kopieren
nicht unkontrolliert in weniger geschützte Backups legen
erst nach abgeschlossener Access-Verifikation gemäß Proxmox-Dokumentation bereinigen
22. Lessons Learned
Die wichtigsten Punkte aus dem Ablauf:
Zuerst alle Ceph-Daemons auf einen kompatiblen Stand bringen.
Helper-Dry-Runs ernst nehmen.
OSD-Lockbox-Keys nie manuell rotieren.
client.admin benötigt Consumer-Refresh.
Live-Migration eignet sich gut, um QEMU/RBD-Sessions zu refreshen.
CephFS kann durch eingelegte ISO-Dateien busy bleiben.
Externe Rook-/CSI-Keys werden nicht automatisch durch Proxmox gepflegt.
Kubernetes-Secrets müssen unmittelbar mit den CephX-Keys synchronisiert werden.
Vor AES256K-Rotation externer CSI-Keys die ceph-csi-Kompatibilität prüfen.
Provisioning- und Mount-Tests praktisch durchführen.
aes erst ganz am Ende deaktivieren.
Den finalen --restrict-ciphers-Schritt erst ausführen, wenn der Helper ihn nach vollständiger Messung vorschlägt.
23. Sicherheits-Hinweise
Hinweis: Do not copy these commands blindly into production.
Vor jedem Schritt prüfen:
Ceph health
Backups
Consumer-Liste
externe Cluster
Kubernetes-Secrets
Versionskompatibilität
Maintenance-Fenster
Wiederherstellbarkeit
Monitoring und Alarmierung
Die wichtigste Fehlerklasse ist nicht die Rotation selbst, sondern ein übersehener Consumer. Wer alte externe Consumer übersieht und aes zu früh deaktiviert, kann diese Consumer von Ceph aussperren.
Fazit
Die eigentliche CephX-Migration im Proxmox-Cluster ist nur ein Teil der Arbeit. Entscheidend wird es bei externen Consumern wie Rook und Ceph-CSI. Erst wenn deren Credentials aktualisiert, Consumer refreshed und Storage-Funktionen praktisch getestet wurden, darf der alte Cipher abgeschaltet werden.
In diesem Projekt war der finale Zustand sauber: nur aes256k erlaubt, Ceph HEALTH_OK, alle OSDs up/in, alle PGs active+clean und der externe Rook-/OKD-Consumer wieder Synced / Healthy.






