fix: add a reload period property (#32715)

closes: #23771

Signed-off-by: Steve Hawkins <shawkins@redhat.com>
This commit is contained in:
Steven Hawkins 2024-09-13 03:47:21 -04:00 committed by GitHub
parent 92e435f192
commit f0bf290c28
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 79 additions and 2 deletions

View file

@ -142,6 +142,10 @@ The deprecated `proxy` option was removed. This option was deprecated in {projec
The `proxy-trusted-addresses` can be used when the `proxy-headers` option is set to specify a allowlist of trusted proxy addresses. If the proxy address for a given request is not trusted, then the respective proxy header values will not be used.
= Option to reload trust and key material added
The `https-certificates-reload-period` option can be set to define the reloading period of key store, trust store, and certificate files referenced by https-* options. Use -1 to disable reloading. Defaults to 1h (one hour).
= Property `origin` in the `UserRepresentation` is deprecated
The `origin` property in the `UserRepresentation` is deprecated and planned to be removed in future releases.

View file

@ -85,4 +85,9 @@ NOTE: Management interface properties are inherited from the main HTTP server, i
It means when mTLS is set, it is also enabled for the management interface.
To override the behavior, use the `https-management-client-auth` property.
== Certificate and Key Reloading
By default {project_name} will reload the certificates, keys, and keystores specified in `https-*` options every hour. For environments where your server keys may need frequent rotation, this allows that to happen without a server restart. You may override the default via the `https-certificates-reload-period` option. Interval on which to reload key store, trust store, and certificate files referenced by https-* options.
The value may be a java.time.Duration value, an integer number of seconds, or an integer followed by one of the time units [ms, h, m, s, d]. Must be greater than 30 seconds. Use -1 to disable.
</@tmpl.guide>

View file

@ -63,6 +63,12 @@ public class HttpOptions {
.defaultValue(Arrays.asList("TLSv1.3,TLSv1.2"))
.build();
public static final Option<String> HTTPS_CERTIFICATES_RELOAD_PERIOD = new OptionBuilder<>("https-certificates-reload-period", String.class)
.category(OptionCategory.HTTP)
.description("Interval on which to reload key store, trust store, and certificate files referenced by https-* options. May be a java.time.Duration value, an integer number of seconds, or an integer followed by one of [ms, h, m, s, d]. Must be greater than 30 seconds. Use -1 to disable.")
.defaultValue("1h")
.build();
public static final Option<File> HTTPS_CERTIFICATE_FILE = new OptionBuilder<>("https-certificate-file", File.class)
.category(OptionCategory.HTTP)
.description("The file path to a server certificate or certificate chain in PEM format.")

View file

@ -68,6 +68,12 @@ public final class HttpPropertyMappers {
.to("quarkus.http.ssl.protocols")
.paramLabel("protocols")
.build(),
fromOption(HttpOptions.HTTPS_CERTIFICATES_RELOAD_PERIOD)
.to("quarkus.http.ssl.certificate.reload-period")
// -1 means no reload
.transformer((value, context) -> "-1".equals(value.get()) ? null : value)
.paramLabel("reload period")
.build(),
fromOption(HttpOptions.HTTPS_CERTIFICATE_FILE)
.to(QUARKUS_HTTPS_CERT_FILES)
.transformer(HttpPropertyMappers.validatePath(QUARKUS_HTTPS_CERT_FILES))

View file

@ -160,7 +160,12 @@ public class PropertyMapper<T> {
// we always fallback to the current value from the property we are mapping
if (transformedValue == null) {
return context.proceed(name);
return ConfigValue.builder()
.withName(name)
.withValue(null)
.withRawValue(config.getValue())
.withConfigSourceName(config.getConfigSourceName())
.build();
}
return transformedValue;

View file

@ -18,6 +18,7 @@
package org.keycloak.quarkus.runtime.configuration.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.keycloak.quarkus.runtime.Environment.isWindows;
import static org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource.CLI_ARGS;
@ -475,4 +476,14 @@ public class ConfigurationTest extends AbstractConfigurationTest {
ConfigValue secret = config.getConfigValue("my.secret");
assertEquals("secret", secret.getValue());
}
@Test
public void testReloadPeriod() {
ConfigArgsConfigSource.setCliArgs("");
assertEquals("1h", createConfig().getConfigValue("quarkus.http.ssl.certificate.reload-period").getValue());
ConfigArgsConfigSource.setCliArgs("--https-certificates-reload-period=-1");
assertNull(createConfig().getConfigValue("quarkus.http.ssl.certificate.reload-period").getValue());
ConfigArgsConfigSource.setCliArgs("--https-certificates-reload-period=2h");
assertEquals("2h", createConfig().getConfigValue("quarkus.http.ssl.certificate.reload-period").getValue());
}
}

View file

@ -31,12 +31,16 @@ import java.util.concurrent.CompletableFuture;
import static io.restassured.RestAssured.when;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import io.quarkus.test.junit.main.Launch;
import io.quarkus.test.junit.main.LaunchResult;
/**
* @author Vaclav Muzikar <vmuzikar@redhat.com>
*/
@DistributionTest(keepAlive = true)
@DistributionTest(keepAlive = true, enableTls = true)
@RawDistOnly(reason = "Containers are immutable")
public class HttpDistTest {
@Test
@ -55,4 +59,10 @@ public class HttpDistTest {
assertThat("Some of the requests should be properly rejected", statusCodes, hasItem(503));
assertThat("None of the requests should throw an unhandled exception", statusCodes, not(hasItem(500)));
}
@Test
@Launch({"start-dev", "--https-certificates-reload-period=wrong"})
public void testHttpCertificateReloadPeriod(LaunchResult result) {
assertThat(result.getErrorOutput(), containsString("Text cannot be parsed to a Duration"));
}
}

View file

@ -153,6 +153,11 @@ HTTP(S):
The file path to a server certificate or certificate chain in PEM format.
--https-certificate-key-file <file>
The file path to a private key in PEM format.
--https-certificates-reload-period <reload period>
Interval on which to reload key store, trust store, and certificate files
referenced by https-* options. May be a java.time.Duration value, an integer
number of seconds, or an integer followed by one of [ms, h, m, s, d]. Must
be greater than 30 seconds. Use -1 to disable. Default: 1h.
--https-cipher-suites <ciphers>
The cipher suites to use. If none is given, a reasonable default is selected.
--https-client-auth <auth>

View file

@ -188,6 +188,11 @@ HTTP(S):
The file path to a server certificate or certificate chain in PEM format.
--https-certificate-key-file <file>
The file path to a private key in PEM format.
--https-certificates-reload-period <reload period>
Interval on which to reload key store, trust store, and certificate files
referenced by https-* options. May be a java.time.Duration value, an integer
number of seconds, or an integer followed by one of [ms, h, m, s, d]. Must
be greater than 30 seconds. Use -1 to disable. Default: 1h.
--https-cipher-suites <ciphers>
The cipher suites to use. If none is given, a reasonable default is selected.
--https-client-auth <auth>

View file

@ -154,6 +154,11 @@ HTTP(S):
The file path to a server certificate or certificate chain in PEM format.
--https-certificate-key-file <file>
The file path to a private key in PEM format.
--https-certificates-reload-period <reload period>
Interval on which to reload key store, trust store, and certificate files
referenced by https-* options. May be a java.time.Duration value, an integer
number of seconds, or an integer followed by one of [ms, h, m, s, d]. Must
be greater than 30 seconds. Use -1 to disable. Default: 1h.
--https-cipher-suites <ciphers>
The cipher suites to use. If none is given, a reasonable default is selected.
--https-client-auth <auth>

View file

@ -189,6 +189,11 @@ HTTP(S):
The file path to a server certificate or certificate chain in PEM format.
--https-certificate-key-file <file>
The file path to a private key in PEM format.
--https-certificates-reload-period <reload period>
Interval on which to reload key store, trust store, and certificate files
referenced by https-* options. May be a java.time.Duration value, an integer
number of seconds, or an integer followed by one of [ms, h, m, s, d]. Must
be greater than 30 seconds. Use -1 to disable. Default: 1h.
--https-cipher-suites <ciphers>
The cipher suites to use. If none is given, a reasonable default is selected.
--https-client-auth <auth>

View file

@ -136,6 +136,11 @@ HTTP(S):
The file path to a server certificate or certificate chain in PEM format.
--https-certificate-key-file <file>
The file path to a private key in PEM format.
--https-certificates-reload-period <reload period>
Interval on which to reload key store, trust store, and certificate files
referenced by https-* options. May be a java.time.Duration value, an integer
number of seconds, or an integer followed by one of [ms, h, m, s, d]. Must
be greater than 30 seconds. Use -1 to disable. Default: 1h.
--https-cipher-suites <ciphers>
The cipher suites to use. If none is given, a reasonable default is selected.
--https-key-store-file <file>

View file

@ -171,6 +171,11 @@ HTTP(S):
The file path to a server certificate or certificate chain in PEM format.
--https-certificate-key-file <file>
The file path to a private key in PEM format.
--https-certificates-reload-period <reload period>
Interval on which to reload key store, trust store, and certificate files
referenced by https-* options. May be a java.time.Duration value, an integer
number of seconds, or an integer followed by one of [ms, h, m, s, d]. Must
be greater than 30 seconds. Use -1 to disable. Default: 1h.
--https-cipher-suites <ciphers>
The cipher suites to use. If none is given, a reasonable default is selected.
--https-key-store-file <file>