Zum Inhalt springen

mTLS: Wenn Services erst den Ausweis zeigen müssen

14. Juli 2026 durch
mTLS: Wenn Services erst den Ausweis zeigen müssen
Tom Ziegler

Ein TLS-Zertifikat auf dem Server ist nett – aber wenn jeder Client ungefragt reinspazieren darf, ist das eher Türsteher mit Augenklappe. Bei mTLS drehen wir den Spieß ein Stück weiter: Nicht nur der Server beweist seine Identität, auch der Client muss ein gültiges Zertifikat vorzeigen. Service A spricht also nur mit Service B, wenn beide sagen können: „Ja, ich bin wirklich ich.“ Klingt nach Paranoia. Ist aber produktive Paranoia.

Wir haben das im Test mit zwei kleinen Services nachgebaut: orders-service ruft payment-service auf. Ohne mTLS reicht ein gültiger DNS-Name und TLS. Mit mTLS braucht orders-service zusätzlich ein Client-Zertifikat, das vom payment-service akzeptiert wird.

Erstmal brauchen wir eine eigene kleine CA. Nicht für die große PKI-Weltherrschaft, sondern für interne Service-Zertifikate:

openssl genrsa -out ca.key 4096
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 \
-out ca.crt -subj "/CN=PLUTEX Internal Service CA"

Dann bekommt der Server sein Zertifikat:

openssl genrsa -out payment.key 2048
openssl req -new -key payment.key -out payment.csr \
-subj "/CN=payment-service.internal"
openssl x509 -req -in payment.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out payment.crt -days 365 -sha256

Und jetzt der wichtige Teil: der Client bekommt ebenfalls ein Zertifikat:

openssl genrsa -out orders.key 2048
openssl req -new -key orders.key -out orders.csr \
-subj "/CN=orders-service"
openssl x509 -req -in orders.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out orders.crt -days 365 -sha256

Auf Serverseite muss nun nicht nur TLS aktiv sein, sondern auch Client-Zertifikate müssen geprüft werden. Beispiel mit Nginx als Reverse Proxy vor dem payment-service:

server {
  listen 443 ssl;
  server_name payment-service.internal;
  ssl_certificate     /etc/nginx/certs/payment.crt;
  ssl_certificate_key /etc/nginx/certs/payment.key;
  ssl_client_certificate /etc/nginx/certs/ca.crt;
  ssl_verify_client on;
  location / {
    proxy_pass http://payment-backend:8080;
    proxy_set_header X-Client-Cert $ssl_client_s_dn;
  }
}

Der kleine Schalter mit großer Wirkung ist:

ssl_verify_client on;

Ohne gültiges Client-Zertifikat gibt es dann keinen Kaffee, sondern einen TLS-Handshake-Abbruch. Sehr befriedigend.

Test ohne Client-Zertifikat:

curl https://payment-service.internal

Ergebnis: scheitert. Gut so.

Test mit Client-Zertifikat:

curl https://payment-service.internal \
--cert orders.crt \
--key orders.key \
--cacert ca.crt

Jetzt klappt der Request – vorausgesetzt, Zertifikat, Key und CA passen zusammen. Wenn nicht, bekommst du OpenSSL-Fehlertexte, die aussehen wie aus einem Dämonenbeschwörungsbuch. Klassiker.

Wichtig im Betrieb: Zertifikate brauchen Lebenszyklen. Ablaufdaten, Rotation, Sperrung, Automatisierung. Wer Client-Zertifikate manuell per SCP verteilt, baut sich früher oder später ein Museum für kaputte Deployments. Besser: cert-manager in Kubernetes, Vault PKI, SPIFFE/SPIRE oder eine interne CA mit automatisierter Ausgabe.

Auch wichtig: mTLS ersetzt keine Autorisierung. Nur weil orders-service echt ist, darf er nicht automatisch alles. Identität ist Schritt eins. Danach kommen Policies: Welcher Service darf welchen Endpoint aufrufen?

Unser Fazit nach dem Selbstversuch: mTLS ist nicht kompliziert, aber gnadenlos präzise. Falscher CN, falsche CA, abgelaufenes Zertifikat – zack, Funkstille. Genau das ist der Punkt. Service-zu-Service-Kommunikation sollte nicht auf „wird schon intern sein“ basieren. Intern ist kein Sicherheitskonzept. Intern ist nur ein Ort, an dem Angreifer nach dem ersten Treffer besonders gerne weitermachen.

mTLS: Wenn Services erst den Ausweis zeigen müssen
Tom Ziegler 14. Juli 2026
Diesen Beitrag teilen