TYPO3 auf Kubernetes unter IT-Grundschutz, Teil 14: Das Referenz-Chart
Dreizehn Teile lang ging es um einzelne Bausteine. Jeder Teil hat eine Frage beantwortet: wie das Image aussieht, wie der Code signiert wird, wie Pods miteinander sprechen. Offen blieb, wie das alles zusammenpasst.
Dieser Teil gibt die Antwort als Code. Das Referenz-Chart typo3-kubernetes-chart setzt die Bausteine der Serie in einem Helm-Chart um. Es ist Open Source unter der Apache-Lizenz 2.0 und klein genug, um es an einem Nachmittag zu lesen.
Teil 14 von 14 der Serie „TYPO3 auf Kubernetes unter IT-Grundschutz“. Die Übersicht aller Teile steht in Teil 1.
01 — Was im Chart steckt
Das Chart installiert TYPO3 mit den Bausteinen, die zur Anwendung gehören. Die Datenbank bringt es bewusst nicht mit. Sie läuft extern, als verwalteter Dienst oder mit einem eigenen Operator.
- TYPO3 auf FrankenPHP als Deployment mit Service und Ingress, der Code schreibgeschützt eingebunden (Teil 2, Teil 8).
- Code als signiertes Artefakt: cosign prüft, oras lädt, beides in initContainern (Teil 3).
- Valkey als Speicher für Cache und Sessions, mit TLS und Client-Zertifikaten. Die Anbindung in TYPO3 übernimmt die eigene Konfiguration (Teil 5).
- Eine eigene CA pro Mandant über cert-manager, mit einstellbarer Zertifikatslaufzeit.
- Secrets über den External Secrets Operator, im Pod nur als Dateien (Teil 7).
- NetworkPolicies mit Default-Deny und einer Freigabe pro Verbindung (Teil 6).
- Autoscaling, PodDisruptionBudget und Verteilung über Zonen und Knoten (Teil 9, Teil 12).
- Scheduler als CronJob und ein optionales Backup der Datenbank (Teil 10).
Drei Profile zum Vergleichen
Im Verzeichnis ci/ liegen drei Beispielwerte. minimal ist die kleinste lauffähige Installation. full schaltet jede Option ein. ha zeigt mehrere TYPO3-Replicas mit Verteilung über Zonen. Valkey läuft darin weiter als einzelne Instanz, die Datenbank liegt außerhalb des Charts. Für echte Hochverfügbarkeit müssen beide ausfallsicher betrieben werden (Teil 12). Die Pipeline rendert alle drei und prüft sie gegen die Kubernetes-Schemas. Wer das Chart anpasst, sieht so sofort, was sich ändert.
Was ein Mandant mitbringt
Das Chart liefert kein TYPO3-Image. Es erwartet ein Laufzeit-Image mit PHP und FrankenPHP, aber ohne Anwendungscode. Den Code bringt das signierte Artefakt. Die Konfiguration kommt über Umgebungsvariablen, Zugangsdaten kommen als Dateien. Die README beschreibt diesen Vertrag Variable für Variable, samt einer kurzen additional.php, die ihn umsetzt.
02 — Der Weg des Codes in den Pod
Bevor PHP eine Zeile ausführt, laufen drei initContainer nacheinander. Der erste prüft die Signatur des Artefakts. Der zweite lädt es in ein leeres Volume. Der dritte richtet TYPO3 gegen die Datenbank ein. Scheitert einer, startet der Pod nicht.
Wer die SBOM-Attestierung aus Teil 3 auch im Cluster prüfen will, schaltet code.verify.attestation ein. Dann kommt ein vierter initContainer dazu.
helm install tenant-a oci://ghcr.io/ohartwig/charts/typo3-kubernetes-chart \
--version 0.2.0 --namespace tenant-a \
--set image.repository=registry.example.org/tenant-a/typo3-runtime \
--set code.artifact=registry.example.org/tenant-a/typo3-code@sha256:... \
--set-file code.verify.publicKey=cosign.pub \
--set ingress.host=typo3.example.org
Digest statt Tag
Das Artefakt wird über seinen Digest referenziert, nicht über ein Tag. Ein Tag kann sich zwischen Prüfung und Download bewegen. Dann prüft cosign andere Bytes, als oras lädt. Mit einem Digest sehen beide Schritte dasselbe. Das Chart warnt bei der Installation, wenn trotzdem ein Tag gesetzt ist.
Ein Setup zur Zeit
Das Setup läuft in jedem Pod. Das muss so sein, denn extension:setup legt auch die öffentlichen Assets in das Volume des jeweiligen Pods. Ein einzelner Job könnte das nicht für alle Replicas erledigen. Starten aber mehrere Pods gleichzeitig, etwa bei einer Neuinstallation, würden sie parallel am Schema arbeiten.
Deshalb hält das Setup eine Advisory-Sperre in der Datenbank. Ein Pod richtet ein, die anderen warten. Die Sperre gehört zur Verbindung. Stirbt ein Pod mitten im Setup, fällt sie mit ihm weg, und nichts muss aufgeräumt werden.
Auch das Chart ist signiert
Wer eine signierte Lieferkette empfiehlt, sollte das Chart nicht unsigniert ausliefern. Jede Version wird beim Release über Sigstore signiert, ohne einen eigenen Schlüssel. Die Signatur ist an den Release-Workflow des Repositorys gebunden. Zum Prüfen braucht es cosign 3, denn cosign 2 findet das neue Signaturformat nicht:
cosign verify ghcr.io/ohartwig/charts/typo3-kubernetes-chart:0.2.0 \
--certificate-identity-regexp '^https://github\.com/ohartwig/typo3-kubernetes-chart/\.github/workflows/release\.yml@refs/tags/v' \
--certificate-oidc-issuer token.actions.githubusercontent.com03 — Rechte, Netz und Schlüssel
Jeder Container im Chart läuft mit denselben Einschränkungen. Das gilt auch für die initContainer, den Scheduler und den Test-Pod. Kein Root, ein schreibgeschütztes Dateisystem, keine Capabilities, das Seccomp-Profil RuntimeDefault. Service-Account-Tokens werden nicht eingebunden, denn TYPO3 spricht nie mit der Kubernetes-API. Damit besteht das Chart den Pod-Security-Standard restricted.
Default-Deny und einzelne Freigaben
Eine NetworkPolicy sperrt zunächst den ganzen Namespace. Danach bekommt jede Verbindung eine eigene Freigabe: Ingress zu TYPO3, TYPO3 zu Valkey, TYPO3 zur Datenbank, die initContainer zur Registry. Valkey selbst darf gar nichts nach außen. Die Freigaben zu Datenbank und Registry erlauben ab Werk jede Adresse auf dem jeweiligen Port. Das ist Absicht, denn das Chart kennt deine Adressen nicht. Das Einengen gehört zur Installation.
mTLS ohne Service Mesh
cert-manager baut pro Namespace eine eigene CA auf. Ab Werk stellt das Chart Zertifikate mit 30 Tagen Laufzeit aus, ein vorsichtiger Startwert. Bei hohem Schutzbedarf senkt internalTls.duration die Laufzeit auf die 24 Stunden aus Teil 5. Valkey verlangt Client-Zertifikate und TLS 1.3. Ein Sidecar lädt das Server-Zertifikat nach der Rotation neu, ohne Neustart. Auch die Datenbank kann das Client-Zertifikat prüfen und einem Benutzer zuordnen. Das ist das explizite Modell, ohne zusätzliche Control Plane.
Secrets nur als Dateien
Das Chart rendert keinen einzigen geheimen Wert. Es enthält nur einen Verweis auf den Secret-Store. Der External Secrets Operator holt die Werte und legt sie als Kubernetes-Secret ab. Im Pod erscheinen sie als Dateien mit dem Modus 0440, nie als Umgebungsvariable. Ein helm get values verrät deshalb nichts.
04 — Warum kein Operator?
Die naheliegende Frage nach dreizehn Teilen: Warum ein Helm-Chart und kein TYPO3-Operator? Ein Operator ist ein eigenes Programm im Cluster. Er beobachtet Ressourcen und greift ein, wenn ihr Zustand abweicht. Das klingt nach mehr Automatisierung. Aus Sicht der Sicherheit bringt es aber auch mehr Angriffsfläche.
Was ein Operator kostet
APP.4.4.A16 empfiehlt bei hohem Schutzbedarf sogar Operatoren für besonders kritische Anwendungen. Wer davon abweicht, begründet es, etwa so:
- Rechte: Ein Operator braucht dauerhaft Schreibrechte auf Deployments und Secrets, oft über mehrere Namespaces. Genau solche Rechte begrenzt APP.4.4.A3.
- Eigener Code: Er ist Software mit eigenem Release-Zyklus. Auch sie braucht Scans, Signaturen und Updates. Jede Lücke darin trifft alle Mandanten.
- Weniger Nachvollziehbarkeit: Was ein Operator tut, steht in seinem Code, nicht im Repository. Ein Chart dagegen rendert zu Manifesten, die jeder vor dem Deployment prüfen kann.
Chart und GitOps decken den Lebenszyklus einer TYPO3-Installation weitgehend ab. Installation, Update und Rollback sind deklarativ. Setup und Migrationen laufen im initContainer, der Scheduler als CronJob. Was an Logik übrig bleibt, passt in einen Job.
Wann sich ein Operator lohnen würde
Die Grenze liegt dort, wo sich der Lebenszyklus nicht mehr deklarativ beschreiben lässt. Etwa bei sehr vielen Mandanten, die per API entstehen und wieder verschwinden. Oder bei Abläufen, die auf Zustände in TYPO3 selbst reagieren müssen. Für eine überschaubare Zahl von Installationen, die ein Team über Git pflegt, trifft das selten zu. Dort ist ein Operator eher Last als Hilfe.
Bewusst nicht enthalten
Das Chart lässt weg, was sich von Plattform zu Plattform unterscheidet: die Datenbank, Speicher für fileadmin, die WAF, Monitoring und den CVE-Scan. Der Scan gehört in die Pipeline vor der Signatur, wie in Teil 4 beschrieben. Der Cluster prüft nur noch die Signatur.
Bezug zum IT-Grundschutz
- SYS.1.6.A6 und SYS.1.6.A12 Sichere Images und ihre Verteilung: Code nur mit gültiger Signatur, referenziert per Digest.
- SYS.1.6.A8 Sichere Speicherung von Zugangsdaten und SYS.1.6.A20 Absicherung von Konfigurationsdaten: Secrets nur als Verweis, im Pod als Datei.
- SYS.1.6.A15 Limitierung der Ressourcen: Requests und Limits für jeden Container.
- SYS.1.6.A17 Ausführung von Containern ohne Privilegien: kein Root, keine Capabilities, Seccomp RuntimeDefault.
- SYS.1.6.A23 Unveränderlichkeit der Container: schreibgeschütztes Root-Dateisystem.
- APP.4.4.A4 Separierung von Pods und APP.4.4.A7 Separierung der Netze: Pod Security
restrictedund NetworkPolicies. - APP.4.4.A6 Initialisierung von Pods: Signaturprüfung, Download und Setup in initContainern.
- APP.4.4.A9 Nutzung von Kubernetes Service-Accounts: kein eingebundenes Token.
- APP.4.4.A16 Verwendung von Operatoren: bewusst kein Operator, Begründung siehe oben. Chart und GitOps machen jeden Schritt vor dem Deployment prüfbar.
- APP.4.4.A18 Mikro-Segmentierung und APP.4.4.A19 Hochverfügbarkeit: eine Freigabe pro Verbindung, PDB und Verteilung über Zonen.
- CON.1 Kryptokonzept: eigene CA pro Mandant, begrenzte, einstellbare Laufzeiten, TLS 1.3.
Häufige Fragen
Ist das Chart für den Produktivbetrieb gedacht?+
Es ist eine Referenz, kein Produkt. Die Voreinstellungen sind auf Sicherheit ausgelegt, und die Pipeline prüft jede Änderung. Vor dem Einsatz solltest du die Netzfreigaben einengen, eigene Ressourcenwerte setzen und die Installation in einer Testumgebung durchspielen. Wer bereits eine Plattform betreibt, übernimmt oft eher einzelne Templates als das ganze Chart.
Warum ist keine Datenbank enthalten?+
Eine Datenbank braucht Speicher, Replikation und Backups mit eigenem Ablauf. Das leistet ein verwalteter Dienst oder ein spezialisierter Operator besser als ein Anwendungs-Chart. Das Chart verbindet sich über TLS mit der Datenbank und kann ihr ein Client-Zertifikat vorlegen. Ein optionaler Job erstellt regelmäßig einen Dump.
Geht es auch ohne cert-manager und External Secrets Operator?+
Teilweise. Statt des External Secrets Operators kann ein selbst angelegtes Secret dienen. cert-manager lässt sich abschalten. Dann entfallen aber mTLS zu Valkey und das Client-Zertifikat für die Datenbank. Bei erhöhtem Schutzbedarf ist das keine gute Wahl.
Darf ich das Chart anpassen und weitergeben?+
Ja. Das Chart steht unter der Apache-Lizenz 2.0. Du darfst es verwenden, ändern und weitergeben, auch in kommerziellen Projekten. Verbesserungen sind als Pull Request willkommen. Sicherheitsprobleme meldest du bitte vertraulich an die Adresse in der SECURITY.md.
Fazit
Das Referenz-Chart fasst die Serie in gut einem Dutzend Templates zusammen. Signierter Code, gehärtete Container, mTLS, Netzregeln und Secrets ohne Git greifen dort ineinander. Jede Entscheidung ist im Code kommentiert und in dieser Serie begründet. Ein Operator würde daran wenig verbessern. Er brächte vor allem Rechte und eigenen Code hinzu.
Das Chart steht auf GitHub. Die Übersicht aller Teile steht in Teil 1: Welche Bausteine wirklich greifen. Zurück zu Teil 13: TYPO3 selbst härten.
Ich bringe dein TYPO3 sicher auf Kubernetes. Mit dem Chart als Ausgangspunkt.
Anpassung an deine Plattform, Signaturkette in der Pipeline, Netzfreigaben, Secrets und mTLS. Dazu die Zuordnung zu den Grundschutz-Bausteinen für dein Audit.
Plattform-Betrieb statt Beratung auf Papier: Auf Wunsch betreibe ich dein TYPO3 dauerhaft mit und liefere die Nachweise.
Über den Autor

Kai Ole Hartwig
Programmiert seit 2002 – autodidaktisch gelernt, 2012 mit KO-Web selbständig gemacht. Über 100 Projekte, Fokus auf Security, Performance, Automatisierung und Qualität. Heute freiberuflich: DevSecOps-Beratung, Schulungen und Softwareentwicklung.
