Vault als PKI rausgeworfen — eine Offline-CA-Hierarchie mit cert-manager

Vault als interne Zertifizierungsstelle war bequem und ein Single Point of Failure zugleich: Läuft Vault nicht, wird kein Cert mehr ausgestellt. Ich habe die PKI auf eine klassische Offline-Hierarchie umgestellt — Root und Intermediate-Key liegen air-gapped, eine kurzlebige Sub-CA lebt als cert-manager-ClusterIssuer im Cluster, und Name Constraints erzwingen, dass kein Blatt je außerhalb meiner internen Domains signiert wird. Ein staged Cutover ohne Trust-Lücke inklusive.

Lange hat Vault in meinem Lab die internen Zertifikate ausgestellt — eine PKI-Engine, ein cert-manager-ClusterIssuer namens vault, fertig. Bequem. Und ein Single Point of Failure mit Ansage: Ist Vault sealed, abgelaufen oder beim Bootstrap, stellt niemand mehr ein Cert aus. Genau dieses Henne-Ei hat mich schon einmal in eine Break-Glass-Recovery gezwungen. Also habe ich die PKI von Vault gelöst und auf das gestellt, wofür X.509 eigentlich gedacht ist: eine Offline-Hierarchie, deren teuerste Schlüssel nie online sind.

Drei Schichten für ein Secret — von pass über SOPS und Vault in den Pod

In einem öffentlichen GitOps-Repo darf nie ein Klartext-Secret liegen — und trotzdem muss jeder Workload an seine Passwörter kommen. Mein Lab löst das in drei klar getrennten Schichten: SOPS+PGP/age für die paar Bootstrap-Secrets, die vor Vault existieren müssen; Vault KV als Langzeitspeicher für alles Anwendungsnahe; und der External Secrets Operator, der daraus zur Laufzeit Kubernetes-Secrets materialisiert. Eine Tour durch den Lebensweg eines Geheimnisses.

Mein Lab ist ein öffentliches GitOps-Repo — über meinen Radicle -Seed-Node seed.this-is-fine.io kann es jeder klonen. Daraus folgt eine harte Regel: kein Klartext-Secret, niemals, nirgends in Git. Und trotzdem braucht jeder Workload im Cluster seine Passwörter, API-Tokens und Signing-Keys. Diesen Widerspruch löse ich in drei Schichten, von denen jede genau eine Aufgabe hat.

Im Beitrag über die pre-commit-Hooks ging es darum, wie ich verhindere, dass ein Secret versehentlich in Git landet. Hier geht es um den geplanten Weg: wie ein Secret absichtlich von meiner Maschine bis in einen Pod fließt, ohne je unverschlüsselt das Repo zu berühren.

Kein Klartext-Secret kommt durch — pre-commit, gitleaks und SOPS

Ein GitOps-Repo ist öffentlich, sobald man es vergisst. Drei Hooks sorgen dafür, dass ich gar nicht erst ein unverschlüsseltes Secret committen kann: gitleaks scannt auf Muster, ein SOPS-Hook verweigert Klartext in geschützten Pfaden, und ein lokaler Decrypt-Check stellt sicher, dass jede verschlüsselte Datei sauber entschlüsselt und alle Empfänger trägt.

Mein Lab-Repo ist öffentlich — abrufbar über meinen Radicle -Seed-Node seed.this-is-fine.io. Genau deshalb darf da nie ein Klartext-Secret hineinrutschen. Nicht „sollte nicht", sondern kann nicht: Drei pre-commit -Hooks fangen den Fehler ab, bevor er ein Commit-Objekt wird. Das ist die billigste Versicherung, die ich kenne — ein paar Zeilen YAML gegen einen Leak, den man nie ganz zurückholt.

Renovate als Dependency-Bot für ein GitOps-Monorepo

Mein Lab ist ein einziges Flux-Repository — Helm-Charts, Container-Images, Talos- und Kubernetes-Versionen, CLI-Pins in Dockerfiles und shell.nix. Renovate hält das alles aktuell, automerged das Unkritische und zwingt mich bei Ceph, Cilium und Vault zum Hinschauen. Hier ist, wie ich es scharf gestellt habe.

Mein Lab ist ein einziges Repository: ein GitOps-Monorepo, aus dem Flux mehrere Talos-Cluster reconciled. Alles, was eine Version trägt, steht darin — Helm-Charts, Container-Images, die Talos- und Kubernetes-Version, dazu CLI-Pins in einem Dockerfile und in shell.nix. Manuell halte ich das nicht aktuell. Das macht Renovate , und zwar so, dass es mir die langweiligen Bumps abnimmt und mich genau bei den drei, vier Dingen stoppt, bei denen ein blinder Merge teuer wäre.

Ceph auf vier ARM-Boards — das Speicher-Fundament unterm Lab

Fast jeder Lab-Artikel sagt beiläufig ceph-block oder ceph-filesystem — erklärt wurde es nie. Hier ist die Schicht darunter: Rook-Ceph, das die NVMe von vier RK1-Boards zu einem fehlertoleranten Speicher bündelt. Mit der echten CephCluster-Config, dem OSD-pro-NVMe-Mapping, den drei StorageClasses — und den Day-2-Kriegsgeschichten, wenn ein MON-Quorum oder eine OSD wegbricht.

In nahezu jedem Beitrag taucht es beiläufig auf: storageClass: ceph-block, eine RWO-PVC, ein copyMethod: Snapshot. Erklärt habe ich diese Schicht nie — dabei funktioniert ohne sie nichts. Das hier ist das Fundament: Rook -Ceph, das die NVMe-SSDs der Turing-Pi-/RK1-Boards zu einem fehlertoleranten Speicher zusammenfasst.