Zum Inhalt springen
Deutsch

TLS everywhere

Produktions-sicher heißt TLS auf jeder Netzwerkoberfläche. Jede Komponente des Frameworks hat ihre eigene TLS-Konfiguration; diese Seite ist der Katalog, wo TLS zu aktivieren ist und welches Cert-Material jede Komponente braucht.

import { TcpTransport, Cluster, ClusterOptions } from 'actor-ts';
const transport = new TcpTransport(self, 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);

Mutually authenticated TLS zwischen Cluster-Nodes. Siehe Cluster-Sicherheit für die vollständige Diskussion.

Jedes Feld hier nimmt das Zertifikatsmaterial selbst entgegen, niemals einen Pfad darauf — deshalb liest das Beispiel die Dateien selbst ein. Nichts im Transport greift auf das Dateisystem zu, und weder Bun noch Node noch Deno akzeptiert in diesen Feldern einen Dateinamen.

cert und key sind auf einem Listener nur gemeinsam gültig. Ein tls-Objekt mit nur einem von beiden brachte den Listener bisher zu dem Schluss „kein TLS”, und er lauschte im Klartext — während dieselbe Konfiguration weiterhin über TLS hinauswählte. Der Cluster bildete sich also, und nichts sah falsch aus. Diese Kombination wird jetzt beim Bind abgelehnt; ein so fehlkonfigurierter Knoten degradiert damit nicht mehr still, sondern scheitert laut.

Nicht überspringen — auch in internen Netzwerken gilt Defense in Depth.

import { HttpExtensionId } from 'actor-ts';
const http = system.extension(HttpExtensionId);
await http.newServerAt('0.0.0.0', 8443)
.useBackend(new FastifyBackend({
https: {
cert: fs.readFileSync('./tls/http.crt'),
key: fs.readFileSync('./tls/http.key'),
},
}))
.bind(routes);

Für HTTPS auf der Anwendungsebene. Oft am Load Balancer terminiert stattdessen — in K8s übernimmt Service/Ingress TLS, die App spricht intern Plain-HTTP. Wählen je nach Form deiner Infrastruktur.

import { managementRoutes, FastifyBackend } from 'actor-ts';
const { routes } = managementRoutes(system, cluster);
// TLS is a property of the HTTP backend — Fastify's `https` option.
const tlsBackend = new FastifyBackend({
https: {
cert: fs.readFileSync('./tls/mgmt.crt'),
key: fs.readFileSync('./tls/mgmt.key'),
},
});
await system.http(8558, { backend: tlsBackend }).bind(routes);

Der Management-Server ist standardmäßig nur intern — aber TLS hilft trotzdem:

  • Schützt vor lateraler Bewegung in einem kompromittierten Netzwerk.
  • Wird von manchen Compliance-Regimen unabhängig von der Netzwerk-Topologie verlangt.

Jeder Broker-Actor hat seine eigenen TLS-Knöpfe:

const kafkaOptions = KafkaOptions.create()
.withBrokers(['kafka-1:9093'])
.withSsl(true)
.withSasl({
mechanism: 'scram-sha-512',
username: process.env.KAFKA_USER!,
password: process.env.KAFKA_PASS!,
});
new KafkaActor(kafkaOptions);
const mqttOptions = MqttOptions.create()
.withBrokerUrl('mqtts://mqtt.example.com:8883')
.withCredentials(process.env.MQTT_USER, process.env.MQTT_PASS);
new MqttActor(mqttOptions);

mqtts://-URL-Schema. Cert-Verifizierung folgt den Defaults des zugrundeliegenden mqtt-Pakets.

const amqpOptions = AmqpOptions.create().withUrl('amqps://rabbitmq.example.com:5671');
new AmqpActor(amqpOptions);
// amqplib nutzt URL-Parameter für die TLS-Konfiguration

amqps://-URL-Schema.

const natsOptions = NatsOptions.create().withServers(['nats://nats.example.com:4222']);
new NatsActor(natsOptions);
// mTLS-Cert-Material (ca / cert / key) wird an die zugrundeliegende
// nats-Verbindung übergeben — z. B. via Connect-Optionen / URL des Treibers.

mTLS via das tls-Objekt — üblich für Produktions-NATS.

const redisStreamsOptions = RedisStreamsOptions.create().withUrl('rediss://redis.example.com:6380');
new RedisStreamsActor(redisStreamsOptions);
// das `rediss://`-Schema aktiviert TLS auf der Verbindung

rediss://-URL-Schema (beachte das doppelte s).

const grpcClientOptions = GrpcClientOptions.create()
.withEndpoint('orders.example.com:50051')
.withCredentials({
kind: 'tls',
rootCerts: fs.readFileSync('./tls/ca.crt'),
});
new GrpcClientActor(grpcClientOptions);

Für Mutual TLS cert + key ergänzen.

const webSocketClientOptions = WebsocketClientOptions.create().withUrl('wss://realtime.example.com/feed');
new WebsocketClientActor(webSocketClientOptions);

wss://-URL-Schema. Cert-Verifizierung folgt den TLS-Defaults der Runtime.

Nicht zutreffend — lokaler Datei-Zugriff. TLS nicht anwendbar.
const cassandraJournalOptions = CassandraJournalOptions.create()
.withContactPoints(['cass-1.example.com:9042'])
.withClient(clientWithMtls);
new CassandraJournal(cassandraJournalOptions);
// mTLS-Cert-Material (cert / key / ca) wird auf dem via withClient()
// übergebenen cassandra-driver-Client konfiguriert

Cassandra-Cluster laufen in Produktion typischerweise mit mTLS.

const s3ObjectStorageOptions = S3ObjectStorageOptions.create().withRegion('eu-west-1');
const objectStorageDurableStateStoreOptions = ObjectStorageDurableStateStoreOptions.create().withBackend(new S3ObjectStorageBackend(s3ObjectStorageOptions));
new ObjectStorageDurableStateStore(objectStorageDurableStateStoreOptions);
// S3 nutzt per Default HTTPS

Cloud-Object-Storage (S3, GCS, Azure Blob) nutzt immer TLS. Keine Konfiguration nötig außer dem Endpoint.

Drei Muster in K8s-Produktion:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: actor-ts-cluster
spec:
secretName: actor-ts-cluster-tls
issuerRef:
name: actor-ts-ca
kind: ClusterIssuer
commonName: actor-ts
dnsNames: [actor-ts-cluster.svc]
duration: 8760h
renewBefore: 720h

cert-manager erneuert Certs automatisch vor Ablauf. Die meisten Produktions-K8s-Setups nutzen ihn.

Vault Agent läuft als Sidecar; zieht Certs in das Pod-Filesystem; erneuert automatisch. Nützlich, wenn du schon HashiCorp Vault hast.

Für Nicht-K8s-Umgebungen geplante Cron-Jobs, die frische Certs aus einer internen CA ziehen + die betroffenen Services neu starten. Funktioniert, erfordert aber sorgfältige operative Disziplin.

ca: fs.readFileSync('./tls/ca.crt'),

Die meisten internen Setups: eine CA, signiert alle Client- + Server-Certs. Die Cert-Verifizierung braucht das CA-Cert auf beiden Enden.

Cloud-managed Certificates (Let’s Encrypt, AWS ACM): nutze öffentliche CA-Bundles — in den meisten Runtimes bereits vorhanden. Kein expliziter ca nötig.