Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tls): Use TLS by default in the agent #554

Merged
merged 10 commits into from
Dec 20, 2024
Merged
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,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.required` [`boolean`]: Specify whether the agent should require TLS on Cryostat server connections, expecting the base URI to be an https connection with a certificate it trusts. Defaults to `true`. Should only be disabled for testing/prototyping purposes.
- [ ] `cryostat.agent.webclient.tls.trustore.cert` [`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.cert[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.truststore.type` [`String`]: the type of truststore used for the agent's client truststore. Default `JKS`.
- [ ] `cryostat.agent.webclient.tls.truststore.path` [`String`]: the filepath to the agent's webclient truststore. This takes precedence over `cryostat.agent.webclient.tls.truststore.cert` and must be configured with the truststore's pass with `cryostat.agent.webclient.tls.truststore.pass.file` or `cryostat.agent.webclient.tls.truststore.pass`.
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/io/cryostat/agent/ConfigModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@ public abstract class ConfigModule {
public static final String CRYOSTAT_AGENT_WEBCLIENT_RESPONSE_RETRY_COUNT =
"cryostat.agent.webclient.response.retry-count";

public static final String CRYOSTAT_AGENT_WEBCLIENT_TLS_REQUIRED =
"cryostat.agent.webclient.tls.required";

public static final String CRYOSTAT_AGENT_WEBSERVER_HOST = "cryostat.agent.webserver.host";
public static final String CRYOSTAT_AGENT_WEBSERVER_PORT = "cryostat.agent.webserver.port";
public static final String CRYOSTAT_AGENT_WEBSERVER_TLS_VERSION =
Expand Down Expand Up @@ -959,6 +962,13 @@ public static long provideCryostatSmartTriggerEvaluationPeriodMs(Config config)
return config.getValue(CRYOSTAT_AGENT_SMART_TRIGGER_EVALUATION_PERIOD_MS, long.class);
}

@Provides
@Singleton
@Named(CRYOSTAT_AGENT_WEBCLIENT_TLS_REQUIRED)
public static boolean provideCryostatAgentTlsEnabled(Config config) {
return config.getValue(CRYOSTAT_AGENT_WEBCLIENT_TLS_REQUIRED, boolean.class);
}

public enum URIRange {
LOOPBACK(u -> check(u, u2 -> true, InetAddress::isLoopbackAddress)),
LINK_LOCAL(
Expand Down
28 changes: 20 additions & 8 deletions src/main/java/io/cryostat/agent/MainModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.socket.ConnectionSocketFactory;
Expand Down Expand Up @@ -236,9 +235,19 @@ public static SSLContext provideClientSslContext(
@Named(ConfigModule.CRYOSTAT_AGENT_WEBCLIENT_TLS_CLIENT_AUTH_KEY_PASS_CHARSET)
String clientAuthKeyPassFileCharset,
@Named(ConfigModule.CRYOSTAT_AGENT_WEBCLIENT_TLS_CLIENT_AUTH_KEY_MANAGER_TYPE)
String clientAuthKeyManagerType) {
String clientAuthKeyManagerType,
@Named(ConfigModule.CRYOSTAT_AGENT_BASEURI) URI baseUri,
@Named(ConfigModule.CRYOSTAT_AGENT_WEBCLIENT_TLS_REQUIRED) boolean tlsRequired) {
try {
KeyManager[] keyManagers = null;
if (tlsRequired && !baseUri.getScheme().equals("https")) {
throw new IllegalArgumentException(
String.format(
"If TLS is enabled via the (%s) property, the base URI (%s)"
+ " must be an https connection.",
ConfigModule.CRYOSTAT_AGENT_WEBCLIENT_TLS_REQUIRED,
ConfigModule.CRYOSTAT_AGENT_BASEURI));
}
if (clientAuthCertPath.isPresent() && clientAuthKeyPath.isPresent()) {
KeyStore ks = KeyStore.getInstance(clientAuthKeystoreType);
Optional<CharBuffer> keystorePass =
Expand Down Expand Up @@ -610,20 +619,23 @@ public static HttpClient provideHttpClient(
boolean verifyHostname,
@Named(ConfigModule.CRYOSTAT_AGENT_WEBCLIENT_CONNECT_TIMEOUT_MS) int connectTimeout,
@Named(ConfigModule.CRYOSTAT_AGENT_WEBCLIENT_RESPONSE_TIMEOUT_MS) int responseTimeout,
@Named(ConfigModule.CRYOSTAT_AGENT_WEBCLIENT_RESPONSE_RETRY_COUNT) int retryCount) {
@Named(ConfigModule.CRYOSTAT_AGENT_WEBCLIENT_RESPONSE_RETRY_COUNT) int retryCount,
@Named(ConfigModule.CRYOSTAT_AGENT_WEBCLIENT_TLS_REQUIRED) boolean tlsRequired) {
SSLConnectionSocketFactory sslSocketFactory =
new SSLConnectionSocketFactory(
sslContext,
verifyHostname
? SSLConnectionSocketFactory.getDefaultHostnameVerifier()
: NoopHostnameVerifier.INSTANCE);
Registry<ConnectionSocketFactory> socketFactoryRegistry =

RegistryBuilder<ConnectionSocketFactory> socketFactoryRegistryBuilder =
RegistryBuilder.<ConnectionSocketFactory>create()
.register("https", sslSocketFactory)
.register("http", new PlainConnectionSocketFactory())
.build();
.register("https", sslSocketFactory);
if (!tlsRequired) {
socketFactoryRegistryBuilder.register("http", new PlainConnectionSocketFactory());
}
HttpClientConnectionManager connMan =
new BasicHttpClientConnectionManager(socketFactoryRegistry);
new BasicHttpClientConnectionManager(socketFactoryRegistryBuilder.build());
return HttpClients.custom()
.setSSLContext(sslContext)
.setSSLSocketFactory(sslSocketFactory)
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/META-INF/microprofile-config.properties
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ cryostat.agent.webclient.response.retry-count=3
cryostat.agent.webclient.tls.version=TLSv1.2
cryostat.agent.webclient.tls.trust-all=false
cryostat.agent.webclient.tls.verify-hostname=true
cryostat.agent.webclient.tls.required=true
cryostat.agent.webclient.tls.truststore.type=JKS
cryostat.agent.webclient.tls.truststore.pass-charset=utf-8

Expand Down Expand Up @@ -82,3 +83,4 @@ cryostat.agent.harvester.max-size-b=0

cryostat.agent.smart-trigger.definitions=
cryostat.agent.smart-trigger.evaluation.period-ms=1000

Loading