diff --git a/CHANGES.md b/CHANGES.md index c50ae7eff..d2d113437 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,7 @@ ## Version 5.0.0 (Not yet released) +* Validate TLS config for JMX and CQL - Issue #529 * Add support for incremental repairs - Issue #31 * Bump java driver from 4.14.1 to 4.17.0 * Bump guava from 31.1 to 32.0.1 (CVE-2023-2976) diff --git a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/DefaultJmxConnectionProvider.java b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/DefaultJmxConnectionProvider.java index 9c18f8376..5be5a35bd 100644 --- a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/DefaultJmxConnectionProvider.java +++ b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/DefaultJmxConnectionProvider.java @@ -22,16 +22,15 @@ import javax.management.remote.JMXConnector; import com.ericsson.bss.cassandra.ecchronos.application.config.connection.Connection; +import com.ericsson.bss.cassandra.ecchronos.application.config.security.JmxTLSConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.ericsson.bss.cassandra.ecchronos.application.config.Config; import com.ericsson.bss.cassandra.ecchronos.application.config.security.Credentials; import com.ericsson.bss.cassandra.ecchronos.application.config.security.Security; -import com.ericsson.bss.cassandra.ecchronos.application.config.security.TLSConfig; import com.ericsson.bss.cassandra.ecchronos.connection.JmxConnectionProvider; import com.ericsson.bss.cassandra.ecchronos.connection.impl.LocalJmxConnectionProvider; -import com.google.common.base.Joiner; public class DefaultJmxConnectionProvider implements JmxConnectionProvider { @@ -70,19 +69,21 @@ public final void close() throws IOException private Map convertTls(final Supplier jmxSecurity) { - TLSConfig tlsConfig = jmxSecurity.get().getJmxTlsConfig(); + JmxTLSConfig tlsConfig = jmxSecurity.get().getJmxTlsConfig(); if (!tlsConfig.isEnabled()) { return new HashMap<>(); } Map config = new HashMap<>(); - config.put("com.sun.management.jmxremote.ssl.enabled.protocols", tlsConfig.getProtocol()); - String ciphers = tlsConfig.getCipherSuites() - .map(Joiner.on(',')::join) - .orElse(""); - config.put("com.sun.management.jmxremote.ssl.enabled.cipher.suites", ciphers); - + if (tlsConfig.getProtocol() != null) + { + config.put("com.sun.management.jmxremote.ssl.enabled.protocols", tlsConfig.getProtocol()); + } + if (tlsConfig.getCipherSuites() != null) + { + config.put("com.sun.management.jmxremote.ssl.enabled.cipher.suites", tlsConfig.getCipherSuites()); + } config.put("javax.net.ssl.keyStore", tlsConfig.getKeyStorePath()); config.put("javax.net.ssl.keyStorePassword", tlsConfig.getKeyStorePassword()); config.put("javax.net.ssl.trustStore", tlsConfig.getTrustStorePath()); diff --git a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/ReloadingCertificateHandler.java b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/ReloadingCertificateHandler.java index 5bd48d08e..fd8adf27e 100644 --- a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/ReloadingCertificateHandler.java +++ b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/ReloadingCertificateHandler.java @@ -15,7 +15,7 @@ package com.ericsson.bss.cassandra.ecchronos.application; import com.datastax.oss.driver.api.core.metadata.EndPoint; -import com.ericsson.bss.cassandra.ecchronos.application.config.security.TLSConfig; +import com.ericsson.bss.cassandra.ecchronos.application.config.security.CqlTLSConfig; import com.ericsson.bss.cassandra.ecchronos.connection.CertificateHandler; import io.netty.buffer.ByteBufAllocator; import io.netty.handler.ssl.SslContext; @@ -53,11 +53,11 @@ public class ReloadingCertificateHandler implements CertificateHandler private static final Logger LOG = LoggerFactory.getLogger(ReloadingCertificateHandler.class); private final AtomicReference currentContext = new AtomicReference<>(); - private final Supplier tlsConfigSupplier; + private final Supplier myCqlTLSConfigSupplier; - public ReloadingCertificateHandler(final Supplier aTLSConfigSupplier) + public ReloadingCertificateHandler(final Supplier cqlTLSConfigSupplier) { - this.tlsConfigSupplier = aTLSConfigSupplier; + this.myCqlTLSConfigSupplier = cqlTLSConfigSupplier; } /** @@ -70,7 +70,7 @@ public ReloadingCertificateHandler(final Supplier aTLSConfigSupplier) public SSLEngine newSslEngine(final EndPoint remoteEndpoint) { Context context = getContext(); - TLSConfig tlsConfig = context.getTlsConfig(); + CqlTLSConfig tlsConfig = context.getTlsConfig(); SslContext sslContext = context.getSSLContext(); SSLEngine sslEngine; @@ -98,7 +98,7 @@ public SSLEngine newSslEngine(final EndPoint remoteEndpoint) protected final Context getContext() { - TLSConfig tlsConfig = tlsConfigSupplier.get(); + CqlTLSConfig tlsConfig = myCqlTLSConfigSupplier.get(); Context context = currentContext.get(); try @@ -114,7 +114,7 @@ protected final Context getContext() { context = currentContext.get(); } - tlsConfig = tlsConfigSupplier.get(); + tlsConfig = myCqlTLSConfigSupplier.get(); } } catch (NoSuchAlgorithmException | IOException | UnrecoverableKeyException | CertificateException @@ -134,11 +134,11 @@ public void close() throws Exception protected static final class Context { - private final TLSConfig myTlsConfig; + private final CqlTLSConfig myTlsConfig; private final SslContext mySslContext; private final Map myChecksums = new HashMap<>(); - Context(final TLSConfig tlsConfig) throws NoSuchAlgorithmException, IOException, UnrecoverableKeyException, + Context(final CqlTLSConfig tlsConfig) throws NoSuchAlgorithmException, IOException, UnrecoverableKeyException, CertificateException, KeyStoreException, KeyManagementException { myTlsConfig = tlsConfig; @@ -146,12 +146,12 @@ protected static final class Context myChecksums.putAll(calculateChecksums(myTlsConfig)); } - TLSConfig getTlsConfig() + CqlTLSConfig getTlsConfig() { return myTlsConfig; } - boolean sameConfig(final TLSConfig newTLSConfig) throws IOException, NoSuchAlgorithmException + boolean sameConfig(final CqlTLSConfig newTLSConfig) throws IOException, NoSuchAlgorithmException { if (!myTlsConfig.equals(newTLSConfig)) { @@ -160,18 +160,16 @@ boolean sameConfig(final TLSConfig newTLSConfig) throws IOException, NoSuchAlgor return checksumSame(newTLSConfig); } - private boolean checksumSame(final TLSConfig newTLSConfig) throws IOException, NoSuchAlgorithmException + private boolean checksumSame(final CqlTLSConfig newTLSConfig) throws IOException, NoSuchAlgorithmException { return myChecksums.equals(calculateChecksums(newTLSConfig)); } - private Map calculateChecksums(final TLSConfig tlsConfig) + private Map calculateChecksums(final CqlTLSConfig tlsConfig) throws IOException, NoSuchAlgorithmException { Map checksums = new HashMap<>(); - if (tlsConfig.getCertificatePath().isPresent() - && tlsConfig.getCertificatePrivateKeyPath().isPresent() - && tlsConfig.getTrustCertificatePath().isPresent()) + if (tlsConfig.isCertificateConfigured()) { String certificate = tlsConfig.getCertificatePath().get(); checksums.put(certificate, getChecksum(certificate)); @@ -203,7 +201,7 @@ SslContext getSSLContext() } } - protected static SslContext createSSLContext(final TLSConfig tlsConfig) throws IOException, + protected static SslContext createSSLContext(final CqlTLSConfig tlsConfig) throws IOException, NoSuchAlgorithmException, KeyStoreException, CertificateException, @@ -211,10 +209,7 @@ protected static SslContext createSSLContext(final TLSConfig tlsConfig) throws I { SslContextBuilder builder = SslContextBuilder.forClient(); - - if (tlsConfig.getCertificatePath().isPresent() - && tlsConfig.getCertificatePrivateKeyPath().isPresent() - && tlsConfig.getTrustCertificatePath().isPresent()) + if (tlsConfig.isCertificateConfigured()) { File certificateFile = new File(tlsConfig.getCertificatePath().get()); File certificatePrivateKeyFile = new File(tlsConfig.getCertificatePrivateKeyPath().get()); @@ -237,7 +232,7 @@ protected static SslContext createSSLContext(final TLSConfig tlsConfig) throws I return builder.protocols(tlsConfig.getProtocols()).build(); } - protected static KeyManagerFactory getKeyManagerFactory(final TLSConfig tlsConfig) throws IOException, + protected static KeyManagerFactory getKeyManagerFactory(final CqlTLSConfig tlsConfig) throws IOException, NoSuchAlgorithmException, KeyStoreException, CertificateException, UnrecoverableKeyException { String algorithm = tlsConfig.getAlgorithm().orElse(KeyManagerFactory.getDefaultAlgorithm()); @@ -246,14 +241,14 @@ protected static KeyManagerFactory getKeyManagerFactory(final TLSConfig tlsConfi try (InputStream keystoreFile = new FileInputStream(tlsConfig.getKeyStorePath())) { KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(algorithm); - KeyStore keyStore = KeyStore.getInstance(tlsConfig.getStoreType()); + KeyStore keyStore = KeyStore.getInstance(tlsConfig.getStoreType().orElse("JKS")); keyStore.load(keystoreFile, keystorePassword); keyManagerFactory.init(keyStore, keystorePassword); return keyManagerFactory; } } - protected static TrustManagerFactory getTrustManagerFactory(final TLSConfig tlsConfig) + protected static TrustManagerFactory getTrustManagerFactory(final CqlTLSConfig tlsConfig) throws IOException, NoSuchAlgorithmException, KeyStoreException, CertificateException { String algorithm = tlsConfig.getAlgorithm().orElse(TrustManagerFactory.getDefaultAlgorithm()); @@ -262,7 +257,7 @@ protected static TrustManagerFactory getTrustManagerFactory(final TLSConfig tlsC try (InputStream truststoreFile = new FileInputStream(tlsConfig.getTrustStorePath())) { TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(algorithm); - KeyStore keyStore = KeyStore.getInstance(tlsConfig.getStoreType()); + KeyStore keyStore = KeyStore.getInstance(tlsConfig.getStoreType().orElse("JKS")); keyStore.load(truststoreFile, truststorePassword); trustManagerFactory.init(keyStore); return trustManagerFactory; diff --git a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/security/TLSConfig.java b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/security/CqlTLSConfig.java similarity index 55% rename from application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/security/TLSConfig.java rename to application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/security/CqlTLSConfig.java index d07bb3882..71a24a7a3 100644 --- a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/security/TLSConfig.java +++ b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/security/CqlTLSConfig.java @@ -14,131 +14,149 @@ */ package com.ericsson.bss.cassandra.ecchronos.application.config.security; +import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.Arrays; import java.util.Objects; import java.util.Optional; - -public class TLSConfig +public class CqlTLSConfig { private static final int HASH_SEED = 31; - private boolean myIsEnabled; + private final boolean myIsEnabled; private String myKeyStorePath; private String myKeyStorePassword; private String myTrustStorePath; private String myTrustStorePassword; + private String myStoreType; + private String myAlgorithm; private String myCertificatePath; private String myCertificatePrivateKeyPath; private String myTrustCertificatePath; private String myProtocol; - private String myAlgorithm; - private String myStoreType; private String[] myCipherSuites; private boolean myRequireEndpointVerification; - @JsonProperty("enabled") - public final boolean isEnabled() - { - return myIsEnabled; + @JsonCreator + public CqlTLSConfig(@JsonProperty("enabled") final boolean isEnabled, + @JsonProperty("keystore") final String keyStorePath, + @JsonProperty("keystore_password") final String keyStorePassword, + @JsonProperty("truststore") final String trustStorePath, + @JsonProperty("truststore_password") final String trustStorePassword, + @JsonProperty("certificate") final String certificatePath, + @JsonProperty("certificate_private_key") final String certificatePrivateKeyPath, + @JsonProperty("trust_certificate") final String trustCertificatePath) + { + myIsEnabled = isEnabled; + myKeyStorePath = keyStorePath; + myKeyStorePassword = keyStorePassword; + myTrustStorePath = trustStorePath; + myTrustStorePassword = trustStorePassword; + myCertificatePath = certificatePath; + myCertificatePrivateKeyPath = certificatePrivateKeyPath; + myTrustCertificatePath = trustCertificatePath; + if (myIsEnabled && !isKeyStoreConfigured() && !isCertificateConfigured()) + { + throw new IllegalArgumentException("Invalid CQL TLS config, you must either configure KeyStore or PEM based" + + " certificates."); + } } - @JsonProperty("enabled") - public final void setEnabled(final boolean enabled) + private boolean isKeyStoreConfigured() { - myIsEnabled = enabled; + return myKeyStorePath != null && !myKeyStorePath.isEmpty() + && myKeyStorePassword != null && myKeyStorePassword != null + && myTrustStorePath != null && !myTrustStorePath.isEmpty() + && myTrustStorePassword != null && !myTrustStorePassword.isEmpty(); } - @JsonProperty("keystore") - public final String getKeyStorePath() + public final boolean isCertificateConfigured() { - return myKeyStorePath; + return getCertificatePath().isPresent() && getCertificatePrivateKeyPath().isPresent() + && getTrustCertificatePath().isPresent(); } - @JsonProperty("keystore") - public final void setKeyStorePath(final String keyStorePath) + public CqlTLSConfig(final boolean isEnabled, final String keyStorePath, final String keyStorePassword, + final String trustStorePath, final String trustStorePassword) { + myIsEnabled = isEnabled; myKeyStorePath = keyStorePath; + myKeyStorePassword = keyStorePassword; + myTrustStorePath = trustStorePath; + myTrustStorePassword = trustStorePassword; } - @JsonProperty("keystore_password") - public final String getKeyStorePassword() + public CqlTLSConfig(final boolean isEnabled, final String certificatePath, final String certificatePrivateKeyPath, + final String trustCertificatePath) { - return myKeyStorePassword; + myIsEnabled = isEnabled; + myCertificatePath = certificatePath; + myCertificatePrivateKeyPath = certificatePrivateKeyPath; + myTrustCertificatePath = trustCertificatePath; } - @JsonProperty("keystore_password") - public final void setKeyStorePassword(final String keyStorePassword) + public final boolean isEnabled() { - myKeyStorePassword = keyStorePassword; + return myIsEnabled; } - @JsonProperty("truststore") - public final String getTrustStorePath() + public final String getKeyStorePath() { - return myTrustStorePath; + return myKeyStorePath; } - @JsonProperty("truststore") - public final void setTrustStorePath(final String trustStorePath) + public final String getKeyStorePassword() { - myTrustStorePath = trustStorePath; + return myKeyStorePassword; } - @JsonProperty("truststore_password") - public final String getTrustStorePassword() + public final String getTrustStorePath() { - return myTrustStorePassword; + return myTrustStorePath; } - @JsonProperty("truststore_password") - public final void setTrustStorePassword(final String trustStorePassword) + public final String getTrustStorePassword() { - myTrustStorePassword = trustStorePassword; + return myTrustStorePassword; } - @JsonProperty("certificate") - public final Optional getCertificatePath() + public final Optional getStoreType() { - return Optional.ofNullable(myCertificatePath); + return Optional.ofNullable(myStoreType); } - @JsonProperty("certificate") - public final void setCertificatePath(final String certificatePath) + @JsonProperty("store_type") + public final void setStoreType(final String storeType) { - myCertificatePath = certificatePath; + myStoreType = storeType; } - @JsonProperty("certificate_private_key") - public final Optional getCertificatePrivateKeyPath() + public final Optional getAlgorithm() { - return Optional.ofNullable(myCertificatePrivateKeyPath); + return Optional.ofNullable(myAlgorithm); } - @JsonProperty("certificate_private_key") - public final void setCertificatePrivateKeyPath(final String certificatePrivateKeyPath) + @JsonProperty("algorithm") + public final void setAlgorithm(final String algorithm) { - myCertificatePrivateKeyPath = certificatePrivateKeyPath; + myAlgorithm = algorithm; } - @JsonProperty("trust_certificate") - public final Optional getTrustCertificatePath() + public final Optional getCertificatePath() { - return Optional.ofNullable(myTrustCertificatePath); + return Optional.ofNullable(myCertificatePath); } - @JsonProperty("trust_certificate") - public final void setTrustCertificatePath(final String trustCertificatePath) + public final Optional getCertificatePrivateKeyPath() { - myTrustCertificatePath = trustCertificatePath; + return Optional.ofNullable(myCertificatePrivateKeyPath); } - @JsonProperty("protocol") - public final String getProtocol() + public final Optional getTrustCertificatePath() { - return myProtocol; + return Optional.ofNullable(myTrustCertificatePath); } @JsonProperty("protocol") @@ -147,7 +165,6 @@ public final void setProtocol(final String protocol) myProtocol = protocol; } - @JsonProperty("cipher_suites") public final Optional getCipherSuites() { if (myCipherSuites == null) @@ -169,31 +186,15 @@ private static String[] transformCiphers(final String cipherSuites) return cipherSuites == null ? null : cipherSuites.split(","); } - @JsonProperty("algorithm") - public final Optional getAlgorithm() - { - return Optional.ofNullable(myAlgorithm); - } - - @JsonProperty("algorithm") - public final void setAlgorithm(final String algorithm) - { - myAlgorithm = algorithm; - } - - @JsonProperty("store_type") - public final String getStoreType() - { - return myStoreType; - } - - @JsonProperty("store_type") - public final void setStoreType(final String storeType) + public final String[] getProtocols() { - myStoreType = storeType; + if (myProtocol == null) + { + return null; + } + return myProtocol.split(","); } - @JsonProperty("require_endpoint_verification") public final boolean requiresEndpointVerification() { return myRequireEndpointVerification; @@ -205,11 +206,6 @@ public final void setRequireEndpointVerification(final boolean requireEndpointVe myRequireEndpointVerification = requireEndpointVerification; } - public final String[] getProtocols() - { - return myProtocol.split(","); - } - @Override public final boolean equals(final Object o) { @@ -221,28 +217,27 @@ public final boolean equals(final Object o) { return false; } - TLSConfig tlsConfig = (TLSConfig) o; - return myIsEnabled == tlsConfig.myIsEnabled - && myRequireEndpointVerification == tlsConfig.myRequireEndpointVerification - && Objects.equals(myKeyStorePath, tlsConfig.myKeyStorePath) - && Objects.equals(myKeyStorePassword, tlsConfig.myKeyStorePassword) - && Objects.equals(myTrustStorePath, tlsConfig.myTrustStorePath) - && Objects.equals(myTrustStorePassword, tlsConfig.myTrustStorePassword) - && Objects.equals(myCertificatePath, tlsConfig.myCertificatePath) - && Objects.equals(myCertificatePrivateKeyPath, tlsConfig.myCertificatePrivateKeyPath) - && Objects.equals(myTrustCertificatePath, tlsConfig.myTrustCertificatePath) - && Objects.equals(myProtocol, tlsConfig.myProtocol) - && Objects.equals(myAlgorithm, tlsConfig.myAlgorithm) - && Objects.equals(myStoreType, tlsConfig.myStoreType) - && Arrays.equals(myCipherSuites, tlsConfig.myCipherSuites); + CqlTLSConfig that = (CqlTLSConfig) o; + return myIsEnabled == that.myIsEnabled && myRequireEndpointVerification == that.myRequireEndpointVerification + && Objects.equals(myKeyStorePath, that.myKeyStorePath) + && Objects.equals(myKeyStorePassword, that.myKeyStorePassword) + && Objects.equals(myTrustStorePath, that.myTrustStorePath) + && Objects.equals(myTrustStorePassword, that.myTrustStorePassword) + && Objects.equals(myStoreType, that.myStoreType) + && Objects.equals(myAlgorithm, that.myAlgorithm) + && Objects.equals(myCertificatePath, that.myCertificatePath) + && Objects.equals(myCertificatePrivateKeyPath, that.myCertificatePrivateKeyPath) + && Objects.equals(myTrustCertificatePath, that.myTrustCertificatePath) + && Objects.equals(myProtocol, that.myProtocol) && Arrays.equals(myCipherSuites, that.myCipherSuites); } @Override public final int hashCode() { int result = Objects.hash(myIsEnabled, myKeyStorePath, myKeyStorePassword, myTrustStorePath, - myTrustStorePassword, myCertificatePath, myCertificatePrivateKeyPath, myTrustCertificatePath, - myProtocol, myAlgorithm, myStoreType, myRequireEndpointVerification); + myTrustStorePassword, + myStoreType, myAlgorithm, myCertificatePath, myCertificatePrivateKeyPath, myTrustCertificatePath, + myProtocol, myRequireEndpointVerification); result = HASH_SEED * result + Arrays.hashCode(myCipherSuites); return result; } diff --git a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/security/JmxTLSConfig.java b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/security/JmxTLSConfig.java new file mode 100644 index 000000000..a6ecc43ff --- /dev/null +++ b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/security/JmxTLSConfig.java @@ -0,0 +1,132 @@ +/* + * Copyright 2023 Telefonaktiebolaget LM Ericsson + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.ericsson.bss.cassandra.ecchronos.application.config.security; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Objects; + +public class JmxTLSConfig +{ + private final boolean myIsEnabled; + private final String myKeyStorePath; + private final String myKeyStorePassword; + private final String myTrustStorePath; + private final String myTrustStorePassword; + private String myProtocol; + private String myCipherSuites; + + @JsonCreator + public JmxTLSConfig(@JsonProperty("enabled") final boolean isEnabled, + @JsonProperty("keystore") final String keyStorePath, + @JsonProperty("keystore_password") final String keyStorePassword, + @JsonProperty("truststore") final String trustStorePath, + @JsonProperty("truststore_password") final String trustStorePassword) + { + myIsEnabled = isEnabled; + myKeyStorePath = keyStorePath; + myKeyStorePassword = keyStorePassword; + myTrustStorePath = trustStorePath; + myTrustStorePassword = trustStorePassword; + if (myIsEnabled && !isKeyStoreConfigured()) + { + throw new IllegalArgumentException("Invalid JMX TLS config, you must configure KeyStore based" + + " certificates."); + } + } + + private boolean isKeyStoreConfigured() + { + return myKeyStorePath != null && !myKeyStorePath.isEmpty() + && myKeyStorePassword != null && myKeyStorePassword != null + && myTrustStorePath != null && !myTrustStorePath.isEmpty() + && myTrustStorePassword != null && !myTrustStorePassword.isEmpty(); + } + + public final boolean isEnabled() + { + return myIsEnabled; + } + + public final String getKeyStorePath() + { + return myKeyStorePath; + } + + public final String getKeyStorePassword() + { + return myKeyStorePassword; + } + + public final String getTrustStorePath() + { + return myTrustStorePath; + } + + public final String getTrustStorePassword() + { + return myTrustStorePassword; + } + + public final String getProtocol() + { + return myProtocol; + } + + @JsonProperty("protocol") + public final void setProtocol(final String protocol) + { + myProtocol = protocol; + } + + public final String getCipherSuites() + { + return myCipherSuites; + } + + @JsonProperty("cipher_suites") + public final void setCipherSuites(final String cipherSuites) + { + myCipherSuites = cipherSuites; + } + + @Override + public final boolean equals(final Object o) + { + if (this == o) + { + return true; + } + if (o == null || getClass() != o.getClass()) + { + return false; + } + JmxTLSConfig that = (JmxTLSConfig) o; + return myIsEnabled == that.myIsEnabled + && Objects.equals(myKeyStorePath, that.myKeyStorePath) + && Objects.equals(myKeyStorePassword, that.myKeyStorePassword) + && Objects.equals(myTrustStorePath, that.myTrustStorePath) + && Objects.equals(myTrustStorePassword, that.myTrustStorePassword) + && Objects.equals(myProtocol, that.myProtocol) && Objects.equals(myCipherSuites, that.myCipherSuites); + } + + @Override + public final int hashCode() + { + return Objects.hash(myIsEnabled, myKeyStorePath, myKeyStorePassword, myTrustStorePath, + myTrustStorePassword, myProtocol, myCipherSuites); + } +} diff --git a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/security/Security.java b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/security/Security.java index f1894df68..1d976ab54 100644 --- a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/security/Security.java +++ b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/security/Security.java @@ -48,7 +48,7 @@ public void setJmxSecurity(final JmxSecurity jmxSecurity) public static final class CqlSecurity { private Credentials myCqlCredentials; - private TLSConfig myCqlTlsConfig; + private CqlTLSConfig myCqlTlsConfig; @JsonProperty("credentials") public Credentials getCqlCredentials() @@ -63,13 +63,13 @@ public void setCqlCredentials(final Credentials cqlCredentials) } @JsonProperty("tls") - public TLSConfig getCqlTlsConfig() + public CqlTLSConfig getCqlTlsConfig() { return myCqlTlsConfig; } @JsonProperty("tls") - public void setCqlTlsConfig(final TLSConfig cqlTlsConfig) + public void setCqlTlsConfig(final CqlTLSConfig cqlTlsConfig) { myCqlTlsConfig = cqlTlsConfig; } @@ -78,7 +78,7 @@ public void setCqlTlsConfig(final TLSConfig cqlTlsConfig) public static final class JmxSecurity { private Credentials myJmxCredentials; - private TLSConfig myJmxTlsConfig; + private JmxTLSConfig myJmxTlsConfig; @JsonProperty("credentials") public Credentials getJmxCredentials() @@ -93,13 +93,13 @@ public void setJmxCredentials(final Credentials jmxCredentials) } @JsonProperty("tls") - public TLSConfig getJmxTlsConfig() + public JmxTLSConfig getJmxTlsConfig() { return myJmxTlsConfig; } @JsonProperty("tls") - public void setJmxTlsConfig(final TLSConfig jmxTlsConfig) + public void setJmxTlsConfig(final JmxTLSConfig jmxTlsConfig) { myJmxTlsConfig = jmxTlsConfig; } diff --git a/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/TestReloadingCertificateHandler.java b/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/TestReloadingCertificateHandler.java index c63b40754..5cb9e9e64 100644 --- a/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/TestReloadingCertificateHandler.java +++ b/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/TestReloadingCertificateHandler.java @@ -15,7 +15,7 @@ package com.ericsson.bss.cassandra.ecchronos.application; -import com.ericsson.bss.cassandra.ecchronos.application.config.security.TLSConfig; +import com.ericsson.bss.cassandra.ecchronos.application.config.security.CqlTLSConfig; import com.ericsson.bss.cassandra.ecchronos.application.utils.CertUtils; import org.junit.BeforeClass; import org.junit.Test; @@ -167,25 +167,19 @@ public void testNewSslEngineDifferentContextWhenCertificateChangesPEM() assertThat(newContext).isNotEqualTo(oldContext); } - private TLSConfig getTLSConfigWithKeyStore() + private CqlTLSConfig getTLSConfigWithKeyStore() { - TLSConfig tlsConfig = new TLSConfig(); - tlsConfig.setKeyStorePath(clientKeyStore); - tlsConfig.setTrustStorePath(clientTrustStore); - tlsConfig.setKeyStorePassword(KEYSTORE_PASSWORD); - tlsConfig.setTrustStorePassword(KEYSTORE_PASSWORD); - tlsConfig.setStoreType(STORE_TYPE_JKS); - tlsConfig.setProtocol(protocolVersion); - return tlsConfig; + CqlTLSConfig cqlTLSConfig = new CqlTLSConfig(true, clientKeyStore, KEYSTORE_PASSWORD, clientTrustStore, + KEYSTORE_PASSWORD); + cqlTLSConfig.setStoreType(STORE_TYPE_JKS); + cqlTLSConfig.setProtocol(protocolVersion); + return cqlTLSConfig; } - private TLSConfig getTLSConfigWithPEMFiles() + private CqlTLSConfig getTLSConfigWithPEMFiles() { - TLSConfig tlsConfig = new TLSConfig(); - tlsConfig.setCertificatePath(clientCert); - tlsConfig.setCertificatePrivateKeyPath(clientCertKey); - tlsConfig.setTrustCertificatePath(clientCaCert); - tlsConfig.setProtocol(protocolVersion); - return tlsConfig; + CqlTLSConfig cqlTLSConfig = new CqlTLSConfig(true, clientCert, clientCertKey, clientCaCert); + cqlTLSConfig.setProtocol(protocolVersion); + return cqlTLSConfig; } } diff --git a/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/config/TestConfig.java b/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/config/TestConfig.java index 1dc372805..4e2d945f6 100644 --- a/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/config/TestConfig.java +++ b/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/config/TestConfig.java @@ -36,8 +36,8 @@ import com.ericsson.bss.cassandra.ecchronos.application.config.rest.RestServerConfig; import com.ericsson.bss.cassandra.ecchronos.application.config.runpolicy.RunPolicyConfig; import com.ericsson.bss.cassandra.ecchronos.application.config.scheduler.SchedulerConfig; +import com.ericsson.bss.cassandra.ecchronos.application.config.security.CqlTLSConfig; import com.ericsson.bss.cassandra.ecchronos.application.config.security.Security; -import com.ericsson.bss.cassandra.ecchronos.application.config.security.TLSConfig; import com.ericsson.bss.cassandra.ecchronos.connection.CertificateHandler; import com.ericsson.bss.cassandra.ecchronos.connection.JmxConnectionProvider; import com.ericsson.bss.cassandra.ecchronos.connection.NativeConnectionProvider; @@ -379,7 +379,7 @@ public boolean getRemoteRouting() public static class TestCertificateHandler implements CertificateHandler { - public TestCertificateHandler(Supplier tlsConfigSupplier) + public TestCertificateHandler(Supplier tlsConfigSupplier) { // Empty constructor } diff --git a/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/config/security/TestSecurity.java b/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/config/security/TestSecurity.java index b6003aff3..3313614ba 100644 --- a/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/config/security/TestSecurity.java +++ b/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/config/security/TestSecurity.java @@ -15,12 +15,15 @@ package com.ericsson.bss.cassandra.ecchronos.application.config.security; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.exc.ValueInstantiationException; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import org.junit.Test; import java.io.File; +import java.io.IOException; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; public class TestSecurity { @@ -36,41 +39,27 @@ public void testDefault() throws Exception Credentials expectedCredentials = new Credentials(false, "cassandra", "cassandra"); - TLSConfig cqlTlsConfig = new TLSConfig(); - cqlTlsConfig.setEnabled(false); - cqlTlsConfig.setKeyStorePath("/path/to/keystore"); - cqlTlsConfig.setKeyStorePassword("ecchronos"); - cqlTlsConfig.setTrustStorePath("/path/to/truststore"); - cqlTlsConfig.setTrustStorePassword("ecchronos"); - cqlTlsConfig.setCertificatePath(null); - cqlTlsConfig.setCertificatePrivateKeyPath(null); - cqlTlsConfig.setTrustCertificatePath(null); - cqlTlsConfig.setProtocol("TLSv1.2"); - cqlTlsConfig.setAlgorithm(null); - cqlTlsConfig.setStoreType("JKS"); - cqlTlsConfig.setCipherSuites(null); - cqlTlsConfig.setRequireEndpointVerification(false); - - TLSConfig jmxTlsConfig = new TLSConfig(); - jmxTlsConfig.setEnabled(false); - jmxTlsConfig.setKeyStorePath("/path/to/keystore"); - jmxTlsConfig.setKeyStorePassword("ecchronos"); - jmxTlsConfig.setTrustStorePath("/path/to/truststore"); - jmxTlsConfig.setTrustStorePassword("ecchronos"); - jmxTlsConfig.setProtocol("TLSv1.2"); - jmxTlsConfig.setCipherSuites(null); + CqlTLSConfig cqlTLSConfig = new CqlTLSConfig(false, "/path/to/keystore", "ecchronos", + "/path/to/truststore", "ecchronos"); + cqlTLSConfig.setStoreType("JKS"); + cqlTLSConfig.setProtocol("TLSv1.2"); + + JmxTLSConfig jmxTLSConfig = new JmxTLSConfig(false, "/path/to/keystore", + "ecchronos", "/path/to/truststore", "ecchronos"); + jmxTLSConfig.setProtocol("TLSv1.2"); + jmxTLSConfig.setCipherSuites(null); assertThat(config.getCqlSecurity().getCqlCredentials()).isEqualTo(expectedCredentials); assertThat(config.getJmxSecurity().getJmxCredentials()).isEqualTo(expectedCredentials); - assertThat(config.getCqlSecurity().getCqlTlsConfig()).isEqualTo(cqlTlsConfig); - assertThat(config.getJmxSecurity().getJmxTlsConfig()).isEqualTo(jmxTlsConfig); + assertThat(config.getCqlSecurity().getCqlTlsConfig()).isEqualTo(cqlTLSConfig); + assertThat(config.getJmxSecurity().getJmxTlsConfig()).isEqualTo(jmxTLSConfig); } @Test - public void testEnabled() throws Exception + public void testCqlAndJmxEnabledKeyStore() throws Exception { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - File file = new File(classLoader.getResource("enabled_security.yml").getFile()); + File file = new File(classLoader.getResource("security/enabled_keystore_jmxandcql.yml").getFile()); ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()); @@ -79,38 +68,30 @@ public void testEnabled() throws Exception Credentials expectedCqlCredentials = new Credentials(true, "cqluser", "cqlpassword"); Credentials expectedJmxCredentials = new Credentials(true, "jmxuser", "jmxpassword"); - TLSConfig cqlTlsConfig = new TLSConfig(); - cqlTlsConfig.setEnabled(true); - cqlTlsConfig.setKeyStorePath("/path/to/cql/keystore"); - cqlTlsConfig.setKeyStorePassword("cqlkeystorepassword"); - cqlTlsConfig.setTrustStorePath("/path/to/cql/truststore"); - cqlTlsConfig.setTrustStorePassword("cqltruststorepassword"); - cqlTlsConfig.setProtocol("TLSv1.2"); - cqlTlsConfig.setAlgorithm("SunX509"); - cqlTlsConfig.setStoreType("JKS"); - cqlTlsConfig.setCipherSuites("VALID_CIPHER_SUITE,VALID_CIPHER_SUITE2"); - cqlTlsConfig.setRequireEndpointVerification(true); - - TLSConfig jmxTlsConfig = new TLSConfig(); - jmxTlsConfig.setEnabled(true); - jmxTlsConfig.setKeyStorePath("/path/to/jmx/keystore"); - jmxTlsConfig.setKeyStorePassword("jmxkeystorepassword"); - jmxTlsConfig.setTrustStorePath("/path/to/jmx/truststore"); - jmxTlsConfig.setTrustStorePassword("jmxtruststorepassword"); - jmxTlsConfig.setProtocol("TLSv1.2"); - jmxTlsConfig.setCipherSuites("VALID_CIPHER_SUITE,VALID_CIPHER_SUITE2"); + CqlTLSConfig cqlTLSConfig = new CqlTLSConfig(true, "/path/to/cql/keystore", + "cqlkeystorepassword", "/path/to/cql/truststore","cqltruststorepassword"); + cqlTLSConfig.setStoreType("JKS"); + cqlTLSConfig.setAlgorithm("SunX509"); + cqlTLSConfig.setProtocol("TLSv1.2"); + cqlTLSConfig.setCipherSuites("VALID_CIPHER_SUITE,VALID_CIPHER_SUITE2"); + cqlTLSConfig.setRequireEndpointVerification(true); + + JmxTLSConfig jmxTLSConfig = new JmxTLSConfig(true, "/path/to/jmx/keystore", + "jmxkeystorepassword", "/path/to/jmx/truststore", "jmxtruststorepassword"); + jmxTLSConfig.setProtocol("TLSv1.2"); + jmxTLSConfig.setCipherSuites("VALID_CIPHER_SUITE,VALID_CIPHER_SUITE2"); assertThat(config.getCqlSecurity().getCqlCredentials()).isEqualTo(expectedCqlCredentials); assertThat(config.getJmxSecurity().getJmxCredentials()).isEqualTo(expectedJmxCredentials); - assertThat(config.getCqlSecurity().getCqlTlsConfig()).isEqualTo(cqlTlsConfig); - assertThat(config.getJmxSecurity().getJmxTlsConfig()).isEqualTo(jmxTlsConfig); + assertThat(config.getCqlSecurity().getCqlTlsConfig()).isEqualTo(cqlTLSConfig); + assertThat(config.getJmxSecurity().getJmxTlsConfig()).isEqualTo(jmxTLSConfig); } @Test - public void testEnabledWithCertificate() throws Exception + public void testCqlEnabledWithCertificate() throws Exception { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - File file = new File(classLoader.getResource("enabled_certificate_security.yml").getFile()); + File file = new File(classLoader.getResource("security/enabled_pem_cql.yml").getFile()); ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()); @@ -118,16 +99,46 @@ public void testEnabledWithCertificate() throws Exception Credentials expectedCqlCredentials = new Credentials(true, "cqluser", "cqlpassword"); - TLSConfig cqlTlsConfig = new TLSConfig(); - cqlTlsConfig.setEnabled(true); - cqlTlsConfig.setCertificatePath("/path/to/cql/certificate"); - cqlTlsConfig.setCertificatePrivateKeyPath("/path/to/cql/certificate_key"); - cqlTlsConfig.setTrustCertificatePath("/path/to/cql/certificate_authorities"); - cqlTlsConfig.setProtocol("TLSv1.2"); - cqlTlsConfig.setCipherSuites("VALID_CIPHER_SUITE,VALID_CIPHER_SUITE2"); - cqlTlsConfig.setRequireEndpointVerification(true); + CqlTLSConfig cqlTLSConfig = new CqlTLSConfig(true, "/path/to/cql/certificate", + "/path/to/cql/certificate_key", "/path/to/cql/certificate_authorities"); + cqlTLSConfig.setProtocol("TLSv1.2"); + cqlTLSConfig.setCipherSuites("VALID_CIPHER_SUITE,VALID_CIPHER_SUITE2"); + cqlTLSConfig.setRequireEndpointVerification(true); assertThat(config.getCqlSecurity().getCqlCredentials()).isEqualTo(expectedCqlCredentials); - assertThat(config.getCqlSecurity().getCqlTlsConfig()).isEqualTo(cqlTlsConfig); + assertThat(config.getCqlSecurity().getCqlTlsConfig()).isEqualTo(cqlTLSConfig); + } + + @Test + public void testJmxEnabledWithCertificate() + { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + File file = new File(classLoader.getResource("security/enabled_pem_jmx.yml").getFile()); + + ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()); + + assertThatExceptionOfType(IOException.class).isThrownBy(() -> objectMapper.readValue(file, Security.class)); + } + + @Test + public void testCqlEnabledWithNothing() + { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + File file = new File(classLoader.getResource("security/enabled_nokeystore_nopem_cql.yml").getFile()); + + ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()); + + assertThatExceptionOfType(ValueInstantiationException.class).isThrownBy(() -> objectMapper.readValue(file, Security.class)); + } + + @Test + public void testJmxEnabledWithNothing() + { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + File file = new File(classLoader.getResource("security/enabled_nokeystore_nopem_jmx.yml").getFile()); + + ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()); + + assertThatExceptionOfType(ValueInstantiationException.class).isThrownBy(() -> objectMapper.readValue(file, Security.class)); } } diff --git a/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/config/security/TestTLSConfig.java b/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/config/security/TestTLSConfig.java deleted file mode 100644 index a9aee700c..000000000 --- a/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/config/security/TestTLSConfig.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2020 Telefonaktiebolaget LM Ericsson - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.ericsson.bss.cassandra.ecchronos.application.config.security; - -import nl.jqno.equalsverifier.Warning; -import org.junit.Test; - -import nl.jqno.equalsverifier.EqualsVerifier; - -import static org.assertj.core.api.Assertions.assertThat; - -public class TestTLSConfig -{ - @Test - public void testSetCipherSuites() - { - TLSConfig tlsConfig = new TLSConfig(); - - tlsConfig.setCipherSuites("test"); - assertThat(tlsConfig.getCipherSuites()).isPresent(); - assertThat(tlsConfig.getCipherSuites().get()).containsExactly("test"); - - tlsConfig.setCipherSuites("test,test2"); - assertThat(tlsConfig.getCipherSuites()).isPresent(); - assertThat(tlsConfig.getCipherSuites().get()).containsExactly("test", "test2"); - - tlsConfig.setCipherSuites(null); - assertThat(tlsConfig.getCipherSuites()).isEmpty(); - } - - @Test - public void testEqualsContract() - { - EqualsVerifier.forClass(TLSConfig.class).usingGetClass() - .suppress(Warning.NONFINAL_FIELDS) - .verify(); - } -} diff --git a/application/src/test/resources/enabled_security.yml b/application/src/test/resources/security/enabled_keystore_jmxandcql.yml similarity index 100% rename from application/src/test/resources/enabled_security.yml rename to application/src/test/resources/security/enabled_keystore_jmxandcql.yml diff --git a/application/src/test/resources/security/enabled_nokeystore_nopem_cql.yml b/application/src/test/resources/security/enabled_nokeystore_nopem_cql.yml new file mode 100644 index 000000000..84f8ee5b1 --- /dev/null +++ b/application/src/test/resources/security/enabled_nokeystore_nopem_cql.yml @@ -0,0 +1,25 @@ +# +# Copyright 2023 Telefonaktiebolaget LM Ericsson +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +cql: + credentials: + enabled: true + username: cqluser + password: cqlpassword + tls: + enabled: true + protocol: TLSv1.2 + cipher_suites: VALID_CIPHER_SUITE,VALID_CIPHER_SUITE2 + require_endpoint_verification: true diff --git a/application/src/test/resources/security/enabled_nokeystore_nopem_jmx.yml b/application/src/test/resources/security/enabled_nokeystore_nopem_jmx.yml new file mode 100644 index 000000000..416e226fa --- /dev/null +++ b/application/src/test/resources/security/enabled_nokeystore_nopem_jmx.yml @@ -0,0 +1,24 @@ +# +# Copyright 2023 Telefonaktiebolaget LM Ericsson +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +jmx: + credentials: + enabled: true + username: jmxuser + password: jmxpassword + tls: + enabled: true + protocol: TLSv1.2 + cipher_suites: VALID_CIPHER_SUITE,VALID_CIPHER_SUITE2 diff --git a/application/src/test/resources/enabled_certificate_security.yml b/application/src/test/resources/security/enabled_pem_cql.yml similarity index 100% rename from application/src/test/resources/enabled_certificate_security.yml rename to application/src/test/resources/security/enabled_pem_cql.yml diff --git a/application/src/test/resources/security/enabled_pem_jmx.yml b/application/src/test/resources/security/enabled_pem_jmx.yml new file mode 100644 index 000000000..7dad5c09b --- /dev/null +++ b/application/src/test/resources/security/enabled_pem_jmx.yml @@ -0,0 +1,28 @@ +# +# Copyright 2023 Telefonaktiebolaget LM Ericsson +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +jmx: + credentials: + enabled: true + username: jmxuser + password: jmxpassword + tls: + enabled: true + certificate: /path/to/jmx/certificate + certificate_private_key: /path/to/jmx/certificate_key + trust_certificate: /path/to/jmx/certificate_authorities + protocol: TLSv1.2 + cipher_suites: VALID_CIPHER_SUITE,VALID_CIPHER_SUITE2 + require_endpoint_verification: true