Cluster-Sicherheit
Der Cluster-Transport ist standardmäßig unauthentifiziertes Plain-TCP. In Ordnung innerhalb eines privaten Netzwerks, in dem jeder Host bereits vertrauenswürdig ist. Nicht in Ordnung irgendwo sonst — öffentliches Internet, Multi-Tenant-K8s, nicht vertrauenswürdige Vermittler.
Diese Seite ist die How-to zur Absicherung des Cluster-Transports. Für den operativen Kontext siehe Operations — Cluster-Sicherheit.
Was abzusichern ist
Abschnitt betitelt „Was abzusichern ist“| Bedrohung | Maßnahme |
|---|---|
| Lauschangriff | TLS auf dem Cluster-Transport |
| MITM (Abfangen + Verändern) | TLS + Zertifikatsprüfung |
| Unautorisierter Join (jeder mit Port-Zugriff kann joinen) | mTLS (zertifikatsbasierte Peer-Authentifizierung) |
| Kompromittiertes Zertifikat (für gestohlene Identität ausgestellt) | Cert-Rotation + Revocation |
| Replay eines mitgeschnittenen Gossip-Frames | TLS, dazu die Sequence pro Sender, die jeder Cluster durchsetzt |
| Ein Mitglied spricht im Payload für einen anderen Node | Framework-Handler halten die im Payload behauptete Identität gegen den Peer der Verbindung — siehe was eine Replica ihren Peers glaubt |
mTLS ist das, was die letzte Zeile überhaupt trägt, und nicht etwas, das sie doppelt: eine Behauptung gegen den Peer der Verbindung zu halten, ist erst dann etwas wert, wenn dieser Peer authentifiziert ist.
Diese Zeile gilt auch für das In-Process-Worker-Mesh
— den einzigen Pfad, auf dem sie früher nicht hielt: Der WorkerBroker
adressiert jeden Frame auf den MessagePort um, über den er hereinkam,
ein Worker kann also nicht die Adresse eines Geschwisters in from
schreiben. Dafür ist nichts zu konfigurieren, und kein mTLS trägt es —
der Host vergibt jedem Worker seine Adresse und hält dessen Port, die
Bindung ist also strukturell statt authentifiziert.
TLS aktivieren
Abschnitt betitelt „TLS aktivieren“import { TcpTransport, NodeAddress, Cluster, ClusterOptions } from 'actor-ts/cluster';
const transport = new TcpTransport( NodeAddress.parse('actor-ts://my-app@10.0.0.5:2552'), system.log, { cert: fs.readFileSync('./tls/cluster.crt'), key: fs.readFileSync('./tls/cluster.key'), ca: fs.readFileSync('./tls/ca.crt'), rejectUnauthorized: true, },);
const clusterOptions = ClusterOptions.create() .withHost(host) .withPort(port) .withSeeds(seeds) .withTransport(transport);await Cluster.join( system, clusterOptions,);TLS-gewrapptes TCP, alles-oder-nichts pro Cluster. Jeder Node verwendet dieselbe TLS-Konfiguration; gemischtes Plain + TLS funktioniert nicht.
Cert-Layout
Abschnitt betitelt „Cert-Layout“Das Minimum:
- Ein CA-Cert + privater Schlüssel (zum Signieren von Per-Node-Certs).
- Ein Per-Node-Cert + privater Schlüssel (von der CA signiert).
# CA erzeugen (einmalig):openssl req -x509 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 3650 -nodes \ -subj "/CN=actor-ts-ca"
# Per-Node-Cert:openssl req -newkey rsa:4096 -keyout node-1.key -out node-1.csr -nodes \ -subj "/CN=node-1.cluster.local"
openssl x509 -req -in node-1.csr -CA ca.crt -CAkey ca.key -CAcreateserial \ -out node-1.crt -days 365Jeder Node lädt:
- Sein eigenes Cert + Key.
- Das CA-Cert (um die Certs der Peers zu verifizieren).
Mutual TLS
Abschnitt betitelt „Mutual TLS“{ cert: fs.readFileSync('./tls/this-node.crt'), key: fs.readFileSync('./tls/this-node.key'), ca: fs.readFileSync('./tls/ca.crt'), rejectUnauthorized: true, // ← Peers ohne gültiges Cert ablehnen}Mit rejectUnauthorized: true + einer gemeinsamen CA verlangt
jede Verbindung von beiden Seiten ein gültiges, von der CA
signiertes Cert. Keine anonymen Joins; kein Plain-Text-Fallback.
cert-manager + Secrets ist das Standardmuster:
# Cert verwaltet von cert-manager:apiVersion: cert-manager.io/v1kind: Certificatemetadata: name: actor-ts-clusterspec: secretName: actor-ts-cluster-tls issuerRef: name: actor-ts-ca kind: ClusterIssuer commonName: actor-ts dnsNames: - actor-ts-cluster.svc duration: 8760h renewBefore: 720h
---# Pod mounted das TLS-Secret:apiVersion: v1kind: Podspec: containers: - name: app volumeMounts: - name: tls mountPath: /etc/tls readOnly: true volumes: - name: tls secret: secretName: actor-ts-cluster-tlscert-manager erneuert Certs automatisch; Pods laden sie beim Neustart neu. Für Cert-Rotation ohne Downtime nutze einen Rolling Restart, nachdem neue Certs bereitliegen.
Firewall
Abschnitt betitelt „Firewall“apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: cluster-internal-onlyspec: podSelector: matchLabels: app: actor-ts ingress: - from: - podSelector: matchLabels: app: actor-ts ports: - protocol: TCP port: 2552Nur app=actor-ts-Pods können Port 2552 erreichen. Kombiniert mit
mTLS sind das zwei unabhängige Schichten.
Performance-Auswirkung
Abschnitt betitelt „Performance-Auswirkung“TLS fügt ~5-15 % Overhead pro Byte auf dem Transport hinzu. Für typische Actor-Nachrichten (kleine Payloads, moderater Durchsatz) unbemerkbar. Für hochfrequenten Cluster-Verkehr messbar, aber selten der Flaschenhals.
Wann NICHT aktivieren
Abschnitt betitelt „Wann NICHT aktivieren“Wohin als Nächstes
Abschnitt betitelt „Wohin als Nächstes“- Operations — Cluster-Sicherheit — operativer Walk-Through.
- TLS überall — TLS über andere Komponenten hinweg.
- Transports — die Schnittstelle des Cluster-Transports.
- Konfiguration — die TLS-HOCON-Keys.
