summaryrefslogtreecommitdiffstats
path: root/athenz-identity-provider-service
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@oath.com>2017-11-15 17:01:10 +0100
committerBjørn Christian Seime <bjorncs@oath.com>2017-11-16 11:38:17 +0100
commit7d0ef9a536a8cab7a7920306171d0f2e7a845462 (patch)
tree58ad39cc1c07ecc9971c5f5bf1730dfad247ccb3 /athenz-identity-provider-service
parent26a183be1a9f6bad2d0206449666e3a98a5b7c74 (diff)
Add Athenz implementation of SslKeyStoreConfigurator
Diffstat (limited to 'athenz-identity-provider-service')
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzSslKeyStoreConfigurator.java98
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/Utils.java8
2 files changed, 106 insertions, 0 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
new file mode 100644
index 00000000000..fb4e331f1e9
--- /dev/null
+++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzSslKeyStoreConfigurator.java
@@ -0,0 +1,98 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+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.SecretStore;
+import com.yahoo.jdisc.http.ssl.SslKeyStoreConfigurator;
+import com.yahoo.jdisc.http.ssl.SslKeyStoreContext;
+import com.yahoo.log.LogLevel;
+import com.yahoo.vespa.hosted.athenz.instanceproviderservice.config.AthenzProviderServiceConfig;
+import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.AthenzCertificateClient;
+import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.SecretStoreKeyProvider;
+
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.time.Duration;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.logging.Logger;
+
+import static com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.Utils.getZoneConfig;
+
+/**
+ * @author bjorncs
+ */
+public class AthenzSslKeyStoreConfigurator extends AbstractComponent implements SslKeyStoreConfigurator {
+ private static final Logger log = Logger.getLogger(AthenzSslKeyStoreConfigurator.class.getName());
+ // 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(1);
+
+ private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
+ private final AthenzCertificateClient certificateClient;
+ private final SecretStoreKeyProvider keyProvider;
+ private final AthenzProviderServiceConfig.Zones zoneConfig;
+ private final AtomicBoolean alreadyConfigured = new AtomicBoolean();
+
+ @Inject
+ public AthenzSslKeyStoreConfigurator(SecretStore secretStore,
+ AthenzProviderServiceConfig config,
+ Zone zone) {
+ AthenzProviderServiceConfig.Zones zoneConfig = getZoneConfig(config, zone);
+ this.certificateClient = new AthenzCertificateClient(config, zoneConfig);
+ this.keyProvider = new SecretStoreKeyProvider(secretStore, zoneConfig.secretName());
+ this.zoneConfig = zoneConfig;
+ }
+
+ @Override
+ public void configure(SslKeyStoreContext sslKeyStoreContext) {
+ 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);
+ }
+
+ @Override
+ public void deconstruct() {
+ try {
+ scheduler.shutdownNow();
+ scheduler.awaitTermination(30, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Failed to shutdown Athenz certificate updater on time", e);
+ }
+ }
+
+ private class AthenzCertificateUpdater implements Runnable {
+
+ private final SslKeyStoreContext sslKeyStoreContext;
+
+ AthenzCertificateUpdater(SslKeyStoreContext sslKeyStoreContext) {
+ this.sslKeyStoreContext = sslKeyStoreContext;
+ }
+
+ @Override
+ 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);
+
+ String dummyPassword = "athenz";
+ KeyStore keyStore = KeyStore.getInstance("JKS");
+ keyStore.load(null);
+ keyStore.setKeyEntry("athenz", privateKey, dummyPassword.toCharArray(), new Certificate[]{certificate});
+ sslKeyStoreContext.updateKeyStore(keyStore, dummyPassword);
+ 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);
+ }
+ }
+ }
+}
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/Utils.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/Utils.java
index d81ec183fd4..ad54aa341bf 100644
--- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/Utils.java
+++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/Utils.java
@@ -3,6 +3,8 @@ package com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import com.yahoo.config.provision.Zone;
+import com.yahoo.vespa.hosted.athenz.instanceproviderservice.config.AthenzProviderServiceConfig;
/**
* @author bjorncs
@@ -20,4 +22,10 @@ public class Utils {
mapper.registerModule(new JavaTimeModule());
return mapper;
}
+
+ public static AthenzProviderServiceConfig.Zones getZoneConfig(AthenzProviderServiceConfig config, Zone zone) {
+ String key = zone.environment().value() + "." + zone.region().value();
+ return config.zones(key);
+ }
+
}