aboutsummaryrefslogtreecommitdiffstats
path: root/vespa-athenz/src
diff options
context:
space:
mode:
Diffstat (limited to 'vespa-athenz/src')
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/AccessTokenResponseEntity.java5
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identity/SiaIdentityProvider.java34
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapper.java41
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/LegacySignedIdentityDocument.java6
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/SignedIdentityDocument.java3
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/LegacySignedIdentityDocumentEntity.java58
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/SignedIdentityDocumentEntity.java6
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzCredentialsService.java156
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderProvider.java9
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSigner.java78
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/LegacyAthenzIdentityProviderImpl.java397
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/ServiceIdentityProviderProvider.java1
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/AthenzX509CertificateUtils.java10
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/SiaUtils.java6
-rw-r--r--vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identity/SiaIdentityProviderTest.java6
-rw-r--r--vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapperTest.java36
-rw-r--r--vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSignerTest.java55
-rw-r--r--vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/LegacyAthenzIdentityProviderImplTest.java160
-rw-r--r--vespa-athenz/src/test/java/com/yahoo/vespa/athenz/utils/SiaUtilsTest.java1
19 files changed, 37 insertions, 1031 deletions
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/AccessTokenResponseEntity.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/AccessTokenResponseEntity.java
index a3063524b93..785c215df18 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/AccessTokenResponseEntity.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/AccessTokenResponseEntity.java
@@ -9,6 +9,7 @@ import com.yahoo.vespa.athenz.api.AthenzRole;
import java.time.Instant;
import java.util.List;
+import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -19,6 +20,7 @@ import java.util.stream.Stream;
public class AccessTokenResponseEntity {
private final AthenzAccessToken accessToken;
private final Instant expiryTime;
+ // roles can be null (not set in the json response)
private final List<AthenzRole> roles;
public AccessTokenResponseEntity(
@@ -29,7 +31,8 @@ public class AccessTokenResponseEntity {
this.accessToken = new AthenzAccessToken(accessToken);
// We do not know from when, so best we can do is assume now ...
this.expiryTime = Instant.now().plusSeconds(expiresIn);
- this.roles = Stream.of(roles.split(" "))
+ this.roles = Optional.ofNullable(roles).stream()
+ .flatMap(r -> Stream.of(r.split(" ")))
.map(AthenzResourceName::fromString)
.map(AthenzRole::fromResourceName)
.toList();
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identity/SiaIdentityProvider.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identity/SiaIdentityProvider.java
index 2c8908a89a6..085e9973cab 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identity/SiaIdentityProvider.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identity/SiaIdentityProvider.java
@@ -42,28 +42,25 @@ public class SiaIdentityProvider extends AbstractComponent implements ServiceIde
this(new AthenzService(config.athenzDomain(), config.athenzService()),
SiaUtils.getPrivateKeyFile(Paths.get(config.keyPathPrefix()), new AthenzService(config.athenzDomain(), config.athenzService())),
SiaUtils.getCertificateFile(Paths.get(config.keyPathPrefix()), new AthenzService(config.athenzDomain(), config.athenzService())),
- Paths.get(config.trustStorePath()), config.publicSystem());
+ Paths.get(config.trustStorePath()));
}
public SiaIdentityProvider(AthenzIdentity service,
Path siaPath,
- Path clientTruststoreFile,
- boolean publicSystem) {
+ Path clientTruststoreFile) {
this(service,
SiaUtils.getPrivateKeyFile(siaPath, service),
SiaUtils.getCertificateFile(siaPath, service),
- clientTruststoreFile,
- publicSystem);
+ clientTruststoreFile);
}
public SiaIdentityProvider(AthenzIdentity service,
Path privateKeyFile,
Path certificateFile,
- Path clientTruststoreFile,
- boolean publicSystem) {
+ Path clientTruststoreFile) {
this.service = service;
this.keyManager = AutoReloadingX509KeyManager.fromPemFiles(privateKeyFile, certificateFile);
- this.sslContext = createIdentitySslContext(keyManager, clientTruststoreFile, publicSystem);
+ this.sslContext = createIdentitySslContext(keyManager, clientTruststoreFile);
this.certificateFile = certificateFile;
this.privateKeyFile = privateKeyFile;
}
@@ -83,26 +80,23 @@ public class SiaIdentityProvider extends AbstractComponent implements ServiceIde
@Override public Path privateKeyPath() { return privateKeyFile; }
public SSLContext createIdentitySslContextWithTrustStore(Path trustStoreFile) {
- return createIdentitySslContext(keyManager, trustStoreFile, false);
+ return createIdentitySslContext(keyManager, trustStoreFile);
}
/**
* Create an SSL context with the given trust store and the key manager from this provider.
- * If the {code includeDefaultTruststore} is true, the default trust store will be included.
+ * Include default trust store
*
* @param keyManager the key manager
* @param trustStoreFile the trust store file
- * @param includeDefaultTruststore whether to include the default trust store
*/
- private static SSLContext createIdentitySslContext(AutoReloadingX509KeyManager keyManager, Path trustStoreFile, boolean includeDefaultTruststore) {
- List<X509Certificate> defaultTrustStore = List.of();
- if (includeDefaultTruststore) {
- try {
- // load the default java trust store and extract the certificates
- defaultTrustStore = Stream.of(TrustManagerUtils.createDefaultX509TrustManager().getAcceptedIssuers()).toList();
- } catch (Exception e) {
- throw new RuntimeException("Failed to load default trust store", e);
- }
+ private static SSLContext createIdentitySslContext(AutoReloadingX509KeyManager keyManager, Path trustStoreFile) {
+ List<X509Certificate> defaultTrustStore;
+ try {
+ // load the default java trust store and extract the certificates
+ defaultTrustStore = Stream.of(TrustManagerUtils.createDefaultX509TrustManager().getAcceptedIssuers()).toList();
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to load default trust store", e);
}
try {
List<X509Certificate> caCertList = Stream.concat(
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapper.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapper.java
index 4bbdd24db32..ac620d2f6d4 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapper.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapper.java
@@ -4,11 +4,9 @@ package com.yahoo.vespa.athenz.identityprovider.api;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
-import com.yahoo.vespa.athenz.api.AthenzIdentity;
import com.yahoo.vespa.athenz.api.AthenzService;
import com.yahoo.vespa.athenz.identityprovider.api.bindings.DefaultSignedIdentityDocumentEntity;
import com.yahoo.vespa.athenz.identityprovider.api.bindings.IdentityDocumentEntity;
-import com.yahoo.vespa.athenz.identityprovider.api.bindings.LegacySignedIdentityDocumentEntity;
import com.yahoo.vespa.athenz.identityprovider.api.bindings.SignedIdentityDocumentEntity;
import com.yahoo.vespa.athenz.utils.AthenzIdentities;
import com.yahoo.yolean.Exceptions;
@@ -54,25 +52,7 @@ public class EntityBindingsMapper {
}
public static SignedIdentityDocument toSignedIdentityDocument(SignedIdentityDocumentEntity entity) {
- if (entity instanceof LegacySignedIdentityDocumentEntity docEntity) {
- IdentityDocument doc = new IdentityDocument(
- fromDottedString(docEntity.providerUniqueId()),
- new AthenzService(docEntity.providerService()),
- docEntity.configServerHostname(),
- docEntity.instanceHostname(),
- docEntity.createdAt(),
- docEntity.ipAddresses(),
- IdentityType.fromId(docEntity.identityType()),
- Optional.ofNullable(docEntity.clusterType()).map(ClusterType::from).orElse(null),
- docEntity.ztsUrl(),
- Optional.ofNullable(docEntity.serviceIdentity()).map(AthenzIdentities::from).orElse(null),
- docEntity.unknownAttributes());
- return new LegacySignedIdentityDocument(
- docEntity.signature(),
- docEntity.signingKeyVersion(),
- entity.documentVersion(),
- doc);
- } else if (entity instanceof DefaultSignedIdentityDocumentEntity docEntity) {
+ if (entity instanceof DefaultSignedIdentityDocumentEntity docEntity) {
return new DefaultSignedIdentityDocument(docEntity.signature(),
docEntity.signingKeyVersion(),
docEntity.documentVersion(),
@@ -83,24 +63,7 @@ public class EntityBindingsMapper {
}
public static SignedIdentityDocumentEntity toSignedIdentityDocumentEntity(SignedIdentityDocument model) {
- if (model instanceof LegacySignedIdentityDocument legacyModel) {
- IdentityDocument idDoc = legacyModel.identityDocument();
- return new LegacySignedIdentityDocumentEntity(
- legacyModel.signature(),
- legacyModel.signingKeyVersion(),
- idDoc.providerUniqueId().asDottedString(),
- idDoc.providerService().getFullName(),
- legacyModel.documentVersion(),
- idDoc.configServerHostname(),
- idDoc.instanceHostname(),
- idDoc.createdAt(),
- idDoc.ipAddresses(),
- idDoc.identityType().id(),
- Optional.ofNullable(idDoc.clusterType()).map(ClusterType::toConfigValue).orElse(null),
- idDoc.ztsUrl(),
- Optional.ofNullable(idDoc.serviceIdentity()).map(AthenzIdentity::getFullName).orElse(null),
- idDoc.unknownAttributes());
- } else if (model instanceof DefaultSignedIdentityDocument defaultModel){
+ if (model instanceof DefaultSignedIdentityDocument defaultModel){
return new DefaultSignedIdentityDocumentEntity(defaultModel.signature(),
defaultModel.signingKeyVersion(),
defaultModel.documentVersion(),
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/LegacySignedIdentityDocument.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/LegacySignedIdentityDocument.java
deleted file mode 100644
index dfab93b2a28..00000000000
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/LegacySignedIdentityDocument.java
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.athenz.identityprovider.api;
-
-public record LegacySignedIdentityDocument(String signature, int signingKeyVersion, int documentVersion,
- IdentityDocument identityDocument) implements SignedIdentityDocument {
-}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/SignedIdentityDocument.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/SignedIdentityDocument.java
index 8ab07d97e74..39629d878db 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/SignedIdentityDocument.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/SignedIdentityDocument.java
@@ -8,10 +8,9 @@ package com.yahoo.vespa.athenz.identityprovider.api;
*/
public interface SignedIdentityDocument {
- int LEGACY_DEFAULT_DOCUMENT_VERSION = 3;
int DEFAULT_DOCUMENT_VERSION = 4;
- default boolean outdated() { return documentVersion() < LEGACY_DEFAULT_DOCUMENT_VERSION; }
+ default boolean outdated() { return documentVersion() < DEFAULT_DOCUMENT_VERSION; }
IdentityDocument identityDocument();
String signature();
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/LegacySignedIdentityDocumentEntity.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/LegacySignedIdentityDocumentEntity.java
deleted file mode 100644
index 647ca474420..00000000000
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/LegacySignedIdentityDocumentEntity.java
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.athenz.identityprovider.api.bindings;
-
-import com.fasterxml.jackson.annotation.JsonAnyGetter;
-import com.fasterxml.jackson.annotation.JsonAnySetter;
-import com.fasterxml.jackson.annotation.JsonCreator;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-import java.net.URI;
-import java.time.Instant;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * @author bjorncs
- */
-@JsonInclude(JsonInclude.Include.NON_NULL)
-public record LegacySignedIdentityDocumentEntity (
- String signature, int signingKeyVersion, String providerUniqueId, String providerService, int documentVersion,
- String configServerHostname, String instanceHostname, Instant createdAt, Set<String> ipAddresses,
- String identityType, String clusterType, URI ztsUrl, String serviceIdentity, Map<String, Object> unknownAttributes) implements SignedIdentityDocumentEntity {
-
- @JsonCreator
- public LegacySignedIdentityDocumentEntity(@JsonProperty("signature") String signature,
- @JsonProperty("signing-key-version") int signingKeyVersion,
- @JsonProperty("provider-unique-id") String providerUniqueId,
- @JsonProperty("provider-service") String providerService,
- @JsonProperty("document-version") int documentVersion,
- @JsonProperty("configserver-hostname") String configServerHostname,
- @JsonProperty("instance-hostname") String instanceHostname,
- @JsonProperty("created-at") Instant createdAt,
- @JsonProperty("ip-addresses") Set<String> ipAddresses,
- @JsonProperty("identity-type") String identityType,
- @JsonProperty("cluster-type") String clusterType,
- @JsonProperty("zts-url") String ztsUrl,
- @JsonProperty("service-identity") String serviceIdentity) {
- this(signature, signingKeyVersion, providerUniqueId, providerService, documentVersion, configServerHostname,
- instanceHostname, createdAt, ipAddresses, identityType, clusterType, URI.create(ztsUrl), serviceIdentity, new HashMap<>());
- }
-
- @JsonProperty("signature") @Override public String signature() { return signature; }
- @JsonProperty("signing-key-version") @Override public int signingKeyVersion() { return signingKeyVersion; }
- @JsonProperty("provider-unique-id") @Override public String providerUniqueId() { return providerUniqueId; }
- @JsonProperty("provider-service") @Override public String providerService() { return providerService; }
- @JsonProperty("document-version") @Override public int documentVersion() { return documentVersion; }
- @JsonProperty("configserver-hostname") @Override public String configServerHostname() { return configServerHostname; }
- @JsonProperty("instance-hostname") @Override public String instanceHostname() { return instanceHostname; }
- @JsonProperty("created-at") @Override public Instant createdAt() { return createdAt; }
- @JsonProperty("ip-addresses") @Override public Set<String> ipAddresses() { return ipAddresses; }
- @JsonProperty("identity-type") @Override public String identityType() { return identityType; }
- @JsonProperty("cluster-type") @Override public String clusterType() { return clusterType; }
- @JsonProperty("zts-url") @Override public URI ztsUrl() { return ztsUrl; }
- @JsonProperty("service-identity") @Override public String serviceIdentity() { return serviceIdentity; }
- @JsonAnyGetter @Override public Map<String, Object> unknownAttributes() { return unknownAttributes; }
- @JsonAnySetter public void set(String name, Object value) { unknownAttributes.put(name, value); }
-}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/SignedIdentityDocumentEntity.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/SignedIdentityDocumentEntity.java
index c5c39fb6590..d909849e9ce 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/SignedIdentityDocumentEntity.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/SignedIdentityDocumentEntity.java
@@ -9,7 +9,6 @@ import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver;
import com.fasterxml.jackson.databind.jsontype.TypeIdResolver;
import com.fasterxml.jackson.databind.type.TypeFactory;
-import com.yahoo.vespa.athenz.identityprovider.api.SignedIdentityDocument;
import java.io.IOException;
import java.util.Objects;
@@ -55,10 +54,7 @@ class SignedIdentityDocumentEntityTypeResolver implements TypeIdResolver {
@Override
public JavaType typeFromId(DatabindContext databindContext, String s) throws IOException {
try {
- int version = Integer.parseInt(s);
- Class<? extends SignedIdentityDocumentEntity> cls = version <= SignedIdentityDocument.LEGACY_DEFAULT_DOCUMENT_VERSION
- ? LegacySignedIdentityDocumentEntity.class
- : DefaultSignedIdentityDocumentEntity.class;
+ Class<? extends SignedIdentityDocumentEntity> cls = DefaultSignedIdentityDocumentEntity.class;
return TypeFactory.defaultInstance().constructSpecializedType(javaType,cls);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Unable to deserialize document with version: \"%s\"".formatted(s));
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzCredentialsService.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzCredentialsService.java
deleted file mode 100644
index 63c966004e5..00000000000
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzCredentialsService.java
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.athenz.identityprovider.client;
-
-import com.yahoo.container.core.identity.IdentityConfig;
-import com.yahoo.security.KeyAlgorithm;
-import com.yahoo.security.KeyUtils;
-import com.yahoo.security.Pkcs10Csr;
-import com.yahoo.vespa.athenz.api.AthenzService;
-import com.yahoo.vespa.athenz.client.zts.DefaultZtsClient;
-import com.yahoo.vespa.athenz.client.zts.InstanceIdentity;
-import com.yahoo.vespa.athenz.client.zts.ZtsClient;
-import com.yahoo.vespa.athenz.identity.ServiceIdentityProvider;
-import com.yahoo.vespa.athenz.identityprovider.api.EntityBindingsMapper;
-import com.yahoo.vespa.athenz.identityprovider.api.IdentityDocument;
-import com.yahoo.vespa.athenz.identityprovider.api.IdentityDocumentClient;
-import com.yahoo.vespa.athenz.identityprovider.api.SignedIdentityDocument;
-import com.yahoo.vespa.athenz.tls.AthenzIdentityVerifier;
-import com.yahoo.vespa.athenz.utils.SiaUtils;
-import com.yahoo.vespa.defaults.Defaults;
-
-import javax.net.ssl.SSLContext;
-import java.net.URI;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.security.KeyPair;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-import java.time.Clock;
-import java.time.Duration;
-import java.util.Optional;
-
-import static java.util.Collections.singleton;
-
-/**
- * A service that provides method for initially registering the instance and refreshing it.
- *
- * @author bjorncs
- */
-class AthenzCredentialsService {
- private static final Duration EXPIRATION_MARGIN = Duration.ofDays(2);
- private static final Path VESPA_SIA_DIRECTORY = Paths.get(Defaults.getDefaults().underVespaHome("var/vespa/sia"));
- private static final Path IDENTITY_DOCUMENT_FILE = VESPA_SIA_DIRECTORY.resolve("vespa-tenant-identity-document.json");
-
- private final AthenzService tenantIdentity;
- private final URI configserverEndpoint;
- private final URI ztsEndpoint;
- private final AthenzService configserverIdentity;
- private final ServiceIdentityProvider nodeIdentityProvider;
- private final String hostname;
- private final CsrGenerator csrGenerator;
- private final Clock clock;
-
- AthenzCredentialsService(IdentityConfig identityConfig,
- ServiceIdentityProvider nodeIdentityProvider,
- String hostname,
- Clock clock) {
- this.tenantIdentity = new AthenzService(identityConfig.domain(), identityConfig.service());
- this.configserverEndpoint = URI.create("https://" + identityConfig.loadBalancerAddress() + ":4443");
- this.ztsEndpoint = URI.create(identityConfig.ztsUrl());
- this.configserverIdentity = new AthenzService(identityConfig.configserverIdentityName());
- this.nodeIdentityProvider = nodeIdentityProvider;
- this.hostname = hostname;
- this.csrGenerator = new CsrGenerator(identityConfig.athenzDnsSuffix(), identityConfig.configserverIdentityName());
- this.clock = clock;
- }
-
- Path certificatePath() { return SiaUtils.getCertificateFile(VESPA_SIA_DIRECTORY, tenantIdentity); }
- Path privateKeyPath() { return SiaUtils.getPrivateKeyFile(VESPA_SIA_DIRECTORY, tenantIdentity); }
-
- AthenzCredentials registerInstance() {
- Optional<AthenzCredentials> athenzCredentialsFromDisk = tryReadCredentialsFromDisk();
- if (athenzCredentialsFromDisk.isPresent()) {
- return athenzCredentialsFromDisk.get();
- }
- KeyPair keyPair = KeyUtils.generateKeypair(KeyAlgorithm.RSA);
- IdentityDocumentClient identityDocumentClient = createIdentityDocumentClient();
- // Use legacy version for now.
- SignedIdentityDocument signedDocument = identityDocumentClient.getTenantIdentityDocument(hostname, SignedIdentityDocument.LEGACY_DEFAULT_DOCUMENT_VERSION).orElseThrow();
- IdentityDocument document = signedDocument.identityDocument();
- Pkcs10Csr csr = csrGenerator.generateInstanceCsr(
- tenantIdentity,
- document.providerUniqueId(),
- document.ipAddresses(),
- document.clusterType(),
- keyPair);
-
- try (ZtsClient ztsClient = new DefaultZtsClient.Builder(ztsEndpoint).withIdentityProvider(nodeIdentityProvider).build()) {
- InstanceIdentity instanceIdentity =
- ztsClient.registerInstance(
- configserverIdentity,
- tenantIdentity,
- EntityBindingsMapper.toAttestationData(signedDocument),
- csr);
- X509Certificate certificate = instanceIdentity.certificate();
- writeCredentialsToDisk(keyPair.getPrivate(), certificate, signedDocument);
- return new AthenzCredentials(certificate, keyPair, signedDocument);
- }
- }
-
- AthenzCredentials updateCredentials(SignedIdentityDocument signedDocument, SSLContext sslContext) {
- KeyPair newKeyPair = KeyUtils.generateKeypair(KeyAlgorithm.RSA);
- IdentityDocument document = signedDocument.identityDocument();
- Pkcs10Csr csr = csrGenerator.generateInstanceCsr(
- tenantIdentity,
- document.providerUniqueId(),
- document.ipAddresses(),
- document.clusterType(),
- newKeyPair);
-
- try (ZtsClient ztsClient = new DefaultZtsClient.Builder(ztsEndpoint).withSslContext(sslContext).build()) {
- InstanceIdentity instanceIdentity =
- ztsClient.refreshInstance(
- configserverIdentity,
- tenantIdentity,
- document.providerUniqueId().asDottedString(),
- csr);
- X509Certificate certificate = instanceIdentity.certificate();
- writeCredentialsToDisk(newKeyPair.getPrivate(), certificate, signedDocument);
- return new AthenzCredentials(certificate, newKeyPair, signedDocument);
- }
- }
-
- private Optional<AthenzCredentials> tryReadCredentialsFromDisk() {
- Optional<PrivateKey> privateKey = SiaUtils.readPrivateKeyFile(VESPA_SIA_DIRECTORY, tenantIdentity);
- if (privateKey.isEmpty()) return Optional.empty();
- Optional<X509Certificate> certificate = SiaUtils.readCertificateFile(VESPA_SIA_DIRECTORY, tenantIdentity);
- if (certificate.isEmpty()) return Optional.empty();
- if (isExpired(certificate.get())) {
- return Optional.empty();
- }
- if (Files.notExists(IDENTITY_DOCUMENT_FILE)) return Optional.empty();
- SignedIdentityDocument signedIdentityDocument = EntityBindingsMapper.readSignedIdentityDocumentFromFile(IDENTITY_DOCUMENT_FILE);
- KeyPair keyPair = new KeyPair(KeyUtils.extractPublicKey(privateKey.get()), privateKey.get());
- return Optional.of(new AthenzCredentials(certificate.get(), keyPair, signedIdentityDocument));
- }
-
- private boolean isExpired(X509Certificate certificate) {
- return clock.instant().isAfter(certificate.getNotAfter().toInstant().minus(EXPIRATION_MARGIN));
- }
-
- private void writeCredentialsToDisk(PrivateKey privateKey,
- X509Certificate certificate,
- SignedIdentityDocument identityDocument) {
- SiaUtils.writePrivateKeyFile(VESPA_SIA_DIRECTORY, tenantIdentity, privateKey);
- SiaUtils.writeCertificateFile(VESPA_SIA_DIRECTORY, tenantIdentity, certificate);
- EntityBindingsMapper.writeSignedIdentityDocumentToFile(IDENTITY_DOCUMENT_FILE, identityDocument);
- }
-
- private DefaultIdentityDocumentClient createIdentityDocumentClient() {
- return new DefaultIdentityDocumentClient(
- configserverEndpoint,
- nodeIdentityProvider,
- new AthenzIdentityVerifier(singleton(configserverIdentity)));
- }
-}
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 30ae4fff59d..dec919cada0 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
@@ -7,24 +7,17 @@ import com.yahoo.container.jdisc.athenz.AthenzIdentityProvider;
import com.yahoo.jdisc.Metric;
import javax.inject.Inject;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
/**
* @author olaa
*/
public class AthenzIdentityProviderProvider implements Provider<AthenzIdentityProvider> {
- private final Path NODE_ADMIN_MANAGED_IDENTITY_DOCUMENT = Paths.get("/var/lib/sia/vespa-tenant-identity-document.json");
private final AthenzIdentityProvider athenzIdentityProvider;
@Inject
public AthenzIdentityProviderProvider(IdentityConfig config, Metric metric) {
- if (Files.exists(NODE_ADMIN_MANAGED_IDENTITY_DOCUMENT))
- athenzIdentityProvider = new AthenzIdentityProviderImpl(config, metric);
- else
- athenzIdentityProvider = new LegacyAthenzIdentityProviderImpl(config, metric);
+ athenzIdentityProvider = new AthenzIdentityProviderImpl(config, metric);
}
@Override
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSigner.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSigner.java
index fd2cefbc93e..43f32a3bae7 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSigner.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSigner.java
@@ -3,11 +3,9 @@ package com.yahoo.vespa.athenz.identityprovider.client;
import com.yahoo.security.SignatureUtils;
import com.yahoo.vespa.athenz.api.AthenzIdentity;
-import com.yahoo.vespa.athenz.api.AthenzService;
import com.yahoo.vespa.athenz.identityprovider.api.DefaultSignedIdentityDocument;
import com.yahoo.vespa.athenz.identityprovider.api.IdentityDocument;
import com.yahoo.vespa.athenz.identityprovider.api.IdentityType;
-import com.yahoo.vespa.athenz.identityprovider.api.LegacySignedIdentityDocument;
import com.yahoo.vespa.athenz.identityprovider.api.SignedIdentityDocument;
import com.yahoo.vespa.athenz.identityprovider.api.VespaUniqueInstanceId;
@@ -22,7 +20,6 @@ import java.util.Base64;
import java.util.Set;
import java.util.TreeSet;
-import static com.yahoo.vespa.athenz.identityprovider.api.SignedIdentityDocument.LEGACY_DEFAULT_DOCUMENT_VERSION;
import static java.nio.charset.StandardCharsets.UTF_8;
/**
@@ -44,39 +41,8 @@ public class IdentityDocumentSigner {
}
}
- public String generateLegacySignature(IdentityDocument doc, PrivateKey privateKey) {
- return generateSignature(doc.providerUniqueId(), doc.providerService(), doc.configServerHostname(),
- doc.instanceHostname(), doc.createdAt(), doc.ipAddresses(), doc.identityType(), privateKey, doc.serviceIdentity());
- }
-
- // Cluster type is ignored due to old Vespa versions not forwarding unknown fields in signed identity document
- private String generateSignature(VespaUniqueInstanceId providerUniqueId,
- AthenzIdentity providerService,
- String configServerHostname,
- String instanceHostname,
- Instant createdAt,
- Set<String> ipAddresses,
- IdentityType identityType,
- PrivateKey privateKey,
- AthenzIdentity serviceIdentity) {
- try {
- Signature signer = SignatureUtils.createSigner(privateKey);
- signer.initSign(privateKey);
- writeToSigner(
- signer, providerUniqueId, providerService, configServerHostname, instanceHostname, createdAt,
- ipAddresses, identityType);
- writeToSigner(signer, serviceIdentity);
- byte[] signature = signer.sign();
- return Base64.getEncoder().encodeToString(signature);
- } catch (GeneralSecurityException e) {
- throw new RuntimeException(e);
- }
- }
-
public boolean hasValidSignature(SignedIdentityDocument doc, PublicKey publicKey) {
- if (doc instanceof LegacySignedIdentityDocument signedDoc) {
- return validateLegacySignature(signedDoc, publicKey);
- } else if (doc instanceof DefaultSignedIdentityDocument signedDoc) {
+ if (doc instanceof DefaultSignedIdentityDocument signedDoc) {
try {
Signature signer = SignatureUtils.createVerifier(publicKey);
signer.initVerify(publicKey);
@@ -89,46 +55,4 @@ public class IdentityDocumentSigner {
throw new IllegalArgumentException("Unknown identity document type: " + doc.getClass().getName());
}
}
-
- private boolean validateLegacySignature(SignedIdentityDocument doc, PublicKey publicKey) {
- try {
- IdentityDocument iddoc = doc.identityDocument();
- Signature signer = SignatureUtils.createVerifier(publicKey);
- signer.initVerify(publicKey);
- writeToSigner(
- signer, iddoc.providerUniqueId(), iddoc.providerService(), iddoc.configServerHostname(),
- iddoc.instanceHostname(), iddoc.createdAt(), iddoc.ipAddresses(), iddoc.identityType());
- if (doc.documentVersion() >= LEGACY_DEFAULT_DOCUMENT_VERSION) {
- writeToSigner(signer, iddoc.serviceIdentity());
- }
- return signer.verify(Base64.getDecoder().decode(doc.signature()));
- } catch (GeneralSecurityException e) {
- throw new RuntimeException(e);
- }
- }
-
- private static void writeToSigner(Signature signer,
- VespaUniqueInstanceId providerUniqueId,
- AthenzIdentity providerService,
- String configServerHostname,
- String instanceHostname,
- Instant createdAt,
- Set<String> ipAddresses,
- IdentityType identityType) throws SignatureException {
- signer.update(providerUniqueId.asDottedString().getBytes(UTF_8));
- signer.update(providerService.getFullName().getBytes(UTF_8));
- signer.update(configServerHostname.getBytes(UTF_8));
- signer.update(instanceHostname.getBytes(UTF_8));
- ByteBuffer timestampAsBuffer = ByteBuffer.allocate(Long.BYTES);
- timestampAsBuffer.putLong(createdAt.toEpochMilli());
- signer.update(timestampAsBuffer.array());
- for (String ipAddress : new TreeSet<>(ipAddresses)) {
- signer.update(ipAddress.getBytes(UTF_8));
- }
- signer.update(identityType.id().getBytes(UTF_8));
- }
-
- private static void writeToSigner(Signature signer, AthenzIdentity serviceIdentity) throws SignatureException{
- signer.update(serviceIdentity.getFullName().getBytes(UTF_8));
- }
}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/LegacyAthenzIdentityProviderImpl.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/LegacyAthenzIdentityProviderImpl.java
deleted file mode 100644
index 34324ef18e6..00000000000
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/LegacyAthenzIdentityProviderImpl.java
+++ /dev/null
@@ -1,397 +0,0 @@
-// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.athenz.identityprovider.client;
-
-import ai.vespa.metrics.ContainerMetrics;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-import com.yahoo.component.AbstractComponent;
-import com.yahoo.component.annotation.Inject;
-import com.yahoo.container.core.identity.IdentityConfig;
-import com.yahoo.container.jdisc.athenz.AthenzIdentityProvider;
-import com.yahoo.container.jdisc.athenz.AthenzIdentityProviderException;
-import com.yahoo.jdisc.Metric;
-import com.yahoo.security.KeyStoreBuilder;
-import com.yahoo.security.MutableX509KeyManager;
-import com.yahoo.security.Pkcs10Csr;
-import com.yahoo.security.SslContextBuilder;
-import com.yahoo.security.X509CertificateWithKey;
-import com.yahoo.vespa.athenz.api.AthenzAccessToken;
-import com.yahoo.vespa.athenz.api.AthenzDomain;
-import com.yahoo.vespa.athenz.api.AthenzRole;
-import com.yahoo.vespa.athenz.api.AthenzService;
-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.utils.SiaUtils;
-import com.yahoo.vespa.defaults.Defaults;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.X509ExtendedKeyManager;
-import java.net.URI;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.security.PrivateKey;
-import java.security.cert.X509Certificate;
-import java.time.Clock;
-import java.time.Duration;
-import java.time.Instant;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Function;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import static com.yahoo.security.KeyStoreType.PKCS12;
-
-/**
- * A {@link AthenzIdentityProvider} / {@link ServiceIdentityProvider} component that provides the tenant identity.
- *
- * @author mortent
- * @author bjorncs
- */
-// 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 LegacyAthenzIdentityProviderImpl extends AbstractComponent implements AthenzIdentityProvider, ServiceIdentityProvider {
-
- 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
- private final static Duration ROLE_TOKEN_EXPIRY = Duration.ofMinutes(10);
-
- // 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 SSLContext identitySslContext;
- private final LoadingCache<AthenzRole, X509Certificate> roleSslCertCache;
- private final Map<AthenzRole, MutableX509KeyManager> roleKeyManagerCache;
- private final LoadingCache<AthenzRole, ZToken> roleSpecificRoleTokenCache;
- private final LoadingCache<AthenzDomain, ZToken> domainSpecificRoleTokenCache;
- private final LoadingCache<AthenzDomain, AthenzAccessToken> domainSpecificAccessTokenCache;
- private final LoadingCache<List<AthenzRole>, AthenzAccessToken> roleSpecificAccessTokenCache;
- private final CsrGenerator csrGenerator;
-
- @Inject
- 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
- 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());
- 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.identitySslContext = createIdentitySslContext(identityKeyManager, trustStore);
- registerInstance();
- }
-
- private static <KEY, VALUE> LoadingCache<KEY, VALUE> createCache(Duration expiry, Function<KEY, VALUE> cacheLoader) {
- return CacheBuilder.newBuilder()
- .refreshAfterWrite(expiry.dividedBy(2).toMinutes(), TimeUnit.MINUTES)
- .expireAfterWrite(expiry.toMinutes(), TimeUnit.MINUTES)
- .build(new CacheLoader<KEY, VALUE>() {
- @Override
- public VALUE load(KEY key) {
- return cacheLoader.apply(key);
- }
- });
- }
-
- private static <KEY, VALUE> LoadingCache<KEY, VALUE> crateAutoReloadableCache(Duration expiry, Function<KEY, VALUE> cacheLoader, ScheduledExecutorService scheduler) {
- LoadingCache<KEY, VALUE> cache = createCache(expiry, cacheLoader);
-
- // The cache above will reload it's contents if and only if a request for the key is made. Scheduling
- // a cache reloader to reload all keys in this cache.
- scheduler.scheduleAtFixedRate(() -> { cache.asMap().keySet().forEach(cache::getUnchecked);},
- expiry.dividedBy(4).toMinutes(),
- expiry.dividedBy(4).toMinutes(),
- TimeUnit.MINUTES);
- return cache;
- }
-
- private static SSLContext createIdentitySslContext(X509ExtendedKeyManager keyManager, Path trustStore) {
- return new SslContextBuilder()
- .withKeyManager(keyManager)
- .withTrustStore(trustStore)
- .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;
- }
-
- @Override
- public String domain() {
- return identity.getDomain().getName();
- }
-
- @Override
- public String service() {
- return identity.getName();
- }
-
- @Override
- public SSLContext getIdentitySslContext() {
- return identitySslContext;
- }
-
- @Override
- public X509CertificateWithKey getIdentityCertificateWithKey() {
- AthenzCredentials copy = this.credentials;
- return new X509CertificateWithKey(copy.getCertificate(), copy.getKeyPair().getPrivate());
- }
-
- @Override public Path certificatePath() { return athenzCredentialsService.certificatePath(); }
-
- @Override public Path privateKeyPath() { return athenzCredentialsService.privateKeyPath(); }
-
- @Override
- public SSLContext getRoleSslContext(String domain, String role) {
- try {
- AthenzRole athenzRole = new AthenzRole(new AthenzDomain(domain), role);
- // Make sure to request a certificate which triggers creating a new key manager for this role
- X509Certificate x509Certificate = getRoleCertificate(athenzRole);
- MutableX509KeyManager keyManager = roleKeyManagerCache.get(athenzRole);
- return new SslContextBuilder()
- .withKeyManager(keyManager)
- .withTrustStore(trustStore)
- .build();
- } catch (Exception e) {
- throw new AthenzIdentityProviderException("Could not retrieve role certificate: " + e.getMessage(), e);
- }
- }
-
- @Override
- public String getRoleToken(String domain) {
- try {
- return domainSpecificRoleTokenCache.get(new AthenzDomain(domain)).getRawToken();
- } catch (Exception e) {
- throw new AthenzIdentityProviderException("Could not retrieve role token: " + e.getMessage(), e);
- }
- }
-
- @Override
- public String getRoleToken(String domain, String role) {
- try {
- return roleSpecificRoleTokenCache.get(new AthenzRole(domain, role)).getRawToken();
- } catch (Exception e) {
- throw new AthenzIdentityProviderException("Could not retrieve role token: " + e.getMessage(), e);
- }
- }
-
- @Override
- public String getAccessToken(String domain) {
- try {
- return domainSpecificAccessTokenCache.get(new AthenzDomain(domain)).value();
- } catch (Exception e) {
- throw new AthenzIdentityProviderException("Could not retrieve access token: " + e.getMessage(), e);
- }
- }
-
- @Override
- public String getAccessToken(String domain, List<String> roles) {
- try {
- List<AthenzRole> roleList = roles.stream()
- .map(roleName -> new AthenzRole(domain, roleName))
- .toList();
- return roleSpecificAccessTokenCache.get(roleList).value();
- } catch (Exception e) {
- throw new AthenzIdentityProviderException("Could not retrieve access token: " + e.getMessage(), e);
- }
- }
-
- @Override
- public String getAccessToken(String domain, List<String> roles, List<String> proxyPrincipal) {
- throw new UnsupportedOperationException("Not implemented in legacy client");
- }
-
- @Override
- public PrivateKey getPrivateKey() {
- return credentials.getKeyPair().getPrivate();
- }
-
- @Override
- public Path trustStorePath() {
- return trustStore;
- }
-
- @Override
- public List<X509Certificate> getIdentityCertificate() {
- return List.of(credentials.getCertificate());
- }
-
- @Override
- public X509Certificate getRoleCertificate(String domain, String role) {
- return getRoleCertificate(new AthenzRole(new AthenzDomain(domain), role));
- }
-
- private X509Certificate getRoleCertificate(AthenzRole athenzRole) {
- try {
- return roleSslCertCache.get(athenzRole);
- } catch (Exception e) {
- throw new AthenzIdentityProviderException("Could not retrieve role certificate: " + e.getMessage(), e);
- }
- }
-
- 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().identityDocument();
- Pkcs10Csr csr = csrGenerator.generateRoleCsr(
- identity, role, doc.providerUniqueId(), doc.clusterType(), credentials.getKeyPair());
- try (ZtsClient client = createZtsClient()) {
- X509Certificate roleCertificate = client.getRoleCertificate(role, csr);
- updateRoleKeyManager(role, roleCertificate);
- log.info(String.format("Requester role certificate for role %s, expires: %s", role.toResourceNameString(), roleCertificate.getNotAfter().toInstant().toString()));
- return roleCertificate;
- }
- }
-
- private void updateRoleKeyManager(AthenzRole role, X509Certificate certificate) {
- MutableX509KeyManager keyManager = roleKeyManagerCache.computeIfAbsent(role, r -> new MutableX509KeyManager());
- keyManager.updateKeystore(
- KeyStoreBuilder.withType(PKCS12)
- .withKeyEntry("default", credentials.getKeyPair().getPrivate(), certificate)
- .build(),
- new char[0]);
- }
-
- private ZToken createRoleToken(AthenzRole athenzRole) {
- try (ZtsClient client = createZtsClient()) {
- return client.getRoleToken(athenzRole, ROLE_TOKEN_EXPIRY);
- }
- }
-
- private ZToken createRoleToken(AthenzDomain domain) {
- try (ZtsClient client = createZtsClient()) {
- return client.getRoleToken(domain, ROLE_TOKEN_EXPIRY);
- }
- }
-
- private AthenzAccessToken createAccessToken(AthenzDomain domain) {
- try (ZtsClient client = createZtsClient()) {
- return client.getAccessToken(domain);
- }
- }
-
- private AthenzAccessToken createAccessToken(List<AthenzRole> roles) {
- try (ZtsClient client = createZtsClient()) {
- return client.getAccessToken(roles);
- }
- }
-
- private DefaultZtsClient createZtsClient() {
- return new DefaultZtsClient.Builder(ztsEndpoint).withSslContext(getIdentitySslContext()).build();
- }
-
- @Override
- public void deconstruct() {
- try {
- scheduler.shutdownNow();
- scheduler.awaitTermination(AWAIT_TERMINTATION_TIMEOUT.getSeconds(), TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
-
- private static SiaIdentityProvider createNodeIdentityProvider(IdentityConfig config) {
- return new SiaIdentityProvider(
- new AthenzService(config.nodeIdentityName()), SiaUtils.DEFAULT_SIA_DIRECTORY, CLIENT_TRUST_STORE, false);
- }
-
- 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(credentials);
- Duration remainingLifetime = Duration.between(clock.instant(), expirationTime);
- Metric.Context dimensions = metric.createContext(Map.of("implementation", this.getClassName()));
- metric.set(CERTIFICATE_EXPIRY_METRIC_NAME, remainingLifetime.getSeconds(), dimensions);
- } catch (Throwable t) {
- log.log(Level.WARNING, "Failed to update metrics: " + t.getMessage(), t);
- }
- }
-}
-
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/ServiceIdentityProviderProvider.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/ServiceIdentityProviderProvider.java
index d0267d406ce..5dd49206c6d 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/ServiceIdentityProviderProvider.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/ServiceIdentityProviderProvider.java
@@ -22,7 +22,6 @@ public class ServiceIdentityProviderProvider implements Provider<ServiceIdentity
@Override
public ServiceIdentityProvider get() {
if (athenzIdentityProvider instanceof AthenzIdentityProviderImpl impl) return impl;
- if (athenzIdentityProvider instanceof LegacyAthenzIdentityProviderImpl legacyImpl) return legacyImpl;
return null;
}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/AthenzX509CertificateUtils.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/AthenzX509CertificateUtils.java
index cc4711c2056..f3cebd5256e 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/AthenzX509CertificateUtils.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/tls/AthenzX509CertificateUtils.java
@@ -68,12 +68,16 @@ public class AthenzX509CertificateUtils {
/** @return Athenz unique instance id from the Subject Alternative Name extension */
public static Optional<String> getInstanceId(List<SubjectAlternativeName> sans) {
// Prefer instance id from SAN URI over the legacy DNS entry
- return getAthenzUniqueInstanceIdFromSanUri(sans)
+ return getLastSegmentFromSanUri(sans, "athenz://instanceid/")
.or(() -> getAthenzUniqueInstanceIdFromSanDns(sans));
}
- private static Optional<String> getAthenzUniqueInstanceIdFromSanUri(List<SubjectAlternativeName> sans) {
- String uriPrefix = "athenz://instanceid/";
+ /** @return Athenz unique instance name from the Subject Alternative Name extension */
+ public static Optional<String> getInstanceName(List<SubjectAlternativeName> sans) {
+ return getLastSegmentFromSanUri(sans, "athenz://instancename/");
+ }
+
+ private static Optional<String> getLastSegmentFromSanUri(List<SubjectAlternativeName> sans, String uriPrefix) {
return sans.stream()
.filter(san -> {
if (san.getType() != Type.URI) return false;
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/SiaUtils.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/SiaUtils.java
index af0da93edc3..56e64b2261d 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/SiaUtils.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/SiaUtils.java
@@ -1,10 +1,10 @@
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.athenz.utils;
-import com.yahoo.vespa.athenz.api.AthenzIdentity;
-import com.yahoo.vespa.athenz.api.AthenzService;
import com.yahoo.security.KeyUtils;
import com.yahoo.security.X509CertificateUtils;
+import com.yahoo.vespa.athenz.api.AthenzIdentity;
+import com.yahoo.vespa.athenz.api.AthenzService;
import java.io.IOException;
import java.io.UncheckedIOException;
@@ -132,7 +132,7 @@ public class SiaUtils {
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(keysDirectory)) {
return StreamSupport.stream(directoryStream.spliterator(), false)
.map(path -> path.getFileName().toString())
- .filter(fileName -> fileName.endsWith(keyFileSuffix))
+ .filter(fileName -> fileName.endsWith(keyFileSuffix) && ! fileName.contains(":role."))
.map(fileName -> fileName.substring(0, fileName.length() - keyFileSuffix.length()))
.map(AthenzService::new)
.collect(toList());
diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identity/SiaIdentityProviderTest.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identity/SiaIdentityProviderTest.java
index 19a81691b76..5ca6a53a4c7 100644
--- a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identity/SiaIdentityProviderTest.java
+++ b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identity/SiaIdentityProviderTest.java
@@ -49,8 +49,7 @@ public class SiaIdentityProviderTest {
new AthenzService("domain", "service-name"),
keyFile.toPath(),
certificateFile.toPath(),
- trustStoreFile.toPath(),
- false);
+ trustStoreFile.toPath());
assertNotNull(provider.getIdentitySslContext());
}
@@ -73,8 +72,7 @@ public class SiaIdentityProviderTest {
new AthenzService("domain", "service-name"),
keyFile.toPath(),
certificateFile.toPath(),
- trustStoreFile.toPath(),
- false);
+ trustStoreFile.toPath());
assertNotNull(provider.getIdentitySslContext());
}
diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapperTest.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapperTest.java
index 297f0c904d9..377aee22ab1 100644
--- a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapperTest.java
+++ b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapperTest.java
@@ -7,12 +7,8 @@ import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
-import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertInstanceOf;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* @author bjorncs
@@ -20,38 +16,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
class EntityBindingsMapperTest {
@Test
- public void legacy_persists_unknown_json_members() throws IOException {
- var originalJson =
- """
- {
- "signature": "sig",
- "signing-key-version": 0,
- "provider-unique-id": "0.cluster.instance.app.tenant.us-west-1.test.node",
- "provider-service": "domain.service",
- "document-version": 2,
- "configserver-hostname": "cfg",
- "instance-hostname": "host",
- "created-at": 12345.0,
- "ip-addresses": [],
- "identity-type": "node",
- "cluster-type": "admin",
- "zts-url": "https://zts.url/",
- "unknown-string": "string-value",
- "unknown-object": { "member-in-unknown-object": 123 }
- }
- """;
- var entity = EntityBindingsMapper.fromString(originalJson);
- assertInstanceOf(LegacySignedIdentityDocument.class, entity);
- assertEquals(2, entity.identityDocument().unknownAttributes().size(), entity.identityDocument().unknownAttributes().toString());
- var json = EntityBindingsMapper.toAttestationData(entity);
-
- var expectedMemberInJson = "member-in-unknown-object";
- assertTrue(json.contains(expectedMemberInJson),
- () -> "Expected JSON to contain '%s', but got \n'%s'".formatted(expectedMemberInJson, json));
- assertEquals(EntityBindingsMapper.mapper.readTree(originalJson), EntityBindingsMapper.mapper.readTree(json));
- }
-
- @Test
public void reads_unknown_json_members() throws IOException {
var iddoc = """
{
diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSignerTest.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSignerTest.java
index 2532a394f4e..3845d9db5b2 100644
--- a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSignerTest.java
+++ b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSignerTest.java
@@ -10,7 +10,6 @@ import com.yahoo.vespa.athenz.identityprovider.api.DefaultSignedIdentityDocument
import com.yahoo.vespa.athenz.identityprovider.api.EntityBindingsMapper;
import com.yahoo.vespa.athenz.identityprovider.api.IdentityDocument;
import com.yahoo.vespa.athenz.identityprovider.api.IdentityType;
-import com.yahoo.vespa.athenz.identityprovider.api.LegacySignedIdentityDocument;
import com.yahoo.vespa.athenz.identityprovider.api.SignedIdentityDocument;
import com.yahoo.vespa.athenz.identityprovider.api.VespaUniqueInstanceId;
import org.junit.jupiter.api.Test;
@@ -23,8 +22,6 @@ import java.util.List;
import static com.yahoo.vespa.athenz.identityprovider.api.IdentityType.TENANT;
import static com.yahoo.vespa.athenz.identityprovider.api.SignedIdentityDocument.DEFAULT_DOCUMENT_VERSION;
-import static com.yahoo.vespa.athenz.identityprovider.api.SignedIdentityDocument.LEGACY_DEFAULT_DOCUMENT_VERSION;
-import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
@@ -47,21 +44,6 @@ public class IdentityDocumentSignerTest {
private static final AthenzIdentity serviceIdentity = new AthenzService("vespa", "node");
@Test
- void legacy_generates_and_validates_signature() {
- IdentityDocumentSigner signer = new IdentityDocumentSigner();
- IdentityDocument identityDocument = new IdentityDocument(
- id, providerService, configserverHostname,
- instanceHostname, createdAt, ipAddresses, identityType, clusterType, ztsUrl, serviceIdentity);
- String signature =
- signer.generateLegacySignature(identityDocument, keyPair.getPrivate());
-
- SignedIdentityDocument signedIdentityDocument = new LegacySignedIdentityDocument(
- signature, KEY_VERSION, LEGACY_DEFAULT_DOCUMENT_VERSION, identityDocument);
-
- assertTrue(signer.hasValidSignature(signedIdentityDocument, keyPair.getPublic()));
- }
-
- @Test
void generates_and_validates_signature() {
IdentityDocumentSigner signer = new IdentityDocumentSigner();
IdentityDocument identityDocument = new IdentityDocument(
@@ -76,41 +58,4 @@ public class IdentityDocumentSignerTest {
assertTrue(signer.hasValidSignature(signedIdentityDocument, keyPair.getPublic()));
}
-
- @Test
- void legacy_ignores_cluster_type_and_zts_url() {
- IdentityDocumentSigner signer = new IdentityDocumentSigner();
- IdentityDocument identityDocument = new IdentityDocument(
- id, providerService, configserverHostname,
- instanceHostname, createdAt, ipAddresses, identityType, clusterType, ztsUrl, serviceIdentity);
- IdentityDocument withoutIgnoredFields = new IdentityDocument(
- id, providerService, configserverHostname,
- instanceHostname, createdAt, ipAddresses, identityType, null, null, serviceIdentity);
-
- String signature =
- signer.generateLegacySignature(identityDocument, keyPair.getPrivate());
-
- var docWithoutIgnoredFields = new LegacySignedIdentityDocument(
- signature, KEY_VERSION, LEGACY_DEFAULT_DOCUMENT_VERSION, withoutIgnoredFields);
- var docWithIgnoredFields = new LegacySignedIdentityDocument(
- signature, KEY_VERSION, LEGACY_DEFAULT_DOCUMENT_VERSION, identityDocument);
-
- assertTrue(signer.hasValidSignature(docWithoutIgnoredFields, keyPair.getPublic()));
- assertEquals(docWithIgnoredFields.signature(), docWithoutIgnoredFields.signature());
- }
-
- @Test
- void validates_signature_for_new_and_old_versions() {
- IdentityDocumentSigner signer = new IdentityDocumentSigner();
- IdentityDocument identityDocument = new IdentityDocument(
- id, providerService, configserverHostname,
- instanceHostname, createdAt, ipAddresses, identityType, clusterType, ztsUrl, serviceIdentity);
- String signature =
- signer.generateLegacySignature(identityDocument, keyPair.getPrivate());
-
- SignedIdentityDocument signedIdentityDocument = new LegacySignedIdentityDocument(
- signature, KEY_VERSION, LEGACY_DEFAULT_DOCUMENT_VERSION, identityDocument);
-
- assertTrue(signer.hasValidSignature(signedIdentityDocument, keyPair.getPublic()));
- }
}
diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/LegacyAthenzIdentityProviderImplTest.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/LegacyAthenzIdentityProviderImplTest.java
deleted file mode 100644
index 90853ff7cfa..00000000000
--- a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/LegacyAthenzIdentityProviderImplTest.java
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.athenz.identityprovider.client;
-
-import com.yahoo.container.core.identity.IdentityConfig;
-import com.yahoo.container.jdisc.athenz.AthenzIdentityProviderException;
-import com.yahoo.jdisc.Metric;
-import com.yahoo.security.KeyAlgorithm;
-import com.yahoo.security.KeyStoreBuilder;
-import com.yahoo.security.KeyStoreType;
-import com.yahoo.security.KeyStoreUtils;
-import com.yahoo.security.KeyUtils;
-import com.yahoo.security.Pkcs10Csr;
-import com.yahoo.security.Pkcs10CsrBuilder;
-import com.yahoo.security.SignatureAlgorithm;
-import com.yahoo.security.X509CertificateBuilder;
-import com.yahoo.test.ManualClock;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.io.TempDir;
-
-import javax.security.auth.x500.X500Principal;
-
-import java.io.File;
-import java.io.IOException;
-import java.math.BigInteger;
-import java.nio.file.Path;
-import java.security.KeyPair;
-import java.security.cert.X509Certificate;
-import java.time.Duration;
-import java.time.Instant;
-import java.time.temporal.ChronoUnit;
-import java.util.Date;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.function.Supplier;
-
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-/**
- * @author mortent
- * @author bjorncs
- */
-public class LegacyAthenzIdentityProviderImplTest {
-
- @TempDir
- public File tempDir;
-
- public static final Duration certificateValidity = Duration.ofDays(30);
-
- private static final IdentityConfig IDENTITY_CONFIG =
- new IdentityConfig(new IdentityConfig.Builder()
- .service("tenantService")
- .domain("tenantDomain")
- .nodeIdentityName("vespa.tenant")
- .configserverIdentityName("vespa.configserver")
- .loadBalancerAddress("cfg")
- .ztsUrl("https:localhost:4443/zts/v1")
- .athenzDnsSuffix("dev-us-north-1.vespa.cloud"));
-
- private final KeyPair caKeypair = KeyUtils.generateKeypair(KeyAlgorithm.EC);
- private Path trustStoreFile;
- private X509Certificate caCertificate;
-
- @BeforeEach
- public void createTrustStoreFile() throws IOException {
- caCertificate = X509CertificateBuilder
- .fromKeypair(
- caKeypair,
- new X500Principal("CN=mydummyca"),
- Instant.EPOCH,
- Instant.EPOCH.plus(10000, ChronoUnit.DAYS),
- SignatureAlgorithm.SHA256_WITH_ECDSA,
- BigInteger.ONE)
- .build();
- trustStoreFile = File.createTempFile("junit", null, tempDir).toPath();
- KeyStoreUtils.writeKeyStoreToFile(
- KeyStoreBuilder.withType(KeyStoreType.JKS)
- .withKeyEntry("default", caKeypair.getPrivate(), caCertificate)
- .build(),
- trustStoreFile);
- }
-
- @Test
- void component_creation_fails_when_credentials_not_found() {
- assertThrows(AthenzIdentityProviderException.class, () -> {
- AthenzCredentialsService credentialService = mock(AthenzCredentialsService.class);
- when(credentialService.registerInstance())
- .thenThrow(new RuntimeException("athenz unavailable"));
-
- new LegacyAthenzIdentityProviderImpl(IDENTITY_CONFIG, mock(Metric.class), trustStoreFile, credentialService, mock(ScheduledExecutorService.class), new ManualClock(Instant.EPOCH));
- });
- }
-
- @Test
- void metrics_updated_on_refresh() {
- ManualClock clock = new ManualClock(Instant.EPOCH);
- Metric metric = mock(Metric.class);
-
- AthenzCredentialsService athenzCredentialsService = mock(AthenzCredentialsService.class);
-
- KeyPair keyPair = KeyUtils.generateKeypair(KeyAlgorithm.EC);
- X509Certificate certificate = getCertificate(keyPair, getExpirationSupplier(clock));
-
- when(athenzCredentialsService.registerInstance())
- .thenReturn(new AthenzCredentials(certificate, keyPair, null));
-
- when(athenzCredentialsService.updateCredentials(any(), any()))
- .thenThrow(new RuntimeException("#1"))
- .thenThrow(new RuntimeException("#2"))
- .thenReturn(new AthenzCredentials(certificate, keyPair, null));
-
- LegacyAthenzIdentityProviderImpl identityProvider =
- new LegacyAthenzIdentityProviderImpl(IDENTITY_CONFIG, metric, trustStoreFile, athenzCredentialsService, mock(ScheduledExecutorService.class), clock);
-
- identityProvider.reportMetrics();
- verify(metric).set(eq(LegacyAthenzIdentityProviderImpl.CERTIFICATE_EXPIRY_METRIC_NAME), eq(certificateValidity.getSeconds()), any());
-
- // Advance 1 day, refresh fails, cert is 1 day old
- clock.advance(Duration.ofDays(1));
- identityProvider.refreshCertificate();
- identityProvider.reportMetrics();
- verify(metric).set(eq(LegacyAthenzIdentityProviderImpl.CERTIFICATE_EXPIRY_METRIC_NAME), eq(certificateValidity.minus(Duration.ofDays(1)).getSeconds()), any());
-
- // Advance 1 more day, refresh fails, cert is 2 days old
- clock.advance(Duration.ofDays(1));
- identityProvider.refreshCertificate();
- identityProvider.reportMetrics();
- verify(metric).set(eq(LegacyAthenzIdentityProviderImpl.CERTIFICATE_EXPIRY_METRIC_NAME), eq(certificateValidity.minus(Duration.ofDays(2)).getSeconds()), any());
-
- // Advance 1 more day, refresh succeds, cert is new
- clock.advance(Duration.ofDays(1));
- identityProvider.refreshCertificate();
- identityProvider.reportMetrics();
- verify(metric).set(eq(LegacyAthenzIdentityProviderImpl.CERTIFICATE_EXPIRY_METRIC_NAME), eq(certificateValidity.getSeconds()), any());
-
- }
-
- private Supplier<Date> getExpirationSupplier(ManualClock clock) {
- return () -> new Date(clock.instant().plus(certificateValidity).toEpochMilli());
- }
-
- private X509Certificate getCertificate(KeyPair keyPair, Supplier<Date> expiry) {
- Pkcs10Csr csr = Pkcs10CsrBuilder.fromKeypair(new X500Principal("CN=dummy"), keyPair, SignatureAlgorithm.SHA256_WITH_ECDSA)
- .build();
- return X509CertificateBuilder
- .fromCsr(csr,
- caCertificate.getSubjectX500Principal(),
- Instant.EPOCH,
- expiry.get().toInstant(),
- caKeypair.getPrivate(),
- SignatureAlgorithm.SHA256_WITH_ECDSA,
- BigInteger.ONE)
- .build();
- }
-
-}
diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/utils/SiaUtilsTest.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/utils/SiaUtilsTest.java
index 9ff59236c0c..8274fe7f7a6 100644
--- a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/utils/SiaUtilsTest.java
+++ b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/utils/SiaUtilsTest.java
@@ -32,6 +32,7 @@ public class SiaUtilsTest {
Files.createFile(SiaUtils.getPrivateKeyFile(siaRoot, fooService));
AthenzService barService = new AthenzService("my.domain.bar");
Files.createFile(SiaUtils.getPrivateKeyFile(siaRoot, barService));
+ Files.createFile(siaRoot.resolve("keys/my.domain.foo:role.my-role.key.pem"));
List<AthenzIdentity> siaIdentities = SiaUtils.findSiaServices(siaRoot);
assertEquals(2, siaIdentities.size());