diff --git a/README.md b/README.md index f1338d0f..a3a9e22d 100644 --- a/README.md +++ b/README.md @@ -176,7 +176,7 @@ and how it advertises itself to a Cryostat server instance. Properties that requ - [ ] `cryostat.agent.webclient.tls.version` [`String`]: the version of TLS used for the Agent's client SSL context. Default `TLSv1.2`. - [ ] `cryostat.agent.webclient.tls.trust-all` [`boolean`]: control whether the agent trusts all certificates presented by the Cryostat server. Default `false`. This should only be overridden for development and testing purposes, never in production. - [ ] `cryostat.agent.webclient.tls.verify-hostname` [`boolean`]: control whether the agent verifies hostnames on certificates presented by the Cryostat server. Default `true`. This should only be overridden for development and testing purposes, never in production. -- [ ] `cryostat.agent.webclient.tls.certs` [`list`]: the list of truststoreConfig objects with alias, path, and type properties for certificates to be stored in the agent's truststore. For example, 'cryostat.agent.webclient.tls.certs[0].type' would be the type of the first certificate in this list. A truststoreConfig object must contain all three properties to be a valid certificate entry. +- [ ] `cryostat.agent.webclient.tls.trustore.certs` [`list`]: the list of truststoreConfig objects with alias, path, and type properties for certificates to be stored in the agent's truststore. For example, 'cryostat.agent.webclient.tls.truststore.certs[0].type' would be the type of the first certificate in this list. A truststoreConfig object must contain all three properties to be a valid certificate entry. - [ ] `cryostat.agent.webclient.connect.timeout-ms` [`long`]: the duration in milliseconds to wait for HTTP requests to the Cryostat server to connect. Default `1000`. - [ ] `cryostat.agent.webclient.response.timeout-ms` [`long`]: the duration in milliseconds to wait for HTTP requests to the Cryostat server to respond. Default `1000`. - [ ] `cryostat.agent.webserver.host` [`String`]: the internal hostname or IP address for the embedded webserver to bind to. Default `0.0.0.0`. diff --git a/src/main/java/io/cryostat/agent/ConfigModule.java b/src/main/java/io/cryostat/agent/ConfigModule.java index b8466377..bacbd6d1 100644 --- a/src/main/java/io/cryostat/agent/ConfigModule.java +++ b/src/main/java/io/cryostat/agent/ConfigModule.java @@ -76,7 +76,7 @@ public abstract class ConfigModule { "cryostat.agent.webclient.connect.timeout-ms"; public static final String CRYOSTAT_AGENT_WEBCLIENT_RESPONSE_TIMEOUT_MS = "cryostat.agent.webclient.response.timeout-ms"; - public static final String CRYOSTAT_AGENT_WEBCLIENT_TLS_TRUSTSTORES = + public static final String CRYOSTAT_AGENT_WEBCLIENT_TLS_TRUSTSTORE_CERTS = "cryostat.agent.webclient.tls.truststore.cert"; public static final Pattern CRYOSTAT_AGENT_TRUSTSTORE_PATTERN = Pattern.compile( @@ -170,64 +170,6 @@ public static Config provideConfig() { } } - @Provides - @Singleton - @Named(CRYOSTAT_AGENT_WEBCLIENT_TLS_TRUSTSTORES) - public static List provideTruststoreConfigs(Config config) { - Map truststoreBuilders = new HashMap<>(); - StreamSupport.stream(config.getPropertyNames().spliterator(), false) - .filter(e -> e.startsWith(CRYOSTAT_AGENT_WEBCLIENT_TLS_TRUSTSTORES)) - .forEach( - name -> { - Matcher matcher = CRYOSTAT_AGENT_TRUSTSTORE_PATTERN.matcher(name); - if (!matcher.matches()) { - throw new IllegalArgumentException( - String.format( - "Invalid truststore config property name format:" - + " \"%s\". Make sure the config property" - + " matches the following pattern:" - + " 'cryostat.agent.truststore.cert[CERT_NUMBER].CERT_PROPERTY'", - name)); - } - int truststoreNumber = Integer.parseInt(matcher.group("index")); - String configProp = matcher.group("property"); - - TruststoreConfig.Builder truststoreBuilder = - truststoreBuilders.computeIfAbsent( - truststoreNumber, k -> new TruststoreConfig.Builder()); - - String value = config.getValue(name, String.class); - switch (configProp) { - case "alias": - truststoreBuilder = truststoreBuilder.withAlias(value); - break; - case "path": - truststoreBuilder = truststoreBuilder.withPath(value); - break; - case "type": - truststoreBuilder = truststoreBuilder.withType(value); - break; - default: - throw new IllegalArgumentException( - String.format( - "Truststore config only includes alias, path," - + " and type. Rename this config property:" - + " %s", - name)); - } - }); - - List truststoreConfigs = new ArrayList<>(); - for (TruststoreConfig.Builder builder : truststoreBuilders.values()) { - try { - truststoreConfigs.add(builder.build()); - } catch (Exception e) { - throw new IllegalStateException(e); - } - } - return truststoreConfigs; - } - @Provides @Named(CRYOSTAT_AGENT_BASEURI_RANGE) public static URIRange provideUriRange(Config config) { @@ -309,6 +251,65 @@ public static int provideCryostatAgentWebclientResponseTimeoutMs(Config config) return config.getValue(CRYOSTAT_AGENT_WEBCLIENT_RESPONSE_TIMEOUT_MS, int.class); } + @Provides + @Singleton + @Named(CRYOSTAT_AGENT_WEBCLIENT_TLS_TRUSTSTORE_CERTS) + public static List provideCryostatAgentWecblientTlsTruststoreCerts( + Config config) { + Map truststoreBuilders = new HashMap<>(); + StreamSupport.stream(config.getPropertyNames().spliterator(), false) + .filter(e -> e.startsWith(CRYOSTAT_AGENT_WEBCLIENT_TLS_TRUSTSTORE_CERTS)) + .forEach( + name -> { + Matcher matcher = CRYOSTAT_AGENT_TRUSTSTORE_PATTERN.matcher(name); + if (!matcher.matches()) { + throw new IllegalArgumentException( + String.format( + "Invalid truststore config property name format:" + + " \"%s\". Make sure the config property" + + " matches the following pattern:" + + " 'cryostat.agent.truststore.cert[CERT_NUMBER].CERT_PROPERTY'", + name)); + } + int truststoreNumber = Integer.parseInt(matcher.group("index")); + String configProp = matcher.group("property"); + + TruststoreConfig.Builder truststoreBuilder = + truststoreBuilders.computeIfAbsent( + truststoreNumber, k -> new TruststoreConfig.Builder()); + + String value = config.getValue(name, String.class); + switch (configProp) { + case "alias": + truststoreBuilder = truststoreBuilder.withAlias(value); + break; + case "path": + truststoreBuilder = truststoreBuilder.withPath(value); + break; + case "type": + truststoreBuilder = truststoreBuilder.withType(value); + break; + default: + throw new IllegalArgumentException( + String.format( + "Truststore config only includes alias, path," + + " and type. Rename this config property:" + + " %s", + name)); + } + }); + + List truststoreConfigs = new ArrayList<>(); + for (TruststoreConfig.Builder builder : truststoreBuilders.values()) { + try { + truststoreConfigs.add(builder.build()); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + return truststoreConfigs; + } + @Provides @Singleton @Named(CRYOSTAT_AGENT_WEBSERVER_HOST) diff --git a/src/main/java/io/cryostat/agent/MainModule.java b/src/main/java/io/cryostat/agent/MainModule.java index 623c2338..f7e28cfd 100644 --- a/src/main/java/io/cryostat/agent/MainModule.java +++ b/src/main/java/io/cryostat/agent/MainModule.java @@ -132,7 +132,7 @@ public static WebServer provideWebServer( public static SSLContext provideClientSslContext( @Named(ConfigModule.CRYOSTAT_AGENT_WEBCLIENT_TLS_VERSION) String clientTlsVersion, @Named(ConfigModule.CRYOSTAT_AGENT_WEBCLIENT_TLS_TRUST_ALL) boolean trustAll, - @Named(ConfigModule.CRYOSTAT_AGENT_WEBCLIENT_TLS_TRUSTSTORES) + @Named(ConfigModule.CRYOSTAT_AGENT_WEBCLIENT_TLS_TRUSTSTORE_CERTS) List truststores) { try { if (trustAll) {