From 303dbfddb8d2e44cf16a2847fa5983aa1dbd4154 Mon Sep 17 00:00:00 2001 From: Bjørn Christian Seime Date: Wed, 3 Jul 2019 14:01:05 +0200 Subject: Use TlsContextBasedProvider in ConfigserverSslContextFactoryProvider --- .../ConfigserverSslContextFactoryProvider.java | 80 +++++++++------------- 1 file changed, 33 insertions(+), 47 deletions(-) (limited to 'athenz-identity-provider-service/src') diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ConfigserverSslContextFactoryProvider.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ConfigserverSslContextFactoryProvider.java index 0eeeae457b6..7c25e906b6f 100644 --- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ConfigserverSslContextFactoryProvider.java +++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ConfigserverSslContextFactoryProvider.java @@ -2,13 +2,17 @@ package com.yahoo.vespa.hosted.athenz.instanceproviderservice; import com.google.inject.Inject; -import com.yahoo.component.AbstractComponent; import com.yahoo.config.provision.Zone; -import com.yahoo.jdisc.http.ssl.SslContextFactoryProvider; +import com.yahoo.jdisc.http.ssl.impl.TlsContextBasedProvider; import com.yahoo.log.LogLevel; import com.yahoo.security.KeyStoreBuilder; import com.yahoo.security.KeyStoreType; import com.yahoo.security.KeyUtils; +import com.yahoo.security.SslContextBuilder; +import com.yahoo.security.tls.DefaultTlsContext; +import com.yahoo.security.tls.MutableX509KeyManager; +import com.yahoo.security.tls.PeerAuthentication; +import com.yahoo.security.tls.TlsContext; import com.yahoo.vespa.athenz.api.AthenzService; import com.yahoo.vespa.athenz.client.zts.DefaultZtsClient; import com.yahoo.vespa.athenz.client.zts.Identity; @@ -17,12 +21,11 @@ import com.yahoo.vespa.athenz.identity.ServiceIdentityProvider; import com.yahoo.vespa.athenz.utils.SiaUtils; import com.yahoo.vespa.defaults.Defaults; import com.yahoo.vespa.hosted.athenz.instanceproviderservice.config.AthenzProviderServiceConfig; -import org.eclipse.jetty.util.ssl.SslContextFactory; +import javax.net.ssl.SSLContext; import java.net.URI; import java.nio.file.Path; import java.nio.file.Paths; -import java.security.GeneralSecurityException; import java.security.KeyPair; import java.security.KeyStore; import java.security.PrivateKey; @@ -42,14 +45,15 @@ import java.util.logging.Logger; * * @author bjorncs */ -public class ConfigserverSslContextFactoryProvider extends AbstractComponent implements SslContextFactoryProvider { +public class ConfigserverSslContextFactoryProvider extends TlsContextBasedProvider { private static final String CERTIFICATE_ALIAS = "athenz"; private static final Duration EXPIRATION_MARGIN = Duration.ofHours(6); private static final Path VESPA_SIA_DIRECTORY = Paths.get(Defaults.getDefaults().underVespaHome("var/vespa/sia")); private static final Logger log = Logger.getLogger(ConfigserverSslContextFactoryProvider.class.getName()); - private final SslContextFactory sslContextFactory; + private final TlsContext tlsContext; + private final MutableX509KeyManager keyManager = new MutableX509KeyManager(); private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(runnable -> new Thread(runnable, "configserver-ssl-context-factory-provider")); private final ZtsClient ztsClient; @@ -69,25 +73,20 @@ public class ConfigserverSslContextFactoryProvider extends AbstractComponent imp Duration updatePeriod = Duration.ofDays(config.updatePeriodDays()); Path trustStoreFile = Paths.get(config.athenzCaTrustStore()); - this.sslContextFactory = initializeSslContextFactory(keyProvider, trustStoreFile, updatePeriod, configserverIdentity, ztsClient, athenzProviderServiceConfig); - scheduler.scheduleAtFixedRate(new KeystoreUpdater(sslContextFactory), + this.tlsContext = createTlsContext(keyProvider, keyManager, trustStoreFile, updatePeriod, configserverIdentity, ztsClient, athenzProviderServiceConfig); + scheduler.scheduleAtFixedRate(new KeystoreUpdater(keyManager), updatePeriod.toDays()/*initial delay*/, updatePeriod.toDays(), TimeUnit.DAYS); } @Override - public SslContextFactory getInstance(String containerId, int port) { - return sslContextFactory; + protected TlsContext getTlsContext(String containerId, int port) { + return tlsContext; } Instant getCertificateNotAfter() { - try { - X509Certificate certificate = (X509Certificate) sslContextFactory.getKeyStore().getCertificate(CERTIFICATE_ALIAS); - return certificate.getNotAfter().toInstant(); - } catch (GeneralSecurityException e) { - throw new IllegalStateException("Unable to find configserver certificate from keystore: " + e.getMessage(), e); - } + return keyManager.getCertificateChain(CERTIFICATE_ALIAS)[0].getNotAfter().toInstant(); } @Override @@ -96,38 +95,28 @@ public class ConfigserverSslContextFactoryProvider extends AbstractComponent imp scheduler.shutdownNow(); scheduler.awaitTermination(30, TimeUnit.SECONDS); ztsClient.close(); + super.deconstruct(); } catch (InterruptedException e) { throw new RuntimeException("Failed to shutdown Athenz certificate updater on time", e); } } - private static SslContextFactory initializeSslContextFactory(KeyProvider keyProvider, - Path trustStoreFile, - Duration updatePeriod, - AthenzService configserverIdentity, - ZtsClient ztsClient, - AthenzProviderServiceConfig zoneConfig) { - - // TODO Use DefaultTlsContext to configure SslContextFactory (ensure that cipher/protocol configuration is same across all TLS endpoints) - - SslContextFactory.Server factory = new SslContextFactory.Server(); - - factory.setWantClientAuth(true); - - KeyStore trustStore = - KeyStoreBuilder.withType(KeyStoreType.JKS) - .fromFile(trustStoreFile) - .build(); - factory.setTrustStore(trustStore); - + private static TlsContext createTlsContext(KeyProvider keyProvider, + MutableX509KeyManager keyManager, + Path trustStoreFile, + Duration updatePeriod, + AthenzService configserverIdentity, + ZtsClient ztsClient, + AthenzProviderServiceConfig zoneConfig) { KeyStore keyStore = tryReadKeystoreFile(configserverIdentity, updatePeriod) .orElseGet(() -> updateKeystore(configserverIdentity, generateKeystorePassword(), keyProvider, ztsClient, zoneConfig)); - factory.setKeyStore(keyStore); - factory.setKeyStorePassword(""); - factory.setExcludeProtocols("TLSv1.3"); // TLSv1.3 is broken is multiple OpenJDK 11 versions - factory.setEndpointIdentificationAlgorithm(null); // disable https hostname verification of clients (must be disabled when using Athenz x509 certificates) - return factory; + keyManager.updateKeystore(keyStore, new char[0]); + SSLContext sslContext = new SslContextBuilder() + .withTrustStore(trustStoreFile) + .withKeyManager(keyManager) + .build(); + return new DefaultTlsContext(sslContext, PeerAuthentication.WANT); } private static Optional tryReadKeystoreFile(AthenzService configserverIdentity, Duration updatePeriod) { @@ -171,10 +160,10 @@ public class ConfigserverSslContextFactoryProvider extends AbstractComponent imp } private class KeystoreUpdater implements Runnable { - final SslContextFactory sslContextFactory; + final MutableX509KeyManager keyManager; - KeystoreUpdater(SslContextFactory sslContextFactory) { - this.sslContextFactory = sslContextFactory; + KeystoreUpdater(MutableX509KeyManager keyManager) { + this.keyManager = keyManager; } @Override @@ -183,10 +172,7 @@ public class ConfigserverSslContextFactoryProvider extends AbstractComponent imp log.log(LogLevel.INFO, "Updating configserver provider certificate from ZTS"); char[] keystorePwd = generateKeystorePassword(); KeyStore keyStore = updateKeystore(configserverIdentity, keystorePwd, keyProvider, ztsClient, athenzProviderServiceConfig); - sslContextFactory.reload(scf -> { - scf.setKeyStore(keyStore); - scf.setKeyStorePassword(new String(keystorePwd)); - }); + keyManager.updateKeystore(keyStore, keystorePwd); log.log(LogLevel.INFO, "Certificate successfully updated"); } catch (Throwable t) { log.log(LogLevel.ERROR, "Failed to update certificate from ZTS: " + t.getMessage(), t); -- cgit v1.2.3