From c86d2e9566134cba9dbd7e4cce4240d263af1d86 Mon Sep 17 00:00:00 2001 From: Valmira Correa Date: Tue, 3 May 2022 21:54:52 -0300 Subject: [PATCH 01/10] Add CQL configuration for certificates in PEM format --- .../ReloadingCertificateHandler.java | 50 ++++++++++++---- .../application/config/TLSConfig.java | 58 ++++++++++++++++++- application/src/main/resources/security.yml | 3 + .../application/config/TestSecurity.java | 28 +++++++++ .../enabled_certificate_security.yml | 28 +++++++++ 5 files changed, 153 insertions(+), 14 deletions(-) create mode 100644 application/src/test/resources/enabled_certificate_security.yml 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 0779634b8..c7dca0841 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 @@ -14,18 +14,25 @@ */ package com.ericsson.bss.cassandra.ecchronos.application; +import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.InetSocketAddress; import java.security.*; import java.security.cert.CertificateException; +import java.util.Arrays; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; import javax.net.ssl.*; import com.ericsson.bss.cassandra.ecchronos.connection.CertificateHandler; +import io.netty.buffer.ByteBufAllocator; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import io.netty.channel.socket.SocketChannel; +import io.netty.handler.ssl.SslHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,17 +66,17 @@ public SSLEngine newSSLEngine(EndPoint remoteEndpoint) { Context context = getContext(); TLSConfig tlsConfig = context.getTlsConfig(); - SSLContext sslContext = context.getSSLContext(); + SslContext sslContext = context.getSSLContext(); SSLEngine sslEngine; if (remoteEndpoint != null) { InetSocketAddress socketAddress = remoteEndpoint.resolve(); - sslEngine = sslContext.createSSLEngine(socketAddress.getHostName(), socketAddress.getPort()); + sslEngine = sslContext.newEngine(ByteBufAllocator.DEFAULT, socketAddress.getHostName(), socketAddress.getPort()); } else { - sslEngine = sslContext.createSSLEngine(); + sslEngine = sslContext.newEngine(ByteBufAllocator.DEFAULT); } sslEngine.setUseClientMode(true); @@ -128,7 +135,7 @@ protected Context getContext() protected static final class Context { private final TLSConfig tlsConfig; - private final SSLContext sslContext; + private final SslContext sslContext; Context(TLSConfig tlsConfig) throws NoSuchAlgorithmException, IOException, UnrecoverableKeyException, CertificateException, KeyStoreException, KeyManagementException @@ -147,22 +154,41 @@ boolean sameConfig(TLSConfig tlsConfig) return this.tlsConfig.equals(tlsConfig); } - SSLContext getSSLContext() + SslContext getSSLContext() { return sslContext; } } - protected static SSLContext createSSLContext(TLSConfig tlsConfig) throws IOException, NoSuchAlgorithmException, - KeyStoreException, CertificateException, UnrecoverableKeyException, KeyManagementException + protected static SslContext createSSLContext(TLSConfig tlsConfig) throws IOException, NoSuchAlgorithmException, + KeyStoreException, CertificateException, UnrecoverableKeyException { - SSLContext sslContext = SSLContext.getInstance(tlsConfig.getProtocol()); - KeyManagerFactory keyManagerFactory = getKeyManagerFactory(tlsConfig); - TrustManagerFactory trustManagerFactory = getTrustManagerFactory(tlsConfig); - sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null); + SslContextBuilder builder = SslContextBuilder.forClient(); - return sslContext; + if (tlsConfig.getCertificate().isPresent() && + tlsConfig.getCertificate_key().isPresent() && + tlsConfig.getCertificate_authorities().isPresent()) + { + File certificateFile = new File(tlsConfig.getCertificate().get()); + File certificateKeyFile = new File(tlsConfig.getCertificate_key().get()); + File certificateAuthorityFile = new File(tlsConfig.getCertificate_authorities().get()); + + builder.keyManager(certificateFile, certificateKeyFile); + builder.trustManager(certificateAuthorityFile); + } + else + { + KeyManagerFactory keyManagerFactory = getKeyManagerFactory(tlsConfig); + TrustManagerFactory trustManagerFactory = getTrustManagerFactory(tlsConfig); + builder.keyManager(keyManagerFactory); + builder.trustManager(trustManagerFactory); + } + if (tlsConfig.getCipherSuites().isPresent()) + { + builder.ciphers(Arrays.asList(tlsConfig.getCipherSuites().get())); + } + return builder.protocols(tlsConfig.getProtocols()).build(); } protected static KeyManagerFactory getKeyManagerFactory(TLSConfig tlsConfig) throws IOException, diff --git a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/TLSConfig.java b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/TLSConfig.java index 8b2944687..8c76d9577 100644 --- a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/TLSConfig.java +++ b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/TLSConfig.java @@ -28,6 +28,10 @@ public class TLSConfig private String truststore; private String truststore_password; + private String certificate; + private String certificate_key; + private String certificate_authorities; + private String protocol; private String algorithm; private String store_type; @@ -85,11 +89,58 @@ public void setTruststore_password(String truststore_password) this.truststore_password = truststore_password; } + public Optional getCertificate() + { + if (this.certificate == null) + { + return Optional.empty(); + } + return Optional.of(certificate); + } + + public void setCertificate(String certificate) + { + this.certificate = certificate; + } + + public Optional getCertificate_key() + { + if (this.certificate_key == null) + { + return Optional.empty(); + } + return Optional.of(certificate_key); + } + + public void setCertificate_key(String certificate_key) + { + this.certificate_key = certificate_key; + } + + public Optional getCertificate_authorities() + { + if (this.certificate_authorities == null) + { + return Optional.empty(); + } + return Optional.of(certificate_authorities); + } + + public void setCertificate_authorities(String certificate_authorities) + { + this.certificate_authorities = certificate_authorities; + } + public String getProtocol() { return protocol; } + public String[] getProtocols() + { + return protocol.split(","); + } + public void setProtocol(String protocol) { this.protocol = protocol; @@ -159,6 +210,9 @@ public boolean equals(Object o) Objects.equals(keystore_password, tlsConfig.keystore_password) && Objects.equals(truststore, tlsConfig.truststore) && Objects.equals(truststore_password, tlsConfig.truststore_password) && + Objects.equals(certificate, tlsConfig.certificate) && + Objects.equals(certificate_key, tlsConfig.certificate_key) && + Objects.equals(certificate_authorities, tlsConfig.certificate_authorities) && Objects.equals(protocol, tlsConfig.protocol) && Objects.equals(algorithm, tlsConfig.algorithm) && Objects.equals(store_type, tlsConfig.store_type) && @@ -168,8 +222,8 @@ public boolean equals(Object o) @Override public int hashCode() { - int result = Objects.hash(enabled, keystore, keystore_password, truststore, truststore_password, protocol, - algorithm, store_type, require_endpoint_verification); + int result = Objects.hash(enabled, keystore, keystore_password, truststore, truststore_password, certificate, + certificate_key, certificate_authorities, protocol, algorithm, store_type, require_endpoint_verification); result = 31 * result + Arrays.hashCode(cipher_suites); return result; } diff --git a/application/src/main/resources/security.yml b/application/src/main/resources/security.yml index a8c498252..b111e48d3 100644 --- a/application/src/main/resources/security.yml +++ b/application/src/main/resources/security.yml @@ -24,6 +24,9 @@ cql: keystore_password: ecchronos truststore: /path/to/truststore truststore_password: ecchronos + certificate: + certificate_key: + certificate_authorities: protocol: TLSv1.2 algorithm: store_type: JKS diff --git a/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/config/TestSecurity.java b/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/config/TestSecurity.java index 0e2677b5b..3f263e4b1 100644 --- a/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/config/TestSecurity.java +++ b/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/config/TestSecurity.java @@ -42,6 +42,9 @@ public void testDefault() throws Exception cqlTlsConfig.setKeystore_password("ecchronos"); cqlTlsConfig.setTruststore("/path/to/truststore"); cqlTlsConfig.setTruststore_password("ecchronos"); + cqlTlsConfig.setCertificate(null); + cqlTlsConfig.setCertificate_key(null); + cqlTlsConfig.setCertificate_authorities(null); cqlTlsConfig.setProtocol("TLSv1.2"); cqlTlsConfig.setAlgorithm(null); cqlTlsConfig.setStore_type("JKS"); @@ -102,4 +105,29 @@ public void testEnabled() throws Exception assertThat(config.getCql().getTls()).isEqualTo(cqlTlsConfig); assertThat(config.getJmx().getTls()).isEqualTo(jmxTlsConfig); } + + @Test + public void testEnabledWithCertificate() throws Exception + { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + File file = new File(classLoader.getResource("enabled_certificate_security.yml").getFile()); + + ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()); + + Security config = objectMapper.readValue(file, Security.class); + + Credentials expectedCqlCredentials = new Credentials(true, "cqluser", "cqlpassword"); + + TLSConfig cqlTlsConfig = new TLSConfig(); + cqlTlsConfig.setEnabled(true); + cqlTlsConfig.setCertificate("/path/to/cql/certificate"); + cqlTlsConfig.setCertificate_key("/path/to/cql/certificate_key"); + cqlTlsConfig.setCertificate_authorities("/path/to/cql/certificate_authorities"); + cqlTlsConfig.setProtocol("TLSv1.2"); + cqlTlsConfig.setCipher_suites("VALID_CIPHER_SUITE,VALID_CIPHER_SUITE2"); + cqlTlsConfig.setRequire_endpoint_verification(true); + + assertThat(config.getCql().getCredentials()).isEqualTo(expectedCqlCredentials); + assertThat(config.getCql().getTls()).isEqualTo(cqlTlsConfig); + } } diff --git a/application/src/test/resources/enabled_certificate_security.yml b/application/src/test/resources/enabled_certificate_security.yml new file mode 100644 index 000000000..7e2c79bf9 --- /dev/null +++ b/application/src/test/resources/enabled_certificate_security.yml @@ -0,0 +1,28 @@ +# +# Copyright 2022 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 + certificate: /path/to/cql/certificate + certificate_key: /path/to/cql/certificate_key + certificate_authorities: /path/to/cql/certificate_authorities + protocol: TLSv1.2 + cipher_suites: VALID_CIPHER_SUITE,VALID_CIPHER_SUITE2 + require_endpoint_verification: true From 612c4f8cff67fb382dfee0294279f82f659da2f5 Mon Sep 17 00:00:00 2001 From: Valmira Correa Date: Wed, 4 May 2022 08:11:50 -0300 Subject: [PATCH 02/10] Add Tomcat configuration for certificates in PEM format --- .../spring/TomcatWebServerCustomizer.java | 85 ++++++++++++++++++- .../src/main/resources/application.yml | 14 ++- 2 files changed, 95 insertions(+), 4 deletions(-) diff --git a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TomcatWebServerCustomizer.java b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TomcatWebServerCustomizer.java index 0358466ab..910aa2c18 100644 --- a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TomcatWebServerCustomizer.java +++ b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TomcatWebServerCustomizer.java @@ -16,6 +16,11 @@ import org.apache.coyote.http11.Http11NioProtocol; +import org.apache.tomcat.util.net.SSLHostConfig; +import org.apache.tomcat.util.net.SSLHostConfigCertificate; +import org.apache.tomcat.util.net.jsse.PEMFile; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; @@ -23,6 +28,11 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.cert.X509Certificate; + @Component @EnableScheduling public class TomcatWebServerCustomizer implements WebServerFactoryCustomizer @@ -32,26 +42,95 @@ public class TomcatWebServerCustomizer implements WebServerFactoryCustomizer { http11NioProtocol = (Http11NioProtocol) connector.getProtocolHandler(); + if (sslIsEnabledForCertificate) + { + http11NioProtocol.addSslHostConfig(getSslHostConfiguration()); + http11NioProtocol.setSSLEnabled(true); + } }); } } + private SSLHostConfig getSslHostConfiguration() + { + SSLHostConfig sslHostConfig = new SSLHostConfig(); + SSLHostConfigCertificate certificateConfig = new SSLHostConfigCertificate(sslHostConfig, SSLHostConfigCertificate.DEFAULT_TYPE); + certificateConfig.setCertificateFile(certificate); + certificateConfig.setCertificateKeyFile(certificateKey); + sslHostConfig.addCertificate(certificateConfig); + sslHostConfig.setCertificateVerification(clientAuth); + sslHostConfig.setTrustStore(getTrustStore()); + if (this.protocol != null) + { + sslHostConfig.setProtocols(protocol); + } + if (this.ciphers != null) + { + sslHostConfig.setCiphers(ciphers); + } + return sslHostConfig; + } + + private KeyStore getTrustStore() + { + KeyStore trustStore = null; + try + { + trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); + trustStore.load(null); + + PEMFile certificateBundle = new PEMFile(certificateAuthorities); + for (X509Certificate certificate : certificateBundle.getCertificates()) + { + trustStore.setCertificateEntry(certificate.getSerialNumber().toString(), certificate); + } + } + catch(GeneralSecurityException | IOException exception) + { + LOG.warn("Unable to load certificate authorities", exception); + } + return trustStore; + } + /** - * Reload the {@code SSLHostConfig} if SSL is enabled. Doing so should update ssl settings and fetch certificates from Keystores + * Reload the {@code SSLHostConfig} if SSL is enabled. Doing so should update ssl settings and reload certificates * It reloads them every 60 seconds by default */ @Scheduled (initialDelayString = "${server.ssl.refresh-rate-in-ms:60000}", fixedRateString = "${server.ssl.refresh-rate-in-ms:60000}") public void reloadSslContext() { - if (sslIsEnabled && http11NioProtocol != null) + if ((sslIsEnabled || sslIsEnabledForCertificate) && http11NioProtocol != null) { http11NioProtocol.reloadSslHostConfigs(); } diff --git a/application/src/main/resources/application.yml b/application/src/main/resources/application.yml index ae7fa661b..517a1a833 100644 --- a/application/src/main/resources/application.yml +++ b/application/src/main/resources/application.yml @@ -28,11 +28,23 @@ management: # Security Config #server: # ssl: +# SSL configuration using certificate stores # enabled: false # key-store: # key-store-password: # key-store-type: # key-alias: # key-password: -# Rate at which certificate are reloaded automatically +# client-auth: false +# protocol: +# ciphers: +# SSL configuration using certificates in PEM format +# enabled-certificate: false +# certificate: +# certificate-key: +# certificate-authorities: +# certificate-client-auth: false +# certificate-protocol: +# certificate-ciphers: +# Rate at which certificates are reloaded automatically # refresh-rate-in-ms: 60000 \ No newline at end of file From 1544afd605041d1124096638d962659b599896b6 Mon Sep 17 00:00:00 2001 From: Valmira Correa Date: Mon, 13 Jun 2022 05:56:25 -0300 Subject: [PATCH 03/10] Fix review comments --- .../ReloadingCertificateHandler.java | 14 ++++---- .../application/config/TLSConfig.java | 4 +-- .../spring/TomcatWebServerCustomizer.java | 33 ++++++----------- .../src/main/resources/application.yml | 10 ++---- .../spring/TestTomcatWebServerCustomizer.java | 15 +------- ...TestTomcatWebServerCustomizerKeystore.java | 35 +++++++++++++++++++ .../TestTomcatWebServerCustomizerPem.java | 30 ++++++++++++++++ application/src/test/resources/server/ca.crt | 21 +++++++++++ .../src/test/resources/server/cert.crt | 19 ++++++++++ application/src/test/resources/server/key.pem | 28 +++++++++++++++ 10 files changed, 154 insertions(+), 55 deletions(-) create mode 100644 application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TestTomcatWebServerCustomizerKeystore.java create mode 100644 application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TestTomcatWebServerCustomizerPem.java create mode 100644 application/src/test/resources/server/ca.crt create mode 100644 application/src/test/resources/server/cert.crt create mode 100644 application/src/test/resources/server/key.pem 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 c7dca0841..011de7273 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 @@ -39,9 +39,6 @@ import com.datastax.driver.core.EndPoint; import com.ericsson.bss.cassandra.ecchronos.application.config.TLSConfig; -import io.netty.channel.socket.SocketChannel; -import io.netty.handler.ssl.SslHandler; - public class ReloadingCertificateHandler implements CertificateHandler { private static final Logger LOG = LoggerFactory.getLogger(ReloadingCertificateHandler.class); @@ -72,7 +69,8 @@ public SSLEngine newSSLEngine(EndPoint remoteEndpoint) if (remoteEndpoint != null) { InetSocketAddress socketAddress = remoteEndpoint.resolve(); - sslEngine = sslContext.newEngine(ByteBufAllocator.DEFAULT, socketAddress.getHostName(), socketAddress.getPort()); + sslEngine = sslContext.newEngine(ByteBufAllocator.DEFAULT, socketAddress.getHostName(), + socketAddress.getPort()); } else { @@ -167,12 +165,12 @@ protected static SslContext createSSLContext(TLSConfig tlsConfig) throws IOExcep SslContextBuilder builder = SslContextBuilder.forClient(); if (tlsConfig.getCertificate().isPresent() && - tlsConfig.getCertificate_key().isPresent() && - tlsConfig.getCertificate_authorities().isPresent()) + tlsConfig.getCertificateKey().isPresent() && + tlsConfig.getCertificateAuthorities().isPresent()) { File certificateFile = new File(tlsConfig.getCertificate().get()); - File certificateKeyFile = new File(tlsConfig.getCertificate_key().get()); - File certificateAuthorityFile = new File(tlsConfig.getCertificate_authorities().get()); + File certificateKeyFile = new File(tlsConfig.getCertificateKey().get()); + File certificateAuthorityFile = new File(tlsConfig.getCertificateAuthorities().get()); builder.keyManager(certificateFile, certificateKeyFile); builder.trustManager(certificateAuthorityFile); diff --git a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/TLSConfig.java b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/TLSConfig.java index 8c76d9577..c9eb90706 100644 --- a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/TLSConfig.java +++ b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/TLSConfig.java @@ -103,7 +103,7 @@ public void setCertificate(String certificate) this.certificate = certificate; } - public Optional getCertificate_key() + public Optional getCertificateKey() { if (this.certificate_key == null) { @@ -117,7 +117,7 @@ public void setCertificate_key(String certificate_key) this.certificate_key = certificate_key; } - public Optional getCertificate_authorities() + public Optional getCertificateAuthorities() { if (this.certificate_authorities == null) { diff --git a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TomcatWebServerCustomizer.java b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TomcatWebServerCustomizer.java index 910aa2c18..37777e849 100644 --- a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TomcatWebServerCustomizer.java +++ b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TomcatWebServerCustomizer.java @@ -42,9 +42,6 @@ public class TomcatWebServerCustomizer implements WebServerFactoryCustomizer { http11NioProtocol = (Http11NioProtocol) connector.getProtocolHandler(); - if (sslIsEnabledForCertificate) - { + if (certificate != null) { http11NioProtocol.addSslHostConfig(getSslHostConfiguration()); http11NioProtocol.setSSLEnabled(true); } @@ -89,16 +84,8 @@ private SSLHostConfig getSslHostConfiguration() certificateConfig.setCertificateFile(certificate); certificateConfig.setCertificateKeyFile(certificateKey); sslHostConfig.addCertificate(certificateConfig); - sslHostConfig.setCertificateVerification(clientAuth); sslHostConfig.setTrustStore(getTrustStore()); - if (this.protocol != null) - { - sslHostConfig.setProtocols(protocol); - } - if (this.ciphers != null) - { - sslHostConfig.setCiphers(ciphers); - } + sslHostConfig.setCertificateVerification(clientAuth.equals("need") ? "true" : "false"); return sslHostConfig; } @@ -130,7 +117,7 @@ private KeyStore getTrustStore() @Scheduled (initialDelayString = "${server.ssl.refresh-rate-in-ms:60000}", fixedRateString = "${server.ssl.refresh-rate-in-ms:60000}") public void reloadSslContext() { - if ((sslIsEnabled || sslIsEnabledForCertificate) && http11NioProtocol != null) + if (sslIsEnabled && http11NioProtocol != null) { http11NioProtocol.reloadSslHostConfigs(); } diff --git a/application/src/main/resources/application.yml b/application/src/main/resources/application.yml index 517a1a833..9da8adcea 100644 --- a/application/src/main/resources/application.yml +++ b/application/src/main/resources/application.yml @@ -28,23 +28,17 @@ management: # Security Config #server: # ssl: -# SSL configuration using certificate stores # enabled: false +# client-auth: +# SSL configuration using certificate stores # key-store: # key-store-password: # key-store-type: # key-alias: # key-password: -# client-auth: false -# protocol: -# ciphers: # SSL configuration using certificates in PEM format -# enabled-certificate: false # certificate: # certificate-key: # certificate-authorities: -# certificate-client-auth: false -# certificate-protocol: -# certificate-ciphers: # Rate at which certificates are reloaded automatically # refresh-rate-in-ms: 60000 \ No newline at end of file diff --git a/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TestTomcatWebServerCustomizer.java b/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TestTomcatWebServerCustomizer.java index 970920afd..8c6f73588 100644 --- a/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TestTomcatWebServerCustomizer.java +++ b/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TestTomcatWebServerCustomizer.java @@ -58,13 +58,8 @@ import static org.assertj.core.api.Assertions.assertThat; -@RunWith (SpringRunner.class) -@SpringBootTest (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@ContextConfiguration(initializers = TestTomcatWebServerCustomizer.PropertyOverrideContextInitializer.class) -public class TestTomcatWebServerCustomizer +public abstract class TestTomcatWebServerCustomizer { - private static final String SERVER_KEYSTORE = "src/test/resources/server/ks.p12"; - private static final String SERVER_TRUSTSTORE = "src/test/resources/server/ts.p12"; private static final String CLIENT_VALID_PATH = "valid/"; private static final String CLIENT_EXPIRED_PATH = "expired/"; private static final int REFRESH_RATE = 100; @@ -153,14 +148,6 @@ public void initialize(ConfigurableApplicationContext configurableApplicationCon { addInlinedPropertiesToEnvironment(configurableApplicationContext, "server.ssl.enabled=true", - "server.ssl.key-store=" + SERVER_KEYSTORE, - "server.ssl.key-store-password=", - "server.ssl.key-store-type=PKCS12", - "server.ssl.key-alias=cert", - "server.ssl.key-password=", - "server.ssl.trust-store=" + SERVER_TRUSTSTORE, - "server.ssl.trust-store-password=", - "server.ssl.trust-store-type=PKCS12", "server.ssl.client-auth=need", "server.ssl.refresh-rate-in-ms=" + REFRESH_RATE); } diff --git a/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TestTomcatWebServerCustomizerKeystore.java b/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TestTomcatWebServerCustomizerKeystore.java new file mode 100644 index 000000000..770682d29 --- /dev/null +++ b/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TestTomcatWebServerCustomizerKeystore.java @@ -0,0 +1,35 @@ +/* + * Copyright 2022 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.spring; + +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith (SpringRunner.class) +@SpringBootTest (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + properties = { + "server.ssl.key-store=src/test/resources/server/ks.p12", + "server.ssl.key-store-password=", + "server.ssl.key-store-type=PKCS12", + "server.ssl.key-alias=cert", + "server.ssl.key-password=", + "server.ssl.trust-store=src/test/resources/server/ts.p12", + "server.ssl.trust-store-password=", + "server.ssl.trust-store-type=PKCS12" + }) +@ContextConfiguration(initializers = TestTomcatWebServerCustomizer.PropertyOverrideContextInitializer.class) +public class TestTomcatWebServerCustomizerKeystore extends TestTomcatWebServerCustomizer {} \ No newline at end of file diff --git a/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TestTomcatWebServerCustomizerPem.java b/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TestTomcatWebServerCustomizerPem.java new file mode 100644 index 000000000..a6a78f8d9 --- /dev/null +++ b/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TestTomcatWebServerCustomizerPem.java @@ -0,0 +1,30 @@ +/* + * Copyright 2022 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.spring; + +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith (SpringRunner.class) +@SpringBootTest (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + properties = { + "server.ssl.certificate=./server/cert.crt", + "server.ssl.certificate-key=./server/key.pem", + "server.ssl.certificate-authorities=./server/ca.crt" + }) +@ContextConfiguration(initializers = TestTomcatWebServerCustomizer.PropertyOverrideContextInitializer.class) +public class TestTomcatWebServerCustomizerPem extends TestTomcatWebServerCustomizer {} \ No newline at end of file diff --git a/application/src/test/resources/server/ca.crt b/application/src/test/resources/server/ca.crt new file mode 100644 index 000000000..df30d7a85 --- /dev/null +++ b/application/src/test/resources/server/ca.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDfzCCAmegAwIBAgIJAIxCCpTWw5+LMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV +BAYTAlRFMQ0wCwYDVQQIDARURVNUMQ0wCwYDVQQHDARURVNUMQ0wCwYDVQQKDARU +RVNUMQ0wCwYDVQQLDARURVNUMQswCQYDVQQDDAJDQTAeFw0yMTAxMjExMTU2MzZa +Fw0yMTAxMjIxMTU2MzZaMFYxCzAJBgNVBAYTAlRFMQ0wCwYDVQQIDARURVNUMQ0w +CwYDVQQHDARURVNUMQ0wCwYDVQQKDARURVNUMQ0wCwYDVQQLDARURVNUMQswCQYD +VQQDDAJDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJu8/uSP1cp +8nn+W3lazvQSyKEyU2TbuKqiawqFTyjLKEL1DinM5imV8LD42SGuRYoC3k0jTgTc +7HwxqmrP87t4CiYhacF990i79QyBYwo+EPgZ+IC04puBCbP3S45NS6L0sm3E3Vsu +nsvduF+7a+HlmYciV1HYJT7h2j8ZzQCqJ4qMvkkf5E3N2EhkPVenR5A4Y4OwPNS/ +AtZo7bzCgRws4WVKrv5Eo1BhPR82kfrMUCPMxGZwylAU/PTGkkxf84OcQRGW8JT9 +AcebkxTLJbnurQMIwG0yY+b7yli6kbDBxWjTA0X5nFd22WvVYoJEOtJrHsZ4O6zi +FH+oOzyD5IECAwEAAaNQME4wHQYDVR0OBBYEFJTbFa7wd276pUfIWA298r54kZh/ +MB8GA1UdIwQYMBaAFJTbFa7wd276pUfIWA298r54kZh/MAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQELBQADggEBAHLZMqP01PeD8FdxR3MvH6PlgJmlatYR58aWkRK2 ++wmDY1ZolI3YPVZemRYp4EGU8nj3tk9wALn5Q1CDyU7aZXerSPngekfaNGhFY1tB +cj+6bEY12FxBW2G0kc80rjbMbfLZEpHEdHKwJLosWuNOBWYOdZof4pS9uQUeGJKq +9MYJl/HFf1j7ZOzNoy9220eSz2rEe90aCD5QJZklkUeCK3uxjIxU9SegUn5XD5jj +aKli1AIgnCYbR76TU8xXRtq5CCohhbM21f/SUZQehluupQ9z3UL9MjMXMN+61ejT +skIUYVNCWMEOV23Cc4+JhV6LC6ivJpv9E/Zxh7H/Gyz2Df0= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/application/src/test/resources/server/cert.crt b/application/src/test/resources/server/cert.crt new file mode 100644 index 000000000..2b5a877e7 --- /dev/null +++ b/application/src/test/resources/server/cert.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDLDCCAhQCCQDwyqHW1MWFjjANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJU +RTENMAsGA1UECAwEVEVTVDENMAsGA1UEBwwEVEVTVDENMAsGA1UECgwEVEVTVDEN +MAsGA1UECwwEVEVTVDELMAkGA1UEAwwCQ0EwIBcNMjEwMTIxMTIwNTIwWhgPMjE4 +NTA1MDExMjA1MjBaMFgxCzAJBgNVBAYTAlRFMQ0wCwYDVQQIDARURVNUMQ0wCwYD +VQQHDARURVNUMQ0wCwYDVQQKDARURVNUMQ0wCwYDVQQLDARURVNUMQ0wCwYDVQQD +DARVc2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA57QgmBI5o6VP +pNoio0oCbLbSnXfbfZS/wVZ5ET1QOhr+ZpbZqwpZTt5QbSguFQNMJn0wkISa1Ymf +QBL+SaZHsxGy4SwX0Fs4N0ou1/38iBubSNfl9FZ/3nwYMZ9do5651s8MHbqGcFdY +oHOtdvVuMKDCpUg2bJZHM4UPya35SZBsjCqatA0xrnDBdjXnPVDoj3O/Y+H6D9pT +pcBG2MabMyC+GgAvt5sZIJxbYZNchXHFiML6sPUXoxpC5SbKmj1/Da5veNBbQsXw +C29ofWeM1t0hEtSkaQCSVl1TRCesA9u5AUBfnKnhlzABizRz6Wb/c3jH59GtS2M3 +mBMmOJLfZwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCJ/8Lkh8cR4X0Upmzx+Szv +YdKvmRM/QC6mtsuvI2qPlwHp3BIIafhiE1ziIIV1K+hqKhq2jN8NTSz8rHVDGMQg +Bhna4Cc/sIWNfinRZGlo9ITAiJSsgEXmiSYYQwsNOvDbApZVLOgw44SQ7KhEO9bh +6JUC2ilXA3BLmdyqLQG/ijOdKWBGefO8eL7kZuWQ7kNWywqco72ZjR1woD86JSf4 +2EAO0p4BJ4b8OQ6NlCZZZcQu7tPpwoV4KQ9fgIHS43nwK26T+kKr9PzAVJ8c1S4g +My4HAU6CWj4m479l+ej6y1pt+VN5ahIKLEpyjBB7JSL23940ZPc1D7pKG4MbdpHj +-----END CERTIFICATE----- diff --git a/application/src/test/resources/server/key.pem b/application/src/test/resources/server/key.pem new file mode 100644 index 000000000..1b94b251d --- /dev/null +++ b/application/src/test/resources/server/key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDntCCYEjmjpU+k +2iKjSgJsttKdd9t9lL/BVnkRPVA6Gv5mltmrCllO3lBtKC4VA0wmfTCQhJrViZ9A +Ev5JpkezEbLhLBfQWzg3Si7X/fyIG5tI1+X0Vn/efBgxn12jnrnWzwwduoZwV1ig +c6129W4woMKlSDZslkczhQ/JrflJkGyMKpq0DTGucMF2Nec9UOiPc79j4foP2lOl +wEbYxpszIL4aAC+3mxkgnFthk1yFccWIwvqw9RejGkLlJsqaPX8Nrm940FtCxfAL +b2h9Z4zW3SES1KRpAJJWXVNEJ6wD27kBQF+cqeGXMAGLNHPpZv9zeMfn0a1LYzeY +EyY4kt9nAgMBAAECggEAHHFbMu/BzZnkbfstF1hldcz3i8cD1aWl6GjiEcCyEX/w +zM0lyT5K+kiGHPA6v++YsHzbslHk4+Ox/d6XApl74bqBd+y+u6AHBZqAp5kRH/Ar +nsSKAPWBWuFm4uiKSSSZ8YmXFisoh6/hPEkW+Sxlq2iAnGOB8tB7yxJBfuNxX5s0 +NU603Tnin1ZUBpgai+IM6Bu4mVWD9VIaN0OvI3qFUg6hlO+liXMglpPMg1n7qFWP +qbKT6HbyeJ28g/TEeu79xFs5NmJGn4fjDT1rQBp1S2HFYlnUYX3aQh7ih5OSoyU4 +xIFVeXYO71/F20GU6h/0kUcu1WqQmIXJh/bXcntGYQKBgQD7KDxEpTvp7uiBq16V +dRQMHLS5vFA+KfO+xsmfiqQgaTWn+sbKBDLIW2oYnPiiQCPeepxPECazH3AmqhBK +7OXlMFkQPhT0pjEfFGxlBuxIbINmnzsTqexcL8t0D8o2f2u4814R5YZpq284mHrD +EJnct8cn+1cSLaaBncv69Vr40QKBgQDsK913L4mXpMW3QDmDvdhYYtDRwLRIRAZ7 +Hbe7B3Byj38Y75zazI6IBV3yu74MdEwGdFIWOigArIQcn1jMwdHmEJjxE9zwoCEI +bMQu6efT7uor25WIXgR31H+2lhWJahgdBSFHKrILtznTIUP6vp3kKmg1yBhHVCON +/I6oX1titwKBgHCjiuP+dvBjhUMiaDj/WQ5VkXf7TMGUbwyQerxioVkn1jiP77eK +SnwxA1QmkhuySGPu+Us8Ix8Samnsu4He3Pv8wvTV4vAV2NHnhvWINVAF2qiboRMg +kjCF/uj+a+IlI1q/SuEb3zxk9mybdfMl7tteUKNNxa8RaiuXaXQTtckBAoGANfi8 +Tt2FQyt7p6o8uperFl/WuuigCpfJJ1+eOlaz4upaMFep7/Kpa/pWAv/Wqb/2E8+H +Zt75f1XthyD/SSPOFRab7RQN/MuLYQKCPvpjaXKC/2zaGmTp/nyIhzB7UYD2a8Nd +XIcsUzMXOuGySF5BdQAf+pJ0wfA/g9ZAv8ey+bcCgYApjzqcWCw9c/DOAdLQPbGX +F+gpz3WoyqWMUQ6/3hpivG8gKGdEMv5ecpfrV9uHEZDPXsbdGAAJC9+nxUh0AQZj +8sYojRi8I6/DfDNj3aLaepTW2jbHEhiHNzaHxoGKV6i1BuuMRcligYRDxwslOxAv +vqeORuYWSWlLMBJc8DWA7g== +-----END PRIVATE KEY----- \ No newline at end of file From e0a6498f24a93ed77329e3c6e18faced0b42c9d5 Mon Sep 17 00:00:00 2001 From: Valmira Correa Date: Tue, 28 Jun 2022 07:50:52 -0300 Subject: [PATCH 04/10] Fix more comments --- .../spring/TomcatWebServerCustomizer.java | 2 +- docs/SETUP.md | 26 +++++++++++++++++-- pom.xml | 2 ++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TomcatWebServerCustomizer.java b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TomcatWebServerCustomizer.java index 37777e849..1ca59e819 100644 --- a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TomcatWebServerCustomizer.java +++ b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TomcatWebServerCustomizer.java @@ -85,7 +85,7 @@ private SSLHostConfig getSslHostConfiguration() certificateConfig.setCertificateKeyFile(certificateKey); sslHostConfig.addCertificate(certificateConfig); sslHostConfig.setTrustStore(getTrustStore()); - sslHostConfig.setCertificateVerification(clientAuth.equals("need") ? "true" : "false"); + sslHostConfig.setCertificateVerification("need".equals(clientAuth) ? "true" : "false"); return sslHostConfig; } diff --git a/docs/SETUP.md b/docs/SETUP.md index 100ef8ee2..55a409760 100644 --- a/docs/SETUP.md +++ b/docs/SETUP.md @@ -115,7 +115,7 @@ cql: keystore_password: ecchronos truststore: /path/to/truststore truststore_password: ecchronos - protocol: TLSv1.2 + protocol: TLSv1.2,TLSv1.3 algorithm: store_type: JKS cipher_suites: @@ -131,10 +131,32 @@ jmx: keystore_password: ecchronos truststore: /path/to/truststore truststore_password: ecchronos - protocol: TLSv1.2 + protocol: TLSv1.2,TLSv1.3 cipher_suites: ``` +CQL also supports certificates in PEM format. + +``` +cql: + credentials: + enabled: true + username: cassandra + password: cassandra + tls: + enabled: false + certificate: /path/to/certificate + certificate_key: /path/to/certificate_key + certificate_authorities: /path/to/certificate_authorities + protocol: TLSv1.2,TLSv1.3 + cipher_suites: + require_endpoint_verification: false +``` +> **Note** +> +> In case certificate stores and PEM certificates are declared in `conf/security.yml` for CQL, +> PEM certificates takes precedence. + The security parameters can be updated during runtime and will automatically be picked up by ecc. It's possible to override the default connection providers if needed. diff --git a/pom.xml b/pom.xml index a7099f744..0515225d4 100644 --- a/pom.xml +++ b/pom.xml @@ -543,6 +543,8 @@ limitations under the License. **/*.cql **/*.txt **/*.p12 + **/*.crt + **/*.pem **/pom.xml.tag **/pom.xml.releaseBackup **/*.options From a1f375b75fbce64fd3c9fba3b679ea8c6f254c8d Mon Sep 17 00:00:00 2001 From: Valmira Correa Date: Fri, 1 Jul 2022 09:06:19 -0300 Subject: [PATCH 05/10] Fix comments --- .../application/config/TLSConfig.java | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/TLSConfig.java b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/TLSConfig.java index c9eb90706..7a43d3351 100644 --- a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/TLSConfig.java +++ b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/TLSConfig.java @@ -91,11 +91,7 @@ public void setTruststore_password(String truststore_password) public Optional getCertificate() { - if (this.certificate == null) - { - return Optional.empty(); - } - return Optional.of(certificate); + return Optional.ofNullable(certificate); } public void setCertificate(String certificate) @@ -105,11 +101,7 @@ public void setCertificate(String certificate) public Optional getCertificateKey() { - if (this.certificate_key == null) - { - return Optional.empty(); - } - return Optional.of(certificate_key); + return Optional.ofNullable(certificate_key); } public void setCertificate_key(String certificate_key) @@ -119,16 +111,12 @@ public void setCertificate_key(String certificate_key) public Optional getCertificateAuthorities() { - if (this.certificate_authorities == null) - { - return Optional.empty(); - } - return Optional.of(certificate_authorities); + return Optional.ofNullable(certificate_authorities); } public void setCertificate_authorities(String certificate_authorities) - { - this.certificate_authorities = certificate_authorities; + { + this.certificate_authorities = certificate_authorities; } public String getProtocol() From 125ff19ca054750790bcfa385ac649c0628dc636 Mon Sep 17 00:00:00 2001 From: Valmira Correa Date: Wed, 31 Aug 2022 13:41:27 -0300 Subject: [PATCH 06/10] Use default web server SSL configuration --- .../spring/TomcatWebServerCustomizer.java | 75 +------------------ .../src/main/resources/application.yml | 7 +- .../TestTomcatWebServerCustomizerPem.java | 7 +- pom.xml | 2 +- 4 files changed, 11 insertions(+), 80 deletions(-) diff --git a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TomcatWebServerCustomizer.java b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TomcatWebServerCustomizer.java index 6a3b3d943..0358466ab 100644 --- a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TomcatWebServerCustomizer.java +++ b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TomcatWebServerCustomizer.java @@ -16,11 +16,6 @@ import org.apache.coyote.http11.Http11NioProtocol; -import org.apache.tomcat.util.net.SSLHostConfig; -import org.apache.tomcat.util.net.SSLHostConfigCertificate; -import org.apache.tomcat.util.net.jsse.PEMFile; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; @@ -28,11 +23,6 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.security.KeyStore; -import java.security.cert.X509Certificate; - @Component @EnableScheduling public class TomcatWebServerCustomizer implements WebServerFactoryCustomizer @@ -42,79 +32,20 @@ public class TomcatWebServerCustomizer implements WebServerFactoryCustomizer { http11NioProtocol = (Http11NioProtocol) connector.getProtocolHandler(); - if (certificate != null) { - sslHostConfig = getSslHostConfiguration(); - http11NioProtocol.addSslHostConfig(sslHostConfig); - http11NioProtocol.setSSLEnabled(true); - } }); } } - private SSLHostConfig getSslHostConfiguration() - { - SSLHostConfig sslHostConfig = new SSLHostConfig(); - SSLHostConfigCertificate certificateConfig = new SSLHostConfigCertificate(sslHostConfig, SSLHostConfigCertificate.DEFAULT_TYPE); - certificateConfig.setCertificateFile(certificate); - certificateConfig.setCertificateKeyFile(certificateKey); - sslHostConfig.addCertificate(certificateConfig); - sslHostConfig.setTrustStore(getTrustStore()); - sslHostConfig.setCertificateVerification("need".equals(clientAuth) ? "true" : "false"); - return sslHostConfig; - } - - private KeyStore getTrustStore() - { - KeyStore trustStore = null; - try - { - trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); - trustStore.load(null); - - PEMFile certificateBundle = new PEMFile(certificateAuthorities); - for (X509Certificate certificate : certificateBundle.getCertificates()) - { - trustStore.setCertificateEntry(certificate.getSerialNumber().toString(), certificate); - } - } - catch(GeneralSecurityException | IOException exception) - { - LOG.warn("Unable to load certificate authorities", exception); - } - return trustStore; - } - /** - * Reload the {@code SSLHostConfig} if SSL is enabled. Doing so should update ssl settings and reload certificates + * Reload the {@code SSLHostConfig} if SSL is enabled. Doing so should update ssl settings and fetch certificates from Keystores * It reloads them every 60 seconds by default */ @Scheduled (initialDelayString = "${server.ssl.refresh-rate-in-ms:60000}", fixedRateString = "${server.ssl.refresh-rate-in-ms:60000}") @@ -122,10 +53,6 @@ public void reloadSslContext() { if (sslIsEnabled && http11NioProtocol != null) { - if (sslHostConfig != null) - { - sslHostConfig.setTrustStore(getTrustStore()); - } http11NioProtocol.reloadSslHostConfigs(); } } diff --git a/application/src/main/resources/application.yml b/application/src/main/resources/application.yml index 954e0e8b2..26e865e62 100644 --- a/application/src/main/resources/application.yml +++ b/application/src/main/resources/application.yml @@ -51,7 +51,10 @@ springdoc: # key-password: # SSL configuration using certificates in PEM format # certificate: -# certificate-key: -# certificate-authorities: +# certificate-private-key: +# key-store-password: +# Optional configuration for certificates in PEM format +# trust-certificate: +# trust-certificate-private-key: # Rate at which certificates are reloaded automatically # refresh-rate-in-ms: 60000 \ No newline at end of file diff --git a/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TestTomcatWebServerCustomizerPem.java b/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TestTomcatWebServerCustomizerPem.java index a6a78f8d9..2abbd51a6 100644 --- a/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TestTomcatWebServerCustomizerPem.java +++ b/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TestTomcatWebServerCustomizerPem.java @@ -22,9 +22,10 @@ @RunWith (SpringRunner.class) @SpringBootTest (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { - "server.ssl.certificate=./server/cert.crt", - "server.ssl.certificate-key=./server/key.pem", - "server.ssl.certificate-authorities=./server/ca.crt" + "server.ssl.certificate=src/test/resources/server/cert.crt", + "server.ssl.certificate-private-key=src/test/resources/server/key.pem", + "server.ssl.trust-certificate=src/test/resources/server/ca.crt", + "server.ssl.key-store-password=test" }) @ContextConfiguration(initializers = TestTomcatWebServerCustomizer.PropertyOverrideContextInitializer.class) public class TestTomcatWebServerCustomizerPem extends TestTomcatWebServerCustomizer {} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 00f90d854..1344f4d92 100644 --- a/pom.xml +++ b/pom.xml @@ -88,7 +88,7 @@ 1.0 1.1.1 3.5 - 2.6.6 + 2.7.0 1.6.8 0.10.0 2.0.2 From 166aefbe48443463408c7297352aaf59828fa97b Mon Sep 17 00:00:00 2001 From: Valmira Correa Date: Thu, 1 Sep 2022 10:18:11 -0300 Subject: [PATCH 07/10] Change Springboot version to 2.7.2 and update security properties --- .../ReloadingCertificateHandler.java | 12 ++++----- .../application/config/TLSConfig.java | 26 +++++++++---------- .../src/main/resources/application.yml | 2 -- application/src/main/resources/security.yml | 4 +-- .../application/config/TestSecurity.java | 8 +++--- .../TestTomcatWebServerCustomizerPem.java | 3 +-- .../enabled_certificate_security.yml | 4 +-- ecchronos-binary/pom.xml | 1 + pom.xml | 2 +- 9 files changed, 30 insertions(+), 32 deletions(-) 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 7c127fd1e..f83e0dd4e 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 @@ -155,15 +155,15 @@ protected static SslContext createSSLContext(TLSConfig tlsConfig) throws IOExcep SslContextBuilder builder = SslContextBuilder.forClient(); if (tlsConfig.getCertificate().isPresent() && - tlsConfig.getCertificateKey().isPresent() && - tlsConfig.getCertificateAuthorities().isPresent()) + tlsConfig.getCertificatePrivateKey().isPresent() && + tlsConfig.getTrustCertificate().isPresent()) { File certificateFile = new File(tlsConfig.getCertificate().get()); - File certificateKeyFile = new File(tlsConfig.getCertificateKey().get()); - File certificateAuthorityFile = new File(tlsConfig.getCertificateAuthorities().get()); + File certificatePrivateKeyFile = new File(tlsConfig.getCertificatePrivateKey().get()); + File trustCertificateFile = new File(tlsConfig.getTrustCertificate().get()); - builder.keyManager(certificateFile, certificateKeyFile); - builder.trustManager(certificateAuthorityFile); + builder.keyManager(certificateFile, certificatePrivateKeyFile); + builder.trustManager(trustCertificateFile); } else { diff --git a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/TLSConfig.java b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/TLSConfig.java index 7a43d3351..b8fbf98a4 100644 --- a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/TLSConfig.java +++ b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/TLSConfig.java @@ -29,8 +29,8 @@ public class TLSConfig private String truststore_password; private String certificate; - private String certificate_key; - private String certificate_authorities; + private String certificate_private_key; + private String trust_certificate; private String protocol; private String algorithm; @@ -99,24 +99,24 @@ public void setCertificate(String certificate) this.certificate = certificate; } - public Optional getCertificateKey() + public Optional getCertificatePrivateKey() { - return Optional.ofNullable(certificate_key); + return Optional.ofNullable(certificate_private_key); } - public void setCertificate_key(String certificate_key) + public void setCertificate_private_key(String certificate_private_key) { - this.certificate_key = certificate_key; + this.certificate_private_key = certificate_private_key; } - public Optional getCertificateAuthorities() + public Optional getTrustCertificate() { - return Optional.ofNullable(certificate_authorities); + return Optional.ofNullable(trust_certificate); } - public void setCertificate_authorities(String certificate_authorities) + public void setTrust_certificate(String trust_certificate) { - this.certificate_authorities = certificate_authorities; + this.trust_certificate = trust_certificate; } public String getProtocol() @@ -199,8 +199,8 @@ public boolean equals(Object o) Objects.equals(truststore, tlsConfig.truststore) && Objects.equals(truststore_password, tlsConfig.truststore_password) && Objects.equals(certificate, tlsConfig.certificate) && - Objects.equals(certificate_key, tlsConfig.certificate_key) && - Objects.equals(certificate_authorities, tlsConfig.certificate_authorities) && + Objects.equals(certificate_private_key, tlsConfig.certificate_private_key) && + Objects.equals(trust_certificate, tlsConfig.trust_certificate) && Objects.equals(protocol, tlsConfig.protocol) && Objects.equals(algorithm, tlsConfig.algorithm) && Objects.equals(store_type, tlsConfig.store_type) && @@ -211,7 +211,7 @@ public boolean equals(Object o) public int hashCode() { int result = Objects.hash(enabled, keystore, keystore_password, truststore, truststore_password, certificate, - certificate_key, certificate_authorities, protocol, algorithm, store_type, require_endpoint_verification); + certificate_private_key, trust_certificate, protocol, algorithm, store_type, require_endpoint_verification); result = 31 * result + Arrays.hashCode(cipher_suites); return result; } diff --git a/application/src/main/resources/application.yml b/application/src/main/resources/application.yml index 26e865e62..6894395fe 100644 --- a/application/src/main/resources/application.yml +++ b/application/src/main/resources/application.yml @@ -52,9 +52,7 @@ springdoc: # SSL configuration using certificates in PEM format # certificate: # certificate-private-key: -# key-store-password: # Optional configuration for certificates in PEM format # trust-certificate: -# trust-certificate-private-key: # Rate at which certificates are reloaded automatically # refresh-rate-in-ms: 60000 \ No newline at end of file diff --git a/application/src/main/resources/security.yml b/application/src/main/resources/security.yml index b111e48d3..4d34c66e7 100644 --- a/application/src/main/resources/security.yml +++ b/application/src/main/resources/security.yml @@ -25,8 +25,8 @@ cql: truststore: /path/to/truststore truststore_password: ecchronos certificate: - certificate_key: - certificate_authorities: + certificate_private_key: + trust_certificate: protocol: TLSv1.2 algorithm: store_type: JKS diff --git a/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/config/TestSecurity.java b/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/config/TestSecurity.java index 3f263e4b1..225eb94bd 100644 --- a/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/config/TestSecurity.java +++ b/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/config/TestSecurity.java @@ -43,8 +43,8 @@ public void testDefault() throws Exception cqlTlsConfig.setTruststore("/path/to/truststore"); cqlTlsConfig.setTruststore_password("ecchronos"); cqlTlsConfig.setCertificate(null); - cqlTlsConfig.setCertificate_key(null); - cqlTlsConfig.setCertificate_authorities(null); + cqlTlsConfig.setCertificate_private_key(null); + cqlTlsConfig.setTrust_certificate(null); cqlTlsConfig.setProtocol("TLSv1.2"); cqlTlsConfig.setAlgorithm(null); cqlTlsConfig.setStore_type("JKS"); @@ -121,8 +121,8 @@ public void testEnabledWithCertificate() throws Exception TLSConfig cqlTlsConfig = new TLSConfig(); cqlTlsConfig.setEnabled(true); cqlTlsConfig.setCertificate("/path/to/cql/certificate"); - cqlTlsConfig.setCertificate_key("/path/to/cql/certificate_key"); - cqlTlsConfig.setCertificate_authorities("/path/to/cql/certificate_authorities"); + cqlTlsConfig.setCertificate_private_key("/path/to/cql/certificate_key"); + cqlTlsConfig.setTrust_certificate("/path/to/cql/certificate_authorities"); cqlTlsConfig.setProtocol("TLSv1.2"); cqlTlsConfig.setCipher_suites("VALID_CIPHER_SUITE,VALID_CIPHER_SUITE2"); cqlTlsConfig.setRequire_endpoint_verification(true); diff --git a/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TestTomcatWebServerCustomizerPem.java b/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TestTomcatWebServerCustomizerPem.java index 2abbd51a6..9678ec5e8 100644 --- a/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TestTomcatWebServerCustomizerPem.java +++ b/application/src/test/java/com/ericsson/bss/cassandra/ecchronos/application/spring/TestTomcatWebServerCustomizerPem.java @@ -24,8 +24,7 @@ properties = { "server.ssl.certificate=src/test/resources/server/cert.crt", "server.ssl.certificate-private-key=src/test/resources/server/key.pem", - "server.ssl.trust-certificate=src/test/resources/server/ca.crt", - "server.ssl.key-store-password=test" + "server.ssl.trust-certificate=src/test/resources/server/ca.crt" }) @ContextConfiguration(initializers = TestTomcatWebServerCustomizer.PropertyOverrideContextInitializer.class) public class TestTomcatWebServerCustomizerPem extends TestTomcatWebServerCustomizer {} \ No newline at end of file diff --git a/application/src/test/resources/enabled_certificate_security.yml b/application/src/test/resources/enabled_certificate_security.yml index 7e2c79bf9..1a94688e1 100644 --- a/application/src/test/resources/enabled_certificate_security.yml +++ b/application/src/test/resources/enabled_certificate_security.yml @@ -21,8 +21,8 @@ cql: tls: enabled: true certificate: /path/to/cql/certificate - certificate_key: /path/to/cql/certificate_key - certificate_authorities: /path/to/cql/certificate_authorities + certificate_private_key: /path/to/cql/certificate_key + trust_certificate: /path/to/cql/certificate_authorities protocol: TLSv1.2 cipher_suites: VALID_CIPHER_SUITE,VALID_CIPHER_SUITE2 require_endpoint_verification: true diff --git a/ecchronos-binary/pom.xml b/ecchronos-binary/pom.xml index c797c3026..09e6678e7 100644 --- a/ecchronos-binary/pom.xml +++ b/ecchronos-binary/pom.xml @@ -104,6 +104,7 @@ MIT License The MIT License (MIT) MIT + MIT-0 Eclipse Public License - v 1.0 EPL 2.0 EDL 1.0 diff --git a/pom.xml b/pom.xml index 1344f4d92..b3c259059 100644 --- a/pom.xml +++ b/pom.xml @@ -88,7 +88,7 @@ 1.0 1.1.1 3.5 - 2.7.0 + 2.7.2 1.6.8 0.10.0 2.0.2 From 9a6c37edce680492bc4c6105064851d0c2bc8f39 Mon Sep 17 00:00:00 2001 From: Valmira Correa Date: Tue, 6 Sep 2022 18:41:27 -0300 Subject: [PATCH 08/10] Correct certificate files and add a note in application.yml --- application/src/main/resources/application.yml | 3 +-- application/src/test/resources/server/ca.crt | 2 +- application/src/test/resources/server/key.pem | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/application/src/main/resources/application.yml b/application/src/main/resources/application.yml index 6894395fe..bb05f44d1 100644 --- a/application/src/main/resources/application.yml +++ b/application/src/main/resources/application.yml @@ -49,10 +49,9 @@ springdoc: # key-store-type: # key-alias: # key-password: -# SSL configuration using certificates in PEM format +# SSL configuration using certificates in PEM format. This configuration takes precedence when certificate store settings are also specified. # certificate: # certificate-private-key: -# Optional configuration for certificates in PEM format # trust-certificate: # Rate at which certificates are reloaded automatically # refresh-rate-in-ms: 60000 \ No newline at end of file diff --git a/application/src/test/resources/server/ca.crt b/application/src/test/resources/server/ca.crt index df30d7a85..be4507701 100644 --- a/application/src/test/resources/server/ca.crt +++ b/application/src/test/resources/server/ca.crt @@ -18,4 +18,4 @@ cj+6bEY12FxBW2G0kc80rjbMbfLZEpHEdHKwJLosWuNOBWYOdZof4pS9uQUeGJKq 9MYJl/HFf1j7ZOzNoy9220eSz2rEe90aCD5QJZklkUeCK3uxjIxU9SegUn5XD5jj aKli1AIgnCYbR76TU8xXRtq5CCohhbM21f/SUZQehluupQ9z3UL9MjMXMN+61ejT skIUYVNCWMEOV23Cc4+JhV6LC6ivJpv9E/Zxh7H/Gyz2Df0= ------END CERTIFICATE----- \ No newline at end of file +-----END CERTIFICATE----- diff --git a/application/src/test/resources/server/key.pem b/application/src/test/resources/server/key.pem index 1b94b251d..40872248a 100644 --- a/application/src/test/resources/server/key.pem +++ b/application/src/test/resources/server/key.pem @@ -25,4 +25,4 @@ XIcsUzMXOuGySF5BdQAf+pJ0wfA/g9ZAv8ey+bcCgYApjzqcWCw9c/DOAdLQPbGX F+gpz3WoyqWMUQ6/3hpivG8gKGdEMv5ecpfrV9uHEZDPXsbdGAAJC9+nxUh0AQZj 8sYojRi8I6/DfDNj3aLaepTW2jbHEhiHNzaHxoGKV6i1BuuMRcligYRDxwslOxAv vqeORuYWSWlLMBJc8DWA7g== ------END PRIVATE KEY----- \ No newline at end of file +-----END PRIVATE KEY----- From 9ed75036351b6fb60688675d0e8f00419222e0e3 Mon Sep 17 00:00:00 2001 From: Valmira Correa Date: Wed, 21 Sep 2022 22:24:40 -0300 Subject: [PATCH 09/10] Add a note about RSA certificate support --- application/src/main/resources/application.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/application/src/main/resources/application.yml b/application/src/main/resources/application.yml index bb05f44d1..e6f0ab55d 100644 --- a/application/src/main/resources/application.yml +++ b/application/src/main/resources/application.yml @@ -49,7 +49,9 @@ springdoc: # key-store-type: # key-alias: # key-password: -# SSL configuration using certificates in PEM format. This configuration takes precedence when certificate store settings are also specified. +# SSL configuration using certificates in PEM format +# This configuration takes precedence when certificate store settings are also specified +# Only certificates using RSA algorithm are supported # certificate: # certificate-private-key: # trust-certificate: From ed657280bc5cb7ffd093d46d18e81cc26e00a2bc Mon Sep 17 00:00:00 2001 From: Valmira Correa Date: Tue, 27 Sep 2022 20:28:20 -0300 Subject: [PATCH 10/10] Fix merge conflicts --- .../ecchronos/application/ReloadingCertificateHandler.java | 4 ++-- .../bss/cassandra/ecchronos/application/config/TLSConfig.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) 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 6969ac658..a2419dcce 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 @@ -175,9 +175,9 @@ protected static SslContext createSSLContext(TLSConfig tlsConfig) throws IOExcep builder.keyManager(keyManagerFactory); builder.trustManager(trustManagerFactory); } - if (tlsConfig.getCipherSuites().isPresent()) + if (tlsConfig.getCipher_suites().isPresent()) { - builder.ciphers(Arrays.asList(tlsConfig.getCipherSuites().get())); + builder.ciphers(Arrays.asList(tlsConfig.getCipher_suites().get())); } return builder.protocols(tlsConfig.getProtocols()).build(); } diff --git a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/TLSConfig.java b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/TLSConfig.java index 38beb2da6..271031e36 100644 --- a/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/TLSConfig.java +++ b/application/src/main/java/com/ericsson/bss/cassandra/ecchronos/application/config/TLSConfig.java @@ -128,7 +128,7 @@ public final String getProtocol() return protocol; } - public String[] getProtocols() + public final String[] getProtocols() { return protocol.split(","); } @@ -201,7 +201,7 @@ public final boolean equals(final Object o) } TLSConfig tlsConfig = (TLSConfig) o; return enabled == tlsConfig.enabled - require_endpoint_verification == tlsConfig.require_endpoint_verification + && require_endpoint_verification == tlsConfig.require_endpoint_verification && Objects.equals(keystore, tlsConfig.keystore) && Objects.equals(keystore_password, tlsConfig.keystore_password) && Objects.equals(truststore, tlsConfig.truststore)