aboutsummaryrefslogtreecommitdiffstats
path: root/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider
diff options
context:
space:
mode:
authorOla Aunronning <olaa@yahooinc.com>2023-04-25 11:37:55 +0200
committerOla Aunronning <olaa@yahooinc.com>2023-04-25 11:39:34 +0200
commitcf4c4d51f2853f094717e957a06eb409c1b1503e (patch)
tree63444b5113a84b25d9f79f2062e2b5834f7c1b28 /vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider
parent8436d1e3127f6e5d1f131f23ac6d35be3692362f (diff)
Rename AthenzIdentityProviderImpl classes
Diffstat (limited to 'vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider')
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java109
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderProvider.java4
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/LegacyAthenzIdentityProviderImpl.java (renamed from vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImplV2.java)125
3 files changed, 118 insertions, 120 deletions
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java
index b9f9f3862c2..3d8f12e559d 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java
@@ -11,7 +11,9 @@ import com.yahoo.container.jdisc.athenz.AthenzIdentityProvider;
import com.yahoo.container.jdisc.athenz.AthenzIdentityProviderException;
import com.yahoo.jdisc.Metric;
import com.yahoo.metrics.ContainerMetrics;
+import com.yahoo.security.AutoReloadingX509KeyManager;
import com.yahoo.security.KeyStoreBuilder;
+import com.yahoo.security.KeyUtils;
import com.yahoo.security.MutableX509KeyManager;
import com.yahoo.security.Pkcs10Csr;
import com.yahoo.security.SslContextBuilder;
@@ -24,9 +26,9 @@ import com.yahoo.vespa.athenz.api.ZToken;
import com.yahoo.vespa.athenz.client.zts.DefaultZtsClient;
import com.yahoo.vespa.athenz.client.zts.ZtsClient;
import com.yahoo.vespa.athenz.identity.ServiceIdentityProvider;
-import com.yahoo.vespa.athenz.identity.SiaIdentityProvider;
+import com.yahoo.vespa.athenz.identityprovider.api.VespaUniqueInstanceId;
+import com.yahoo.vespa.athenz.tls.AthenzX509CertificateUtils;
import com.yahoo.vespa.athenz.utils.SiaUtils;
-import com.yahoo.vespa.defaults.Defaults;
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509ExtendedKeyManager;
@@ -38,7 +40,6 @@ import java.security.cert.X509Certificate;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -65,7 +66,6 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
// TODO Make some of these values configurable through config. Match requested expiration of register/update requests.
// TODO These should match the requested expiration
- static final Duration UPDATE_PERIOD = Duration.ofDays(1);
static final Duration AWAIT_TERMINTATION_TIMEOUT = Duration.ofSeconds(90);
private final static Duration ROLE_SSL_CONTEXT_EXPIRY = Duration.ofHours(2);
// TODO CMS expects 10min or less token ttl. Use 10min default until we have configurable expiry
@@ -73,20 +73,17 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
// TODO Make path to trust store paths config
private static final Path CLIENT_TRUST_STORE = Paths.get("/opt/yahoo/share/ssl/certs/yahoo_certificate_bundle.pem");
- private static final Path ATHENZ_TRUST_STORE = Paths.get("/opt/yahoo/share/ssl/certs/athenz_certificate_bundle.pem");
public static final String CERTIFICATE_EXPIRY_METRIC_NAME = ContainerMetrics.ATHENZ_TENANT_CERT_EXPIRY_SECONDS.baseName();
- private volatile AthenzCredentials credentials;
private final Metric metric;
private final Path trustStore;
- private final AthenzCredentialsService athenzCredentialsService;
private final ScheduledExecutorService scheduler;
private final Clock clock;
private final AthenzService identity;
private final URI ztsEndpoint;
- private final MutableX509KeyManager identityKeyManager = new MutableX509KeyManager();
+ private final AutoReloadingX509KeyManager autoReloadingX509KeyManager;
private final SSLContext identitySslContext;
private final LoadingCache<AthenzRole, X509Certificate> roleSslCertCache;
private final Map<AthenzRole, MutableX509KeyManager> roleKeyManagerCache;
@@ -98,40 +95,31 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
@Inject
public AthenzIdentityProviderImpl(IdentityConfig config, Metric metric) {
- this(config,
- metric,
- CLIENT_TRUST_STORE,
- new AthenzCredentialsService(config,
- createNodeIdentityProvider(config),
- Defaults.getDefaults().vespaHostname(),
- Clock.systemUTC()),
- new ScheduledThreadPoolExecutor(1),
- Clock.systemUTC());
+ this(config, metric, CLIENT_TRUST_STORE, new ScheduledThreadPoolExecutor(1), Clock.systemUTC());
}
// Test only
AthenzIdentityProviderImpl(IdentityConfig config,
Metric metric,
Path trustStore,
- AthenzCredentialsService athenzCredentialsService,
ScheduledExecutorService scheduler,
Clock clock) {
this.metric = metric;
this.trustStore = trustStore;
- this.athenzCredentialsService = athenzCredentialsService;
this.scheduler = scheduler;
this.clock = clock;
this.identity = new AthenzService(config.domain(), config.service());
this.ztsEndpoint = URI.create(config.ztsUrl());
- roleSslCertCache = crateAutoReloadableCache(ROLE_SSL_CONTEXT_EXPIRY, this::requestRoleCertificate, this.scheduler);
- roleKeyManagerCache = new HashMap<>();
- roleSpecificRoleTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createRoleToken);
- domainSpecificRoleTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createRoleToken);
- domainSpecificAccessTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createAccessToken);
- roleSpecificAccessTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createAccessToken);
+ this.roleSslCertCache = crateAutoReloadableCache(ROLE_SSL_CONTEXT_EXPIRY, this::requestRoleCertificate, this.scheduler);
+ this.roleKeyManagerCache = new HashMap<>();
+ this.roleSpecificRoleTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createRoleToken);
+ this.domainSpecificRoleTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createRoleToken);
+ this.domainSpecificAccessTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createAccessToken);
+ this.roleSpecificAccessTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createAccessToken);
this.csrGenerator = new CsrGenerator(config.athenzDnsSuffix(), config.configserverIdentityName());
- this.identitySslContext = createIdentitySslContext(identityKeyManager, trustStore);
- registerInstance();
+ this.autoReloadingX509KeyManager = AutoReloadingX509KeyManager.fromPemFiles(privateKeyPath(),certificatePath());
+ this.identitySslContext = createIdentitySslContext(autoReloadingX509KeyManager, trustStore);
+ this.scheduler.scheduleAtFixedRate(this::reportMetrics, 0, 5, TimeUnit.MINUTES);
}
private static <KEY, VALUE> LoadingCache<KEY, VALUE> createCache(Duration expiry, Function<KEY, VALUE> cacheLoader) {
@@ -165,16 +153,6 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
.build();
}
- private void registerInstance() {
- try {
- updateIdentityCredentials(this.athenzCredentialsService.registerInstance());
- this.scheduler.scheduleAtFixedRate(this::refreshCertificate, UPDATE_PERIOD.toMinutes(), UPDATE_PERIOD.toMinutes(), TimeUnit.MINUTES);
- this.scheduler.scheduleAtFixedRate(this::reportMetrics, 0, 5, TimeUnit.MINUTES);
- } catch (Throwable t) {
- throw new AthenzIdentityProviderException("Could not retrieve Athenz credentials", t);
- }
- }
-
@Override
public AthenzService identity() {
return identity;
@@ -197,13 +175,13 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
@Override
public X509CertificateWithKey getIdentityCertificateWithKey() {
- AthenzCredentials copy = this.credentials;
- return new X509CertificateWithKey(copy.getCertificate(), copy.getKeyPair().getPrivate());
+ var copy = this.autoReloadingX509KeyManager.getCurrentCertificateWithKey();
+ return new X509CertificateWithKey(copy.certificate(), copy.privateKey());
}
- @Override public Path certificatePath() { return athenzCredentialsService.certificatePath(); }
+ @Override public Path certificatePath() { return SiaUtils.getCertificateFile(identity); }
- @Override public Path privateKeyPath() { return athenzCredentialsService.privateKeyPath(); }
+ @Override public Path privateKeyPath() { return SiaUtils.getPrivateKeyFile(identity); }
@Override
public SSLContext getRoleSslContext(String domain, String role) {
@@ -262,7 +240,7 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
@Override
public PrivateKey getPrivateKey() {
- return credentials.getKeyPair().getPrivate();
+ return autoReloadingX509KeyManager.getPrivateKey(AutoReloadingX509KeyManager.CERTIFICATE_ALIAS);
}
@Override
@@ -272,7 +250,7 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
@Override
public List<X509Certificate> getIdentityCertificate() {
- return Collections.singletonList(credentials.getCertificate());
+ return List.of(autoReloadingX509KeyManager.getCertificateChain(AutoReloadingX509KeyManager.CERTIFICATE_ALIAS));
}
@Override
@@ -288,19 +266,15 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
}
}
- private void updateIdentityCredentials(AthenzCredentials credentials) {
- this.credentials = credentials;
- this.identityKeyManager.updateKeystore(
- KeyStoreBuilder.withType(PKCS12)
- .withKeyEntry("default", credentials.getKeyPair().getPrivate(), credentials.getCertificate())
- .build(),
- new char[0]);
- }
-
private X509Certificate requestRoleCertificate(AthenzRole role) {
- var doc = credentials.getIdentityDocument();
+ var credentials = autoReloadingX509KeyManager.getCurrentCertificateWithKey();
+ var athenzUniqueInstanceId = VespaUniqueInstanceId.fromDottedString(
+ AthenzX509CertificateUtils.getInstanceId(credentials.certificate())
+ .orElseThrow()
+ );
+ var keyPair = KeyUtils.toKeyPair(credentials.privateKey());
Pkcs10Csr csr = csrGenerator.generateRoleCsr(
- identity, role, doc.providerUniqueId(), doc.clusterType(), credentials.getKeyPair());
+ identity, role, athenzUniqueInstanceId, null, keyPair);
try (ZtsClient client = createZtsClient()) {
X509Certificate roleCertificate = client.getRoleCertificate(role, csr);
updateRoleKeyManager(role, roleCertificate);
@@ -313,7 +287,7 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
MutableX509KeyManager keyManager = roleKeyManagerCache.computeIfAbsent(role, r -> new MutableX509KeyManager());
keyManager.updateKeystore(
KeyStoreBuilder.withType(PKCS12)
- .withKeyEntry("default", credentials.getKeyPair().getPrivate(), certificate)
+ .withKeyEntry("default", autoReloadingX509KeyManager.getCurrentCertificateWithKey().privateKey(), certificate)
.build(),
new char[0]);
}
@@ -356,32 +330,13 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
}
}
- private static SiaIdentityProvider createNodeIdentityProvider(IdentityConfig config) {
- return new SiaIdentityProvider(
- new AthenzService(config.nodeIdentityName()), SiaUtils.DEFAULT_SIA_DIRECTORY, CLIENT_TRUST_STORE);
- }
-
- private boolean isExpired(AthenzCredentials credentials) {
- return clock.instant().isAfter(getExpirationTime(credentials));
- }
-
- private static Instant getExpirationTime(AthenzCredentials credentials) {
- return credentials.getCertificate().getNotAfter().toInstant();
- }
-
- void refreshCertificate() {
- try {
- updateIdentityCredentials(isExpired(credentials)
- ? athenzCredentialsService.registerInstance()
- : athenzCredentialsService.updateCredentials(credentials.getIdentityDocument(), identitySslContext));
- } catch (Throwable t) {
- log.log(Level.WARNING, "Failed to update credentials: " + t.getMessage(), t);
- }
+ private static Instant getExpirationTime(X509Certificate certificate) {
+ return certificate.getNotAfter().toInstant();
}
void reportMetrics() {
try {
- Instant expirationTime = getExpirationTime(credentials);
+ Instant expirationTime = getExpirationTime(autoReloadingX509KeyManager.getCurrentCertificateWithKey().certificate());
Duration remainingLifetime = Duration.between(clock.instant(), expirationTime);
metric.set(CERTIFICATE_EXPIRY_METRIC_NAME, remainingLifetime.getSeconds(), null);
} catch (Throwable t) {
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderProvider.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderProvider.java
index d53b68bffc9..66dad931815 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderProvider.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderProvider.java
@@ -21,9 +21,9 @@ public class AthenzIdentityProviderProvider implements Provider<AthenzIdentityPr
@Inject
public AthenzIdentityProviderProvider(IdentityConfig config, Metric metric) {
if (Files.exists(NODE_ADMIN_MANAGED_IDENTITY_DOCUMENT))
- athenzIdentityProvider = new AthenzIdentityProviderImplV2(config, metric);
- else
athenzIdentityProvider = new AthenzIdentityProviderImpl(config, metric);
+ else
+ athenzIdentityProvider = new LegacyAthenzIdentityProviderImpl(config, metric);
}
@Override
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImplV2.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/LegacyAthenzIdentityProviderImpl.java
index b03ad244ee4..e67af028402 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImplV2.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/LegacyAthenzIdentityProviderImpl.java
@@ -11,9 +11,7 @@ import com.yahoo.container.jdisc.athenz.AthenzIdentityProvider;
import com.yahoo.container.jdisc.athenz.AthenzIdentityProviderException;
import com.yahoo.jdisc.Metric;
import com.yahoo.metrics.ContainerMetrics;
-import com.yahoo.security.AutoReloadingX509KeyManager;
import com.yahoo.security.KeyStoreBuilder;
-import com.yahoo.security.KeyUtils;
import com.yahoo.security.MutableX509KeyManager;
import com.yahoo.security.Pkcs10Csr;
import com.yahoo.security.SslContextBuilder;
@@ -27,9 +25,8 @@ import com.yahoo.vespa.athenz.client.zts.DefaultZtsClient;
import com.yahoo.vespa.athenz.client.zts.ZtsClient;
import com.yahoo.vespa.athenz.identity.ServiceIdentityProvider;
import com.yahoo.vespa.athenz.identity.SiaIdentityProvider;
-import com.yahoo.vespa.athenz.identityprovider.api.VespaUniqueInstanceId;
-import com.yahoo.vespa.athenz.tls.AthenzX509CertificateUtils;
import com.yahoo.vespa.athenz.utils.SiaUtils;
+import com.yahoo.vespa.defaults.Defaults;
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509ExtendedKeyManager;
@@ -41,6 +38,7 @@ import java.security.cert.X509Certificate;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -58,16 +56,16 @@ import static com.yahoo.security.KeyStoreType.PKCS12;
*
* @author mortent
* @author bjorncs
- * @author olaa
*/
// This class should probably not implement ServiceIdentityProvider,
// as that interface is intended for providing the node's identity, not the tenant's application identity.
-public final class AthenzIdentityProviderImplV2 extends AbstractComponent implements AthenzIdentityProvider, ServiceIdentityProvider {
+public final class LegacyAthenzIdentityProviderImpl extends AbstractComponent implements AthenzIdentityProvider, ServiceIdentityProvider {
- private static final Logger log = Logger.getLogger(AthenzIdentityProviderImplV2.class.getName());
+ private static final Logger log = Logger.getLogger(LegacyAthenzIdentityProviderImpl.class.getName());
// TODO Make some of these values configurable through config. Match requested expiration of register/update requests.
// TODO These should match the requested expiration
+ static final Duration UPDATE_PERIOD = Duration.ofDays(1);
static final Duration AWAIT_TERMINTATION_TIMEOUT = Duration.ofSeconds(90);
private final static Duration ROLE_SSL_CONTEXT_EXPIRY = Duration.ofHours(2);
// TODO CMS expects 10min or less token ttl. Use 10min default until we have configurable expiry
@@ -75,17 +73,20 @@ public final class AthenzIdentityProviderImplV2 extends AbstractComponent implem
// TODO Make path to trust store paths config
private static final Path CLIENT_TRUST_STORE = Paths.get("/opt/yahoo/share/ssl/certs/yahoo_certificate_bundle.pem");
+ private static final Path ATHENZ_TRUST_STORE = Paths.get("/opt/yahoo/share/ssl/certs/athenz_certificate_bundle.pem");
public static final String CERTIFICATE_EXPIRY_METRIC_NAME = ContainerMetrics.ATHENZ_TENANT_CERT_EXPIRY_SECONDS.baseName();
+ private volatile AthenzCredentials credentials;
private final Metric metric;
private final Path trustStore;
+ private final AthenzCredentialsService athenzCredentialsService;
private final ScheduledExecutorService scheduler;
private final Clock clock;
private final AthenzService identity;
private final URI ztsEndpoint;
- private final AutoReloadingX509KeyManager autoReloadingX509KeyManager;
+ private final MutableX509KeyManager identityKeyManager = new MutableX509KeyManager();
private final SSLContext identitySslContext;
private final LoadingCache<AthenzRole, X509Certificate> roleSslCertCache;
private final Map<AthenzRole, MutableX509KeyManager> roleKeyManagerCache;
@@ -96,32 +97,41 @@ public final class AthenzIdentityProviderImplV2 extends AbstractComponent implem
private final CsrGenerator csrGenerator;
@Inject
- public AthenzIdentityProviderImplV2(IdentityConfig config, Metric metric) {
- this(config, metric, CLIENT_TRUST_STORE, new ScheduledThreadPoolExecutor(1), Clock.systemUTC());
+ public LegacyAthenzIdentityProviderImpl(IdentityConfig config, Metric metric) {
+ this(config,
+ metric,
+ CLIENT_TRUST_STORE,
+ new AthenzCredentialsService(config,
+ createNodeIdentityProvider(config),
+ Defaults.getDefaults().vespaHostname(),
+ Clock.systemUTC()),
+ new ScheduledThreadPoolExecutor(1),
+ Clock.systemUTC());
}
// Test only
- AthenzIdentityProviderImplV2(IdentityConfig config,
- Metric metric,
- Path trustStore,
- ScheduledExecutorService scheduler,
- Clock clock) {
+ LegacyAthenzIdentityProviderImpl(IdentityConfig config,
+ Metric metric,
+ Path trustStore,
+ AthenzCredentialsService athenzCredentialsService,
+ ScheduledExecutorService scheduler,
+ Clock clock) {
this.metric = metric;
this.trustStore = trustStore;
+ this.athenzCredentialsService = athenzCredentialsService;
this.scheduler = scheduler;
this.clock = clock;
this.identity = new AthenzService(config.domain(), config.service());
this.ztsEndpoint = URI.create(config.ztsUrl());
- this.roleSslCertCache = crateAutoReloadableCache(ROLE_SSL_CONTEXT_EXPIRY, this::requestRoleCertificate, this.scheduler);
- this.roleKeyManagerCache = new HashMap<>();
- this.roleSpecificRoleTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createRoleToken);
- this.domainSpecificRoleTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createRoleToken);
- this.domainSpecificAccessTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createAccessToken);
- this.roleSpecificAccessTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createAccessToken);
+ roleSslCertCache = crateAutoReloadableCache(ROLE_SSL_CONTEXT_EXPIRY, this::requestRoleCertificate, this.scheduler);
+ roleKeyManagerCache = new HashMap<>();
+ roleSpecificRoleTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createRoleToken);
+ domainSpecificRoleTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createRoleToken);
+ domainSpecificAccessTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createAccessToken);
+ roleSpecificAccessTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createAccessToken);
this.csrGenerator = new CsrGenerator(config.athenzDnsSuffix(), config.configserverIdentityName());
- this.autoReloadingX509KeyManager = AutoReloadingX509KeyManager.fromPemFiles(privateKeyPath(),certificatePath());
- this.identitySslContext = createIdentitySslContext(autoReloadingX509KeyManager, trustStore);
- this.scheduler.scheduleAtFixedRate(this::reportMetrics, 0, 5, TimeUnit.MINUTES);
+ this.identitySslContext = createIdentitySslContext(identityKeyManager, trustStore);
+ registerInstance();
}
private static <KEY, VALUE> LoadingCache<KEY, VALUE> createCache(Duration expiry, Function<KEY, VALUE> cacheLoader) {
@@ -155,6 +165,16 @@ public final class AthenzIdentityProviderImplV2 extends AbstractComponent implem
.build();
}
+ private void registerInstance() {
+ try {
+ updateIdentityCredentials(this.athenzCredentialsService.registerInstance());
+ this.scheduler.scheduleAtFixedRate(this::refreshCertificate, UPDATE_PERIOD.toMinutes(), UPDATE_PERIOD.toMinutes(), TimeUnit.MINUTES);
+ this.scheduler.scheduleAtFixedRate(this::reportMetrics, 0, 5, TimeUnit.MINUTES);
+ } catch (Throwable t) {
+ throw new AthenzIdentityProviderException("Could not retrieve Athenz credentials", t);
+ }
+ }
+
@Override
public AthenzService identity() {
return identity;
@@ -177,13 +197,13 @@ public final class AthenzIdentityProviderImplV2 extends AbstractComponent implem
@Override
public X509CertificateWithKey getIdentityCertificateWithKey() {
- var copy = this.autoReloadingX509KeyManager.getCurrentCertificateWithKey();
- return new X509CertificateWithKey(copy.certificate(), copy.privateKey());
+ AthenzCredentials copy = this.credentials;
+ return new X509CertificateWithKey(copy.getCertificate(), copy.getKeyPair().getPrivate());
}
- @Override public Path certificatePath() { return SiaUtils.getCertificateFile(identity); }
+ @Override public Path certificatePath() { return athenzCredentialsService.certificatePath(); }
- @Override public Path privateKeyPath() { return SiaUtils.getPrivateKeyFile(identity); }
+ @Override public Path privateKeyPath() { return athenzCredentialsService.privateKeyPath(); }
@Override
public SSLContext getRoleSslContext(String domain, String role) {
@@ -242,7 +262,7 @@ public final class AthenzIdentityProviderImplV2 extends AbstractComponent implem
@Override
public PrivateKey getPrivateKey() {
- return autoReloadingX509KeyManager.getPrivateKey(AutoReloadingX509KeyManager.CERTIFICATE_ALIAS);
+ return credentials.getKeyPair().getPrivate();
}
@Override
@@ -252,7 +272,7 @@ public final class AthenzIdentityProviderImplV2 extends AbstractComponent implem
@Override
public List<X509Certificate> getIdentityCertificate() {
- return List.of(autoReloadingX509KeyManager.getCertificateChain(AutoReloadingX509KeyManager.CERTIFICATE_ALIAS));
+ return Collections.singletonList(credentials.getCertificate());
}
@Override
@@ -268,15 +288,19 @@ public final class AthenzIdentityProviderImplV2 extends AbstractComponent implem
}
}
+ private void updateIdentityCredentials(AthenzCredentials credentials) {
+ this.credentials = credentials;
+ this.identityKeyManager.updateKeystore(
+ KeyStoreBuilder.withType(PKCS12)
+ .withKeyEntry("default", credentials.getKeyPair().getPrivate(), credentials.getCertificate())
+ .build(),
+ new char[0]);
+ }
+
private X509Certificate requestRoleCertificate(AthenzRole role) {
- var credentials = autoReloadingX509KeyManager.getCurrentCertificateWithKey();
- var athenzUniqueInstanceId = VespaUniqueInstanceId.fromDottedString(
- AthenzX509CertificateUtils.getInstanceId(credentials.certificate())
- .orElseThrow()
- );
- var keyPair = KeyUtils.toKeyPair(credentials.privateKey());
+ var doc = credentials.getIdentityDocument();
Pkcs10Csr csr = csrGenerator.generateRoleCsr(
- identity, role, athenzUniqueInstanceId, null, keyPair);
+ identity, role, doc.providerUniqueId(), doc.clusterType(), credentials.getKeyPair());
try (ZtsClient client = createZtsClient()) {
X509Certificate roleCertificate = client.getRoleCertificate(role, csr);
updateRoleKeyManager(role, roleCertificate);
@@ -289,7 +313,7 @@ public final class AthenzIdentityProviderImplV2 extends AbstractComponent implem
MutableX509KeyManager keyManager = roleKeyManagerCache.computeIfAbsent(role, r -> new MutableX509KeyManager());
keyManager.updateKeystore(
KeyStoreBuilder.withType(PKCS12)
- .withKeyEntry("default", autoReloadingX509KeyManager.getCurrentCertificateWithKey().privateKey(), certificate)
+ .withKeyEntry("default", credentials.getKeyPair().getPrivate(), certificate)
.build(),
new char[0]);
}
@@ -332,13 +356,32 @@ public final class AthenzIdentityProviderImplV2 extends AbstractComponent implem
}
}
- private static Instant getExpirationTime(X509Certificate certificate) {
- return certificate.getNotAfter().toInstant();
+ private static SiaIdentityProvider createNodeIdentityProvider(IdentityConfig config) {
+ return new SiaIdentityProvider(
+ new AthenzService(config.nodeIdentityName()), SiaUtils.DEFAULT_SIA_DIRECTORY, CLIENT_TRUST_STORE);
+ }
+
+ private boolean isExpired(AthenzCredentials credentials) {
+ return clock.instant().isAfter(getExpirationTime(credentials));
+ }
+
+ private static Instant getExpirationTime(AthenzCredentials credentials) {
+ return credentials.getCertificate().getNotAfter().toInstant();
+ }
+
+ void refreshCertificate() {
+ try {
+ updateIdentityCredentials(isExpired(credentials)
+ ? athenzCredentialsService.registerInstance()
+ : athenzCredentialsService.updateCredentials(credentials.getIdentityDocument(), identitySslContext));
+ } catch (Throwable t) {
+ log.log(Level.WARNING, "Failed to update credentials: " + t.getMessage(), t);
+ }
}
void reportMetrics() {
try {
- Instant expirationTime = getExpirationTime(autoReloadingX509KeyManager.getCurrentCertificateWithKey().certificate());
+ Instant expirationTime = getExpirationTime(credentials);
Duration remainingLifetime = Duration.between(clock.instant(), expirationTime);
metric.set(CERTIFICATE_EXPIRY_METRIC_NAME, remainingLifetime.getSeconds(), null);
} catch (Throwable t) {