Cluster-Sicherheit
Der Cluster-Transport ist standardmäßig Plain-TCP ohne Authentifizierung — schnell, einfach, okay für ein privates Netzwerk. Nicht okay für irgendeinen Cluster, der eine unsichere Grenze überschreitet (öffentliches Internet, Multi-Tenant-Kubernetes, Cross-Region-Links ohne VPN).
Diese Seite behandelt das Produktions-Sicherheits-Setup für den Cluster-Transport.
Zwei Anliegen
Abschnitt betitelt „Zwei Anliegen“| Anliegen | Wie adressieren |
|---|---|
| Lauschangriff — Peer-to-Peer-Traffic lesbar für jeden auf der Leitung. | TLS auf dem Cluster-Transport. |
| Unautorisierte Joins — ein bösartiger Node verbindet sich + wird Cluster-Mitglied. | Shared-Secret-Auth am Handshake. |
Beide sollten zusammen aktiviert sein für jeden nach außen gerichteten Cluster.
TLS aktivieren
Abschnitt betitelt „TLS aktivieren“import { TcpTransport, NodeAddress, Cluster } from 'actor-ts';import fs from 'node:fs';
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, // Peer-Certs verifizieren },);
await Cluster.join(system, { host: '10.0.0.5', port: 2552, seeds: [...], transport,});Die TLS-Einstellungen:
cert+key— Zertifikat + Private Key dieses Nodes.ca— vertrauenswürdiges CA-Bundle. Nutze, um die Zertifikate der Peers zu verifizieren.rejectUnauthorized: true— Handshakes scheitern lassen, wenn das Cert des Peers nicht voncasigniert ist.
Mit rejectUnauthorized: true + einer geteilten CA wird der Cluster
mutually authenticated — jede Verbindung verlangt ein Peer-Cert,
das von der vertrauenswürdigen CA signiert ist.
Zertifikatsmanagement
Abschnitt betitelt „Zertifikatsmanagement“Drei Ansätze:
Self-signed für Entwicklung
Abschnitt betitelt „Self-signed für Entwicklung“openssl req -x509 -newkey rsa:4096 -keyout cluster.key -out cluster.crt -days 365 -nodes -subj "/CN=actor-ts"Nutze dasselbe Cert + denselben Key auf jedem Node. Okay für Dev / Staging. Nicht in Produktion einsetzen.
Private CA für Produktion
Abschnitt betitelt „Private CA für Produktion“# CA einmalig erstellen:openssl req -x509 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 3650 -nodes -subj "/CN=actor-ts-ca"
# Per-Node-Certs, signiert von der CA:openssl req -newkey rsa:4096 -keyout node-1.key -out node-1.csr -nodes -subj "/CN=node-1"openssl x509 -req -in node-1.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out node-1.crt -days 365Jeder Node bekommt sein eigenes Cert; alle vertrauen der CA. Certs zu rotieren ist pro Node und erfordert kein Anfassen der CA.
cert-manager / Vault für K8s
Abschnitt betitelt „cert-manager / Vault für K8s“Für K8s-Deployments nutze cert-manager mit einer internen CA oder HashiCorp Vault. Certs werden als Volume-Secrets gemountet; Rotation übernimmt der Cert-Manager.
# Beispiel cert-manager-Certificate-Spec: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: 720hDer Pod mountet das Secret als Files; der Actor liest sie.
Shared-Secret-Auth (optionale Schicht)
Abschnitt betitelt „Shared-Secret-Auth (optionale Schicht)“Über TLS hinaus kann das Framework ein Shared Secret im Cluster-Handshake verlangen:
new TcpTransport(self, log, tlsOpts, /* maxFrame */ undefined, { sharedSecret: process.env.CLUSTER_SECRET,});Jeder Node braucht dasselbe Secret. Falsche Secrets scheitern am Handshake; böse Akteure ohne Secret können nicht joinen.
Mit TLS + mTLS bereits aktiv bringt das Shared Secret Hosenträger-und-Gürtel — fängt die Insider-Bedrohung einer kompromittierten privaten CA ab, bei der ein Angreifer mit gestohlenem Cert sonst nicht blockiert würde. Für die meisten Deployments reicht mTLS allein.
Cluster-Port mit Firewall absichern
Abschnitt betitelt „Cluster-Port mit Firewall absichern“Cluster-Port (2552) — nur intern:- Pods können auf 2552 mit Pods reden- nicht via Service / Ingress exponiert- LoadBalancer sieht ihn nieSelbst mit TLS + Auth: exponiere den Cluster-Port eng. Eine NetworkPolicy in K8s:
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: actor-ts-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 sich gegenseitig auf Port 2552
erreichen.
Bedrohungsmodell
Abschnitt betitelt „Bedrohungsmodell“| Bedrohung | Gegenmaßnahme |
|---|---|
| Netzwerk-Lauschangriff | TLS |
| Man-in-the-Middle | TLS + Zertifikatsprüfung |
| Unautorisierter Cluster-Join | mTLS + Shared Secret |
| Insider mit gestohlenem Cert | Shared Secret + Cert-Rotation |
| Kompromittierter Pod im Cluster | Application-Level-Auth (hier nicht abgedeckt) |
Der Cluster-Transport handhabt Transport-Level-Sicherheit. Application-Level-Anliegen (Auth zwischen spezifischen Actors, Per-Tenant-Isolation) bleiben dein Job — der Cluster-Transport ist in sich selbst vertrauenswürdig.
Per-Deployment-Rezept
Abschnitt betitelt „Per-Deployment-Rezept“import { TcpTransport, Cluster } from 'actor-ts';
const tlsSettings = { cert: fs.readFileSync(process.env.TLS_CERT_PATH!), key: fs.readFileSync(process.env.TLS_KEY_PATH!), ca: fs.readFileSync(process.env.TLS_CA_PATH!), rejectUnauthorized: true,};
const transport = new TcpTransport(self, log, tlsSettings);
await Cluster.join(system, { host, port, seeds, transport,});Env-Vars tragen Pfade; cert-manager / Vault mounten die Files. Code bleibt umgebungs-generisch.
Wohin als nächstes
Abschnitt betitelt „Wohin als nächstes“- Operations-Überblick — Produktions-Readiness-Checkliste.
- TLS everywhere — TLS für HTTP + Broker + Journals.
- Master-Key-Rotation — Rotation von Data-at-rest-Verschlüsselungsschlüsseln.
- Transports — das zugrundeliegende Transport-Interface.
- Konfiguration — die HOCON-Keys für TLS-Einstellungen.