diff options
author | Bjørn Christian Seime <bjorn.christian@seime.no> | 2017-12-06 16:50:38 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-12-06 16:50:38 +0100 |
commit | 8eca6284aa54563c0f0ba3fca1e2b2634a310cb5 (patch) | |
tree | c577b49360cf12128123b1d669c7213a78b03f6b | |
parent | 885e43f0fa85c7a0afaef905fb652399d5237bb3 (diff) | |
parent | f1fbd499da784fef06ef4f3bcaedf32d3ecc394a (diff) |
Merge pull request #4369 from vespa-engine/bjorncs/more-robust-ssl-init
Bjorncs/more robust ssl init
-rw-r--r-- | athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzSslKeyStoreConfigurator.java | 62 |
1 files changed, 41 insertions, 21 deletions
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzSslKeyStoreConfigurator.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzSslKeyStoreConfigurator.java index 3b7d05bf026..706f797cd2c 100644 --- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzSslKeyStoreConfigurator.java +++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzSslKeyStoreConfigurator.java @@ -10,12 +10,15 @@ import com.yahoo.log.LogLevel; import com.yahoo.vespa.hosted.athenz.instanceproviderservice.config.AthenzProviderServiceConfig; import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.AthenzCertificateClient; +import java.io.IOException; import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.cert.Certificate; +import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.time.Duration; -import java.time.Instant; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -34,12 +37,14 @@ public class AthenzSslKeyStoreConfigurator extends AbstractComponent implements // TODO Make expiry and update frequency configurable parameters private static final Duration CERTIFICATE_EXPIRY_TIME = Duration.ofDays(30); private static final Duration CERTIFICATE_UPDATE_PERIOD = Duration.ofDays(7); + private static final String DUMMY_PASSWORD = "athenz"; private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); private final AthenzCertificateClient certificateClient; private final KeyProvider keyProvider; private final AthenzProviderServiceConfig.Zones zoneConfig; private final AtomicBoolean alreadyConfigured = new AtomicBoolean(); + private KeyStore initialKeyStore; @Inject public AthenzSslKeyStoreConfigurator(KeyProvider keyProvider, @@ -49,6 +54,7 @@ public class AthenzSslKeyStoreConfigurator extends AbstractComponent implements this.certificateClient = new AthenzCertificateClient(config, zoneConfig); this.keyProvider = keyProvider; this.zoneConfig = zoneConfig; + this.initialKeyStore = downloadCertificate(keyProvider, certificateClient, zoneConfig); } @Override @@ -56,8 +62,12 @@ public class AthenzSslKeyStoreConfigurator extends AbstractComponent implements if (alreadyConfigured.getAndSet(true)) { // For debugging purpose of SslKeyStoreConfigurator interface throw new IllegalStateException("Already configured. configure() can only be called once."); } - AthenzCertificateUpdater updater = new AthenzCertificateUpdater(sslKeyStoreContext); - scheduler.scheduleAtFixedRate(updater, /*initialDelay*/0, CERTIFICATE_UPDATE_PERIOD.toMinutes(), TimeUnit.MINUTES); + sslKeyStoreContext.updateKeyStore(initialKeyStore, DUMMY_PASSWORD); + initialKeyStore = null; + scheduler.scheduleAtFixedRate(new AthenzCertificateUpdater(sslKeyStoreContext), + CERTIFICATE_UPDATE_PERIOD.toMinutes()/*initial delay*/, + CERTIFICATE_UPDATE_PERIOD.toMinutes(), + TimeUnit.MINUTES); } @Override @@ -70,6 +80,32 @@ public class AthenzSslKeyStoreConfigurator extends AbstractComponent implements } } + private static KeyStore downloadCertificate(KeyProvider keyProvider, + AthenzCertificateClient certificateClient, + AthenzProviderServiceConfig.Zones zoneConfig) { + try { + PrivateKey privateKey = keyProvider.getPrivateKey(zoneConfig.secretVersion()); + X509Certificate certificate = certificateClient.updateCertificate(privateKey, CERTIFICATE_EXPIRY_TIME); + verifyActualExpiry(certificate); + + KeyStore keyStore = KeyStore.getInstance("JKS"); + keyStore.load(null); + keyStore.setKeyEntry("athenz", privateKey, DUMMY_PASSWORD.toCharArray(), new Certificate[]{certificate}); + return keyStore; + } catch (IOException | NoSuchAlgorithmException | CertificateException | KeyStoreException e) { + throw new RuntimeException(e); + } + } + + private static void verifyActualExpiry(X509Certificate certificate) { + Duration actualExpiry = + Duration.between(certificate.getNotBefore().toInstant(), certificate.getNotAfter().toInstant()); + if (CERTIFICATE_EXPIRY_TIME.compareTo(actualExpiry) > 0) { + log.log(LogLevel.WARNING, + String.format("Expected expiry %s, got %s", CERTIFICATE_EXPIRY_TIME, actualExpiry)); + } + } + private class AthenzCertificateUpdater implements Runnable { private final SslKeyStoreContext sslKeyStoreContext; @@ -82,29 +118,13 @@ public class AthenzSslKeyStoreConfigurator extends AbstractComponent implements public void run() { try { log.log(LogLevel.INFO, "Updating Athenz certificate from ZTS"); - PrivateKey privateKey = keyProvider.getPrivateKey(zoneConfig.secretVersion()); - X509Certificate certificate = certificateClient.updateCertificate(privateKey, CERTIFICATE_EXPIRY_TIME); - verifyActualExperiy(certificate); - - String dummyPassword = "athenz"; - KeyStore keyStore = KeyStore.getInstance("JKS"); - keyStore.load(null); - keyStore.setKeyEntry("athenz", privateKey, dummyPassword.toCharArray(), new Certificate[]{certificate}); - sslKeyStoreContext.updateKeyStore(keyStore, dummyPassword); + KeyStore keyStore = downloadCertificate(keyProvider, certificateClient, zoneConfig); + sslKeyStoreContext.updateKeyStore(keyStore, DUMMY_PASSWORD); log.log(LogLevel.INFO, "Athenz certificate reload successfully completed"); } catch (Throwable e) { log.log(LogLevel.ERROR, "Failed to update certificate from ZTS: " + e.getMessage(), e); } } - private void verifyActualExperiy(X509Certificate certificate) { - Instant notAfter = certificate.getNotAfter().toInstant(); - Instant notBefore = certificate.getNotBefore().toInstant(); - if (!notBefore.plus(CERTIFICATE_EXPIRY_TIME).equals(notAfter)) { - Duration actualExpiry = Duration.between(notBefore, notAfter); - log.log(LogLevel.WARNING, - String.format("Expected expiry %s, got %s", CERTIFICATE_EXPIRY_TIME, actualExpiry)); - } - } } } |