Skip to content

Commit d8662b2

Browse files
feat(spring-boot): consideration of "ssl.enabled" properties to enable liveness/readiness probe for Spring Boot Actuator (3807)
feat(spring-boot): Consideration of ssl.enabled properties to enable liveness/readiness probe for Spring Boot Actuator --- feat(spring-boot): Update changelog --- feat(spring-boot): Update spring boot docs --- feat(spring-boot): Update spring boot docs --- Merge branch 'master' into feat-spring-boot-ssl
1 parent b0c866a commit d8662b2

File tree

8 files changed

+320
-11
lines changed

8 files changed

+320
-11
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Usage:
2727
* Fix #2286: Remove Guava dependency where ever possible
2828
* Fix #3809: Actuator liveness and readiness probe not getting generated with Spring boot 4.x.x
2929
* Fix #3707: Setting readOnly flag in VolumeConfig has no effect
30+
* Fix #1458: Consideration of "ssl.enabled" properties to enable liveness/readiness probe for Spring Boot Actuator
3031

3132
### 1.18.2 (2025-11-03)
3233
* Fix #3750: Remove unneeded XMLUtil.createNewDocument method

jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/SpringBootConfiguration.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ public class SpringBootConfiguration {
3131
private String serverKeystore;
3232
private String managementKeystore;
3333
private String servletPath;
34+
private boolean serverSslEnabled;
35+
private boolean managementSslEnabled;
3436
private String serverContextPath;
3537
private String managementContextPath;
3638
private String actuatorBasePath;
@@ -54,27 +56,40 @@ public static SpringBootConfiguration from(JavaProject project) {
5456
.orElse(1);
5557
final SpringBootConfiguration.SpringBootConfigurationBuilder configBuilder = SpringBootConfiguration.builder();
5658
// Spring Boot 1 and common properties
59+
final String serverKeystore = properties.getProperty("server.ssl.key-store");
60+
final String managementKeystore = properties.getProperty("management.ssl.key-store");
61+
5762
configBuilder
5863
.managementPort(Optional.ofNullable(properties.getProperty("management.port")).map(Integer::parseInt).orElse(null))
5964
.serverPort(Integer.parseInt(properties.getProperty("server.port", DEFAULT_SERVER_PORT)))
60-
.serverKeystore(properties.getProperty("server.ssl.key-store"))
65+
.serverKeystore(serverKeystore)
6166
.managementHealthProbesEnabled(Boolean.parseBoolean(properties.getProperty("management.health.probes.enabled")))
62-
.managementKeystore(properties.getProperty("management.ssl.key-store"))
67+
.managementKeystore(managementKeystore)
6368
.servletPath(properties.getProperty("server.servlet-path"))
6469
.serverContextPath(properties.getProperty("server.context-path"))
6570
.managementContextPath(properties.getProperty("management.context-path"))
6671
.actuatorBasePath("")
6772
.actuatorDefaultBasePath("")
68-
.webFluxBasePath(properties.getProperty("spring.webflux.base-path"));
73+
.webFluxBasePath(properties.getProperty("spring.webflux.base-path"))
74+
.serverSslEnabled(Optional.ofNullable(properties.getProperty("server.ssl.enabled"))
75+
.map(Boolean::parseBoolean)
76+
.orElse(serverKeystore != null))
77+
.managementSslEnabled(Optional.ofNullable(properties.getProperty("management.ssl.enabled"))
78+
.map(Boolean::parseBoolean)
79+
.orElse(managementKeystore != null));
6980
if (majorVersion > 1) {
81+
final String managementServerKeystore = properties.getProperty("management.server.ssl.key-store");
7082
configBuilder
7183
.managementPort(Optional.ofNullable(properties.getProperty("management.server.port")).map(Integer::parseInt).orElse(null))
72-
.managementKeystore(properties.getProperty("management.server.ssl.key-store"))
84+
.managementKeystore(managementServerKeystore)
7385
.servletPath(properties.getProperty("server.servlet.path"))
7486
.serverContextPath(properties.getProperty("server.servlet.context-path"))
7587
.managementContextPath(properties.getProperty("management.server.servlet.context-path"))
7688
.actuatorBasePath(properties.getProperty("management.endpoints.web.base-path"))
77-
.actuatorDefaultBasePath("/actuator");
89+
.actuatorDefaultBasePath("/actuator")
90+
.managementSslEnabled(Optional.ofNullable(properties.getProperty("management.server.ssl.enabled"))
91+
.map(Boolean::parseBoolean)
92+
.orElse(managementServerKeystore != null));
7893
}
7994
if (majorVersion == 3) {
8095
configBuilder

jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/SpringBootConfigurationTest.java

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ void setUp(@TempDir Path target) throws IOException {
5454
properties.put("management.context-path", "management.context-path");
5555
properties.put("management.server.servlet.context-path", "management.server.servlet.context-path");
5656
properties.put("management.endpoints.web.base-path", "management.endpoints.web.base-path");
57+
properties.put("server.ssl.enabled", "true");
58+
properties.put("management.ssl.enabled", "true");
59+
properties.put("management.server.ssl.enabled", "true");
5760
try (OutputStream fos = Files.newOutputStream(target.resolve("application.properties"))) {
5861
properties.store(fos, null);
5962
}
@@ -134,6 +137,99 @@ void getActuatorBasePath() {
134137
void getActuatorDefaultBasePath() {
135138
assertThat(springBootConfiguration.getActuatorDefaultBasePath()).isEqualTo("/actuator");
136139
}
140+
141+
@Test
142+
@DisplayName("isServerSslEnabled returns true when server.ssl.enabled is true")
143+
void isServerSslEnabled_whenExplicitlyTrue() {
144+
assertThat(springBootConfiguration.isServerSslEnabled()).isTrue();
145+
}
146+
147+
@Test
148+
@DisplayName("isManagementSslEnabled returns true when management.server.ssl.enabled is true")
149+
void isManagementSslEnabled_whenExplicitlyTrue() {
150+
assertThat(springBootConfiguration.isManagementSslEnabled()).isTrue();
151+
}
152+
153+
@Test
154+
@DisplayName("isServerSslEnabled defaults to true when keystore configured and ssl.enabled not set")
155+
void isServerSslEnabled_defaultsToTrueWithKeystore(@TempDir Path target) throws IOException {
156+
final Properties properties = new Properties();
157+
properties.put("server.ssl.key-store", "keystore.jks");
158+
try (OutputStream fos = Files.newOutputStream(target.resolve("application.properties"))) {
159+
properties.store(fos, null);
160+
}
161+
SpringBootConfiguration config = SpringBootConfiguration.from(JavaProject.builder()
162+
.properties(properties)
163+
.outputDirectory(target.toFile())
164+
.dependency(Dependency.builder()
165+
.groupId("org.springframework.boot")
166+
.artifactId("spring-boot")
167+
.version("3.0")
168+
.build())
169+
.build());
170+
assertThat(config.isServerSslEnabled()).isTrue();
171+
}
172+
173+
@Test
174+
@DisplayName("isServerSslEnabled returns false when server.ssl.enabled is false")
175+
void isServerSslEnabled_whenExplicitlyFalse(@TempDir Path target) throws IOException {
176+
final Properties properties = new Properties();
177+
properties.put("server.ssl.key-store", "keystore.jks");
178+
properties.put("server.ssl.enabled", "false");
179+
try (OutputStream fos = Files.newOutputStream(target.resolve("application.properties"))) {
180+
properties.store(fos, null);
181+
}
182+
SpringBootConfiguration config = SpringBootConfiguration.from(JavaProject.builder()
183+
.properties(properties)
184+
.outputDirectory(target.toFile())
185+
.dependency(Dependency.builder()
186+
.groupId("org.springframework.boot")
187+
.artifactId("spring-boot")
188+
.version("3.0")
189+
.build())
190+
.build());
191+
assertThat(config.isServerSslEnabled()).isFalse();
192+
}
193+
194+
@Test
195+
@DisplayName("isManagementSslEnabled returns false when management.server.ssl.enabled is false")
196+
void isManagementSslEnabled_whenExplicitlyFalse(@TempDir Path target) throws IOException {
197+
final Properties properties = new Properties();
198+
properties.put("management.server.ssl.key-store", "keystore.jks");
199+
properties.put("management.server.ssl.enabled", "false");
200+
try (OutputStream fos = Files.newOutputStream(target.resolve("application.properties"))) {
201+
properties.store(fos, null);
202+
}
203+
SpringBootConfiguration config = SpringBootConfiguration.from(JavaProject.builder()
204+
.properties(properties)
205+
.outputDirectory(target.toFile())
206+
.dependency(Dependency.builder()
207+
.groupId("org.springframework.boot")
208+
.artifactId("spring-boot")
209+
.version("3.0")
210+
.build())
211+
.build());
212+
assertThat(config.isManagementSslEnabled()).isFalse();
213+
}
214+
215+
@Test
216+
@DisplayName("isServerSslEnabled defaults to false when no keystore and ssl.enabled not set")
217+
void isServerSslEnabled_defaultsToFalseWithoutKeystore(@TempDir Path target) throws IOException {
218+
final Properties properties = new Properties();
219+
try (OutputStream fos = Files.newOutputStream(target.resolve("application.properties"))) {
220+
properties.store(fos, null);
221+
}
222+
SpringBootConfiguration config = SpringBootConfiguration.from(JavaProject.builder()
223+
.properties(properties)
224+
.outputDirectory(target.toFile())
225+
.dependency(Dependency.builder()
226+
.groupId("org.springframework.boot")
227+
.artifactId("spring-boot")
228+
.version("3.0")
229+
.build())
230+
.build());
231+
assertThat(config.isServerSslEnabled()).isFalse();
232+
}
137233
}
138234

139235
@Nested
@@ -207,6 +303,60 @@ void getActuatorBasePath() {
207303
void getActuatorDefaultBasePath() {
208304
assertThat(springBootConfiguration.getActuatorDefaultBasePath()).isEqualTo("/actuator");
209305
}
306+
307+
@Test
308+
@DisplayName("isServerSslEnabled returns true when server.ssl.enabled is true")
309+
void isServerSslEnabled_whenExplicitlyTrue() {
310+
assertThat(springBootConfiguration.isServerSslEnabled()).isTrue();
311+
}
312+
313+
@Test
314+
@DisplayName("isManagementSslEnabled returns true when management.server.ssl.enabled is true")
315+
void isManagementSslEnabled_whenExplicitlyTrue() {
316+
assertThat(springBootConfiguration.isManagementSslEnabled()).isTrue();
317+
}
318+
319+
@Test
320+
@DisplayName("isServerSslEnabled returns false when server.ssl.enabled is false")
321+
void isServerSslEnabled_whenExplicitlyFalse(@TempDir Path target) throws IOException {
322+
final Properties properties = new Properties();
323+
properties.put("server.ssl.key-store", "keystore.jks");
324+
properties.put("server.ssl.enabled", "false");
325+
try (OutputStream fos = Files.newOutputStream(target.resolve("application.properties"))) {
326+
properties.store(fos, null);
327+
}
328+
SpringBootConfiguration config = SpringBootConfiguration.from(JavaProject.builder()
329+
.properties(properties)
330+
.outputDirectory(target.toFile())
331+
.dependency(Dependency.builder()
332+
.groupId("org.springframework.boot")
333+
.artifactId("spring-boot")
334+
.version("2.0")
335+
.build())
336+
.build());
337+
assertThat(config.isServerSslEnabled()).isFalse();
338+
}
339+
340+
@Test
341+
@DisplayName("isManagementSslEnabled returns false when management.server.ssl.enabled is false")
342+
void isManagementSslEnabled_whenExplicitlyFalse(@TempDir Path target) throws IOException {
343+
final Properties properties = new Properties();
344+
properties.put("management.server.ssl.key-store", "keystore.jks");
345+
properties.put("management.server.ssl.enabled", "false");
346+
try (OutputStream fos = Files.newOutputStream(target.resolve("application.properties"))) {
347+
properties.store(fos, null);
348+
}
349+
SpringBootConfiguration config = SpringBootConfiguration.from(JavaProject.builder()
350+
.properties(properties)
351+
.outputDirectory(target.toFile())
352+
.dependency(Dependency.builder()
353+
.groupId("org.springframework.boot")
354+
.artifactId("spring-boot")
355+
.version("2.0")
356+
.build())
357+
.build());
358+
assertThat(config.isManagementSslEnabled()).isFalse();
359+
}
210360
}
211361

212362
@Nested
@@ -351,5 +501,61 @@ void getActuatorDefaultBasePath(String version) {
351501
assertThat(springBootConfiguration.getActuatorDefaultBasePath()).
352502
isEmpty();
353503
}
504+
505+
@ParameterizedTest(name = "{0}")
506+
@ValueSource(strings = {"1.0", "undefined"})
507+
@DisplayName("isServerSslEnabled returns true when ssl.enabled is true (Spring Boot 1)")
508+
void isServerSslEnabled_whenExplicitlyTrue(String version) {
509+
springBootConfiguration = SpringBootConfiguration.from(project.toBuilder()
510+
.dependency(Dependency.builder()
511+
.groupId("org.springframework.boot")
512+
.artifactId("spring-boot")
513+
.version(version)
514+
.build())
515+
.build());
516+
assertThat(springBootConfiguration.isServerSslEnabled()).isTrue();
517+
}
518+
519+
@Test
520+
@DisplayName("isManagementSslEnabled uses management.ssl.enabled property (Spring Boot 1)")
521+
void isManagementSslEnabled_withManagementSslEnabled(@TempDir Path target) throws IOException {
522+
final Properties properties = new Properties();
523+
properties.put("management.ssl.key-store", "keystore.jks");
524+
properties.put("management.ssl.enabled", "false");
525+
try (OutputStream fos = Files.newOutputStream(target.resolve("application.properties"))) {
526+
properties.store(fos, null);
527+
}
528+
SpringBootConfiguration config = SpringBootConfiguration.from(JavaProject.builder()
529+
.properties(properties)
530+
.outputDirectory(target.toFile())
531+
.dependency(Dependency.builder()
532+
.groupId("org.springframework.boot")
533+
.artifactId("spring-boot")
534+
.version("1.0")
535+
.build())
536+
.build());
537+
assertThat(config.isManagementSslEnabled()).isFalse();
538+
}
539+
540+
@Test
541+
@DisplayName("isServerSslEnabled returns false when server.ssl.enabled is false (Spring Boot 1)")
542+
void isServerSslEnabled_whenExplicitlyFalse(@TempDir Path target) throws IOException {
543+
final Properties properties = new Properties();
544+
properties.put("server.ssl.key-store", "keystore.jks");
545+
properties.put("server.ssl.enabled", "false");
546+
try (OutputStream fos = Files.newOutputStream(target.resolve("application.properties"))) {
547+
properties.store(fos, null);
548+
}
549+
SpringBootConfiguration config = SpringBootConfiguration.from(JavaProject.builder()
550+
.properties(properties)
551+
.outputDirectory(target.toFile())
552+
.dependency(Dependency.builder()
553+
.groupId("org.springframework.boot")
554+
.artifactId("spring-boot")
555+
.version("1.0")
556+
.build())
557+
.build());
558+
assertThat(config.isServerSslEnabled()).isFalse();
559+
}
354560
}
355561
}

jkube-kit/doc/src/main/asciidoc/inc/enricher/spring-boot-healthcheck/_jkube_healthcheck_spring_boot.adoc

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,18 @@ If the user has enabled the `management.health.probes.enabled` property this Enr
2424
management.health.probes.enabled=true
2525
----
2626

27-
The port number is read from the `management.port` option, and will use the default value of `8080`
28-
The scheme will use HTTPS if `server.ssl.key-store` option is in use, and fallback to use `HTTP` otherwise.
27+
The port number is read from the `management.port` (Spring Boot 1) or `management.server.port` (Spring Boot 2+) option, and will use the default value of `8080`.
28+
29+
The probe scheme (`http` or `https`) is determined as follows:
30+
31+
* For probes targeting the management port:
32+
** If `management.server.ssl.enabled` (Spring Boot 2+) or `management.ssl.enabled` (Spring Boot 1) is explicitly set, this value determines whether HTTPS is used
33+
** Otherwise, HTTPS is used if `management.server.ssl.key-store` (Spring Boot 2+) or `management.ssl.key-store` (Spring Boot 1) is configured
34+
* For probes targeting the server port:
35+
** If `server.ssl.enabled` is explicitly set, this value determines whether HTTPS is used
36+
** Otherwise, HTTPS is used if `server.ssl.key-store` is configured
37+
38+
This allows you to disable SSL for health probes even when a keystore is configured by setting the appropriate `ssl.enabled` property to `false`.
2939

3040
The enricher will use the following settings by default:
3141

jkube-kit/doc/src/main/asciidoc/inc/generator/_spring_boot.adoc

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,17 @@ Beside the <<generator-options-common, common generator options>> and the <<gen
2323
|===
2424

2525
The generator adds Kubernetes liveness and readiness probes pointing to either the management or server port as read from the `application.properties`.
26-
If the `management.port` (for Spring Boot 1) or `management.server.port` (for Spring Boot 2) and `management.ssl.key-store` (for Spring Boot 1) or `management.server.ssl.key-store` (for Spring Boot 2) properties are set in `application.properties` otherwise or `server.ssl.key-store` property is set in `application.properties` then the probes are automatically set to use `https`.
26+
27+
The probe scheme (`http` or `https`) is determined as follows:
28+
29+
* For probes targeting the management port:
30+
** If `management.server.ssl.enabled` (Spring Boot 2+) or `management.ssl.enabled` (Spring Boot 1) is explicitly set, this value determines whether HTTPS is used
31+
** Otherwise, HTTPS is used if `management.server.ssl.key-store` (Spring Boot 2+) or `management.ssl.key-store` (Spring Boot 1) is configured
32+
* For probes targeting the server port:
33+
** If `server.ssl.enabled` is explicitly set, this value determines whether HTTPS is used
34+
** Otherwise, HTTPS is used if `server.ssl.key-store` is configured
35+
36+
This allows you to disable SSL for health probes even when a keystore is configured by setting the appropriate `ssl.enabled` property to `false`.
2737

2838
ifeval::["{plugin-type}" == "maven"]
2939
The generator works differently when called together with `{goal-prefix}:watch`.

jkube-kit/jkube-kit-spring-boot/src/main/java/org/eclipse/jkube/springboot/enricher/SpringBootHealthCheckEnricher.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,11 +127,11 @@ protected Probe buildProbe(Integer initialDelay, Integer period, Integer timeout
127127
String scheme;
128128
String prefix;
129129
if (usingManagementPort) {
130-
scheme = StringUtils.isNotBlank(springBootConfiguration.getManagementKeystore()) ? SCHEME_HTTPS : SCHEME_HTTP;
130+
scheme = StringUtils.isNotBlank(springBootConfiguration.getManagementKeystore()) && springBootConfiguration.isManagementSslEnabled() ? SCHEME_HTTPS : SCHEME_HTTP;
131131
prefix = StringUtils.isNotBlank(springBootConfiguration.getManagementContextPath()) ?
132132
springBootConfiguration.getManagementContextPath() : "";
133133
} else {
134-
scheme = StringUtils.isNotBlank(springBootConfiguration.getServerKeystore()) ? SCHEME_HTTPS : SCHEME_HTTP;
134+
scheme = StringUtils.isNotBlank(springBootConfiguration.getServerKeystore()) && springBootConfiguration.isServerSslEnabled() ? SCHEME_HTTPS : SCHEME_HTTP;
135135
if (hasSpringWebFluxDependency(getContext().getProject()) && StringUtils.isNotBlank(springBootConfiguration.getWebFluxBasePath())) {
136136
prefix = springBootConfiguration.getWebFluxBasePath();
137137
} else if (StringUtils.isNotBlank(springBootConfiguration.getServerContextPath())) {

jkube-kit/jkube-kit-spring-boot/src/main/java/org/eclipse/jkube/springboot/watcher/SpringBootWatcher.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ String getPortForwardUrl(NamespacedKubernetesClient kubernetes, final Collection
105105
int containerPort = springBootConfiguration.getServerPort();
106106
portForwardService.forwardPortAsync(kubernetes, selector, containerPort, localPort);
107107

108-
String scheme = StringUtils.isNotBlank(springBootConfiguration.getServerKeystore()) ?
108+
String scheme = StringUtils.isNotBlank(springBootConfiguration.getServerKeystore()) && springBootConfiguration.isServerSslEnabled() ?
109109
"https://" : "http://";
110110
String contextPath = StringUtils.isNotBlank(springBootConfiguration.getServerContextPath()) ?
111111
springBootConfiguration.getServerContextPath() : "";

0 commit comments

Comments
 (0)