mTLS Spring Boot konfigurieren: Anleitung für 2026

mTLS Spring Boot konfigurieren ohne Keystore-Chaos: SSL Bundles für Server, RestClient und Integrationstests mit Spring Boot 4.1. Plus die Frage, wann die Anwendung die falsche Ebene dafür ist.

25 Sep.. 2026 | DevOps & Security

Inhaltsverzeichnis

Pexon Consulting | 8 Min. Lesezeit | 28.07.2026


TL;DR

mTLS in Spring Boot konfigurierst du seit Version 3.1 über SSL Bundles statt über selbstgebaute SSLContext-Beans. Sechs Zeilen YAML für den Server, eine Zeile für den Client. Pexon Consulting baut solche Zero-Trust-Strecken als Cloud- und KI-Dienstleister mit 80 Mitarbeitern in Deutschland. Typischer Aufwand pro Dienst: zwei Tage statt zwei Wochen.

Vor SSL Bundles Mit SSL Bundles
Konfiguration eigene SSLContext-Bean, 60+ Zeilen Java 6 Zeilen YAML
Zertifikatsformat JKS-Konvertierung per keytool PEM direkt nutzbar
Rotation Neustart der Anwendung reload-on-update: true
Testbarkeit Mock-Server ohne TLS echtes mTLS im Integrationstest

Warum Keystores der eigentliche Schmerz sind

Die kurze Antwort: Nicht das Protokoll ist kompliziert, sondern das Format-Chaos davor. mTLS selbst ist ein Handshake, bei dem beide Seiten ein Zertifikat vorzeigen. Der Aufwand entsteht, weil die Zertifikate aus der PKI als PEM kommen, die Java-Welt aber jahrelang auf JKS und PKCS12 bestand.

Das Ergebnis kennst du vermutlich aus jedem zweiten Projekt: ein keytool-Aufruf mit acht Parametern, den niemand mehr erklären kann, versteckt in einem Shell-Skript im Build. Dazu eine SSLContext-Bean, die jemand 2019 aus einem Stack-Overflow-Post kopiert hat.

Genau das ist seit Spring Boot 3.1 nicht mehr nötig. SSL Bundles nehmen PEM-Dateien direkt entgegen und bauen KeyStore, KeyManager und SSLContext selbst zusammen. Wir raten inzwischen konsequent davon ab, eigene SSLContext-Beans zu schreiben: Jede handgebaute Variante, die uns in Reviews begegnet, kann weniger als das Framework und bricht bei der ersten Rotation.

Was 2026 dazugekommen ist

Spring Boot steht bei 81.165 GitHub-Stars (Abruf 28.07.2026) und bleibt damit das Rückgrat der deutschen Java-Enterprise-Landschaft. Für mTLS sind drei Daten relevant:

  • Spring Boot 4.1.0, veröffentlicht am 10.06.2026, ist die aktuelle Minor-Version.
  • Spring Boot 4.0.0 kam am 20.11.2025 als GA, aufgesetzt auf Spring Framework 7.0 (GA 13.11.2025).
  • Mitgeliefert wird Spring Security 7.0.5.

Der Sprung auf 4.x ist für mTLS-Setups relevanter, als er klingt. Mit Spring Framework 7 ist RestClient der Standard für synchrone HTTP-Aufrufe. Wer weiterhin RestTemplate verwendet, bekommt Support, aber die Beispiele in der Dokumentation wandern ab.

Server-Seite: mTLS erzwingen

Auf dem Server brauchst du zwei Dinge: ein eigenes Zertifikat und die Anweisung, dass Clients ebenfalls eines vorzeigen müssen. Beides steht in der application.yml, nicht im Code.

spring:
  ssl:
    bundle:
      pem:
        server:
          keystore:
            certificate: "classpath:certs/server.crt"
            private-key: "classpath:certs/server.key"
          truststore:
            # Nur die eigene CA. NICHT das System-Truststore verwenden,
            # sonst akzeptiert der Server jedes öffentlich signierte Zertifikat.
            certificate: "classpath:certs/ca.crt"

server:
  port: 8443
  ssl:
    bundle: "server"
    client-auth: need

Der entscheidende Schalter ist client-auth: need. Es gibt drei Werte, und der Unterschied zwischen zweien davon ist die häufigste Fehlkonfiguration, die uns begegnet:

Wert Verhalten Wann sinnvoll
none kein Client-Zertifikat, normales TLS öffentliche Endpunkte
want Zertifikat wird angefragt, fehlt es, läuft der Request trotzdem Migrationsphase
need ohne gültiges Zertifikat bricht der Handshake ab Produktion

want fühlt sich in der Migration richtig an und ist es kurzzeitig auch. Nur bleibt es erfahrungsgemäß stehen. Setz dir ein Datum, an dem umgestellt wird, sonst hast du ein Sicherheitsversprechen im Architekturdiagramm, das im Betrieb nichts erzwingt.

Das Truststore-Feld verdient den zweiten Blick. Trägst du dort nichts ein, fällt Java auf den System-Truststore zurück, und dann authentifiziert sich jedes Zertifikat einer öffentlichen CA erfolgreich. Das ist kein theoretischer Fehler, das ist der Klassiker in Code-Reviews.

Client-Seite: RestClient und WebClient

Der Client braucht dasselbe Bundle-Prinzip, nur wird es an den HTTP-Client gehängt statt an den Servlet-Container. Für RestClient und RestTemplate läuft das über den Builder:

@Configuration
public class ApiClientConfig {

    // Das Bundle kommt aus application.yml, hier wird es nur zugewiesen.
    @Bean
    RestClient inventoryClient(RestClient.Builder builder, SslBundles bundles) {
        return builder
                .baseUrl("https://inventory.internal:8443")
                .apply(ClientHttpRequestFactorySettings.defaults()
                        .withSslBundle(bundles.getBundle("client")))
                .build();
    }
}

Für reaktive Anwendungen gibt es WebClientSsl, das dieselbe Aufgabe für WebClient.Builder übernimmt:

@Bean
WebClient inventoryWebClient(WebClient.Builder builder, WebClientSsl ssl) {
    return builder
            .baseUrl("https://inventory.internal:8443")
            .apply(ssl.fromBundle("client"))
            .build();
}

Beide Varianten haben denselben Vorteil: Das Zertifikat steht nirgends im Java-Code. Wechselt die PKI Format oder Pfad, ändert sich eine YAML-Zeile, kein Kompilat.

Das läuft jetzt im POC. Was für den Produktivbetrieb fehlt: Zertifikats-Rotation ohne Deployment, Monitoring der Ablaufdaten, SSO-Anbindung, und eine CA, die nicht auf dem Laptop eines Kollegen liegt. Genau den Sprung von „läuft auf meinem Rechner“ zu „läuft im Unternehmen“ machen wir als Projekt: Zero-Trust-Strecke mit unseren Architekten besprechen

Integrationstests: hier bleiben die meisten hängen

Direkt gesagt: Das ist der Punkt, an dem in der Praxis die meiste Zeit verbrennt. In der Spring-Boot-Community ist die Frage ein Dauerbrenner. Ein Entwickler beschreibt sein Problem in r/SpringBoot so: „I’m having a problem regarding spring boot mTLS integration testing.“ Der Kern steckt in seinem Folgesatz: „The whole point is to test the mTLS authentication.“

Und genau da liegt der Fehler in den meisten Antworten, die man darauf findet. Der häufigste Rat lautet, für Tests ein zweites YAML-Profil ohne mTLS zu bauen. Das löst den roten Build, testet aber die Sicherheitsschicht nicht mehr, um die es geht.

Der Weg, den wir in Projekten gehen: ein zweites Bundle nur für Tests, mit einem Zertifikat, das dieselbe Test-CA signiert hat.

# src/test/resources/application-test.yml
spring:
  ssl:
    bundle:
      pem:
        test-client:
          keystore:
            certificate: "classpath:certs/test-client.crt"
            private-key: "classpath:certs/test-client.key"
          truststore:
            certificate: "classpath:certs/test-ca.crt"
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
class InventoryApiMtlsTest {

    @Test
    void ohneZertifikatKeinZugriff() {
        RestClient anonym = RestClient.create();

        // Erwartet: Handshake scheitert, nicht etwa 401 oder 403.
        assertThatThrownBy(() -> anonym.get().uri(baseUrl).retrieve().body(String.class))
                .isInstanceOf(ResourceAccessException.class);
    }
}

Der zweite Test ist wichtiger als der erste: Prüfe nicht nur, dass ein gültiges Zertifikat durchkommt, sondern dass ein ungültiges scheitert. Ein Test, der nur den Happy Path abdeckt, bleibt auch dann grün, wenn jemand versehentlich client-auth: none setzt.

Die Test-Zertifikate erzeugst du mit openssl im Build, nicht per keytool von Hand. PEM ist das Format, das SSL Bundles ohnehin erwarten, und ein Skript ist reproduzierbar. Ein manuell erzeugter Keystore im Repository läuft nach zwölf Monaten ab, und niemand weiß mehr, wie er entstanden ist.

Rotation und der Punkt, an dem die App die falsche Ebene ist

Zertifikate laufen ab, meist zum ungünstigsten Zeitpunkt. Spring Boot kann Bundles zur Laufzeit neu laden:

spring:
  ssl:
    bundle:
      pem:
        server:
          reload-on-update: true

In Kubernetes zeigt das Bundle dann auf ein gemountetes Secret, das der Cert-Manager erneuert. Die Anwendung zieht die neue Datei, ohne dass ein Pod neu startet. Wie der Unterbau dafür aussehen sollte, haben wir in unserer Übersicht zu Container- und Kubernetes-Infrastruktur beschrieben.

Hier kommt allerdings die unbequeme Empfehlung, und sie widerspricht dem Rest dieses Artikels: Wenn ihr bereits ein Service Mesh betreibt, gehört mTLS nicht in die Anwendung. Istio oder Linkerd erledigen Handshake und Rotation im Sidecar, für jede Sprache im Cluster gleich, ohne dass ein Java-Team, ein Go-Team und ein Python-Team dieselbe Logik dreimal bauen. Wie das auf Mesh-Ebene aussieht, steht in mTLS im Service Mesh.

Application-Level-mTLS lohnt sich in drei Fällen. Der Gegenpart liegt außerhalb des Clusters, etwa bei einer Bank oder einem Behördendienst. Es gibt kein Mesh und es soll auch keins geben. Oder die Anwendung läuft auf einer klassischen VM. In allen anderen Fällen baust du eine zweite Sicherheitsschicht, die du danach doppelt betreiben musst.

Häufig gestellte Fragen

Was kostet die Einführung von mTLS in einer bestehenden Spring-Boot-Landschaft?

Der Code-Anteil ist klein, meist ein bis zwei Tage pro Dienst. Der Aufwand steckt in der PKI: CA-Betrieb, Ausstellungsprozess, Rotation und Monitoring. Für eine Landschaft mit 10 bis 15 Diensten kalkulieren wir üblicherweise ein Projekt im niedrigen fünfstelligen Bereich, sofern eine CA bereits existiert. Ohne CA kommt deren Aufbau dazu.

Brauche ich Spring Security für mTLS?

Nein, nicht für den Handshake. Die Authentifizierung auf Transportebene übernimmt der Servlet-Container über client-auth: need. Spring Security brauchst du erst, wenn aus dem Zertifikat eine Identität mit Rollen werden soll, also für x509() in der Filterkette. Beides zu trennen hilft beim Debuggen: Scheitert der Handshake, ist es TLS. Kommt ein 403, ist es Security.

mTLS oder OAuth2, was ist besser?

Die Frage stellt sich seltener, als sie gestellt wird, weil beide unterschiedliche Ebenen absichern. mTLS authentifiziert den Dienst, OAuth2 den Benutzer oder die Anwendung. In regulierten Umgebungen laufen sie zusammen: mTLS als Kanal zwischen den Diensten, ein Token für den fachlichen Kontext darin. Wer nur eines wählen kann, nimmt bei Server-zu-Server-Verkehr mTLS und bei Benutzerkontext OAuth2.

Warum schlägt der Handshake fehl, obwohl das Zertifikat gültig ist?

In den meisten Fällen liegt es am Truststore, nicht am Keystore. Der Server prüft das Client-Zertifikat gegen seine eigene Vertrauensliste. Ist dort nur die Root-CA hinterlegt, das Zertifikat stammt aber von einer Zwischen-CA, fehlt ein Kettenglied. Prüfen lässt sich das mit openssl s_client -connect host:8443 -cert client.crt -key client.key.

Funktionieren SSL Bundles auch mit älteren Spring-Boot-Versionen?

SSL Bundles gibt es seit Spring Boot 3.1. Für 2.7 und älter bleibt nur die manuelle SSLContext-Konfiguration. Da 2.7 seit längerem außerhalb des kostenlosen Supports liegt, ist das in der Regel ein Argument für das Upgrade und nicht für eine Übergangslösung.


Nächster Schritt

Wenn ihr mTLS nicht nur in einem Dienst, sondern über eine ganze Landschaft ausrollt, ist die Anwendungskonfiguration der kleinere Teil. Die Fragen, die das Projekt tragen, sind CA-Betrieb, Rotation und Monitoring.


Verwandte Themen


Quellen: Spring Boot SSL-Referenz, GitHub-Repository spring-projects/spring-boot (Star-Zahl abgerufen am 28.07.2026), Spring-Boot-Release-Historie (Version 4.1.0 vom 10.06.2026).


Microsoft Fabric. Bilder Blogtemplate Whitepaper

Blueprint: Sicher On-Premise KI-Architektur in 4 Wochen

  • Ein praxisorientierter Implementierungsplan für souverände, performante und DSGVO-konforme Generative KI

Beratungsgespräch

Sichern Sie sich Ihre kostenfreie Erstberatung

Analyse Ihres individuellen Cloud- oder KI-Bedarfs
Erste Empfehlungen zu Umsetzungsstrategien
Transparente Einblicke in unsere Methoden, Technologien & Referenzen