1. Introduction
When securing a Spring Boot application, SSL/TLS configuration can occur at two different layers: the JVM level and the Spring Boot level. Although both deal with certificates and encryption, they operate independently and serve different purposes. Understanding this distinction is essential for correctly securing traffic both into and out of your application.
2. JVM-Level SSL (Global to the Process)
JVM-level SSL configuration applies to the entire Java Virtual Machine, affecting all outbound TLS communication initiated by the application.
What it controls
- Outbound HTTPS calls
- Trust anchors (which CAs the JVM trusts)
- Client certificates for outbound mutual TLS
Configuration example
-Djavax.net.ssl.keyStore=/etc/certs/client-keystore.p12
-Djavax.net.ssl.keyStorePassword=changeit
-Djavax.net.ssl.trustStore=/etc/certs/jvm-truststore.jks
-Djavax.net.ssl.trustStorePassword=changeit
3. Spring Boot-Level SSL (Embedded Server)
Spring Boot-level SSL is used by the embedded web server (Tomcat/Jetty/Undertow). This controls the TLS endpoint your application exposes to callers.
What it controls
- Inbound HTTPS traffic
- Server certificate presented to clients
- Optional client authentication for inbound mutual TLS (configured via
server.ssl.client-auth)
Configuration example
server:
ssl:
enabled: true
key-store: classpath:server.p12
key-store-password: changeit
key-store-type: PKCS12
trust-store: classpath:client-truststore.jks
trust-store-password: changeit
client-auth: need # Options: none, want, need
Note: The trust-store property is only used when client-auth is set to want or need. It validates client certificates during mutual TLS authentication.
4. Key Differences
| Aspect | JVM-Level SSL | Spring Boot-Level SSL |
|---|---|---|
| Scope | Entire JVM (default for all connections) | Only Spring Boot web server |
| Direction | Outbound (and default inbound) | Inbound (overrides JVM) |
| Use case | Trust upstream services, outbound requests | Serve HTTPS to callers |
| Config | -Djavax.net.ssl.* |
application.yml |
Clarification: JVM-level settings provide defaults for all SSL/TLS connections, but Spring Boot's embedded server overrides these defaults with its own configuration for inbound traffic.
5. When You Need Both
A typical microservice often acts as both a TLS server (for inbound requests) and a TLS client (for outbound dependencies). In this scenario, both SSL layers must be configured.
6. How to Combine JVM-Level and Spring Boot-Level SSL
Combined Use Case
| Requirement | Layer | What is configured |
|---|---|---|
| Present a server certificate to clients | Spring Boot | server.ssl.key-store |
| Trust incoming clients for mTLS | Spring Boot | server.ssl.trust-store |
| Trust upstream service certificates | JVM | javax.net.ssl.trustStore |
| Present client cert for outbound mTLS | JVM | javax.net.ssl.keyStore |
Combined configuration example
JVM-level (outbound)
-Djavax.net.ssl.keyStore=/etc/certs/outbound-client-keystore.p12
-Djavax.net.ssl.keyStorePassword=changeit
-Djavax.net.ssl.trustStore=/etc/certs/outbound-truststore.jks
-Djavax.net.ssl.trustStorePassword=changeit
Spring Boot-level (inbound)
server:
ssl:
enabled: true
key-store: classpath:inbound-server-keystore.p12
key-store-password: changeit
trust-store: classpath:inbound-truststore.jks
trust-store-password: changeit
client-auth: need
When to keep them separate
- Different certificate authorities
- Different rotation lifecycles
- Security boundary separation
- mTLS with asymmetric trust domains
When they can be merged
- Single CA for both directions
- Small trust domain
- Simplified deployment model
7. Advanced Considerations
HTTP Client Libraries
Some HTTP client libraries (RestTemplate, WebClient, Apache HttpClient, etc.) may allow or require custom SSL context configuration beyond JVM-level settings. This is useful when you need:
- Different trust stores for different downstream services
- Per-client SSL configurations
- Programmatic certificate validation logic
Example with RestTemplate:
SSLContext sslContext = SSLContextBuilder.create()
.loadTrustMaterial(trustStore, null)
.build();
SSLConnectionSocketFactory socketFactory =
new SSLConnectionSocketFactory(sslContext);
HttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(socketFactory)
.build();
RestTemplate restTemplate = new RestTemplate(
new HttpComponentsClientHttpRequestFactory(httpClient)
);
8. Summary
| Traffic Direction | Layer | Config |
|---|---|---|
| Inbound (clients → you) | Spring Boot | application.yml |
| Outbound (you → others) | JVM | JVM -D flags |
Both layers serve different purposes but can work together when an application is both a TLS server and a TLS client.
Top comments (0)