summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/IdentityDocumentGenerator.java29
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/InstanceValidator.java64
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/ca/restapi/CertificateAuthorityApiHandler.java2
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/ca/restapi/InstanceSerializer.java5
-rw-r--r--athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/IdentityDocumentGeneratorTest.java4
-rw-r--r--athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/InstanceValidatorTest.java84
-rw-r--r--athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/ca/restapi/ContainerTester.java2
-rw-r--r--athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/ca/restapi/InstanceSerializerTest.java4
-rw-r--r--athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/ca/restapi/mock/InstanceValidatorMock.java2
-rw-r--r--configdefinitions/src/vespa/athenz-provider-service.def5
-rw-r--r--flags/src/main/java/com/yahoo/vespa/flags/Flags.java7
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java26
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapper.java2
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/SignedIdentityDocument.java7
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/SignedIdentityDocumentEntity.java8
-rw-r--r--vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapperTest.java1
-rw-r--r--vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/IdentityDocumentSignerTest.java17
17 files changed, 204 insertions, 65 deletions
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/IdentityDocumentGenerator.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/IdentityDocumentGenerator.java
index 5143a38b2c1..5138bee1ff6 100644
--- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/IdentityDocumentGenerator.java
+++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/IdentityDocumentGenerator.java
@@ -3,7 +3,10 @@ package com.yahoo.vespa.hosted.athenz.instanceproviderservice;
import com.yahoo.component.annotation.Inject;
import com.yahoo.config.provision.Zone;
+import com.yahoo.container.jdisc.secretstore.SecretStore;
import com.yahoo.net.HostName;
+import com.yahoo.security.KeyUtils;
+
import com.yahoo.vespa.athenz.api.AthenzService;
import com.yahoo.vespa.athenz.identityprovider.api.ClusterType;
import com.yahoo.vespa.athenz.identityprovider.api.IdentityType;
@@ -32,17 +35,20 @@ public class IdentityDocumentGenerator {
private final NodeRepository nodeRepository;
private final Zone zone;
private final KeyProvider keyProvider;
+ private final SecretStore secretStore;
private final AthenzProviderServiceConfig athenzProviderServiceConfig;
@Inject
public IdentityDocumentGenerator(AthenzProviderServiceConfig config,
NodeRepository nodeRepository,
Zone zone,
- KeyProvider keyProvider) {
+ KeyProvider keyProvider,
+ SecretStore secretStore) {
this.athenzProviderServiceConfig = config;
this.nodeRepository = nodeRepository;
this.zone = zone;
this.keyProvider = keyProvider;
+ this.secretStore = secretStore;
}
public SignedIdentityDocument generateSignedIdentityDocument(String hostname, IdentityType identityType) {
@@ -61,7 +67,7 @@ public class IdentityDocumentGenerator {
Set<String> ips = new HashSet<>(node.ipConfig().primary());
- PrivateKey privateKey = keyProvider.getPrivateKey(athenzProviderServiceConfig.secretVersion());
+ PrivateKey privateKey = privateKey(node);
AthenzService providerService = new AthenzService(athenzProviderServiceConfig.domain(), athenzProviderServiceConfig.serviceName());
String configServerHostname = HostName.getLocalhost();
@@ -73,11 +79,28 @@ public class IdentityDocumentGenerator {
return new SignedIdentityDocument(
signature, athenzProviderServiceConfig.secretVersion(), providerUniqueId, providerService,
SignedIdentityDocument.DEFAULT_DOCUMENT_VERSION, configServerHostname, node.hostname(),
- createdAt, ips, identityType, clusterType);
+ createdAt, ips, identityType, clusterType, ztsUrl(node));
} catch (Exception e) {
throw new RuntimeException("Exception generating identity document: " + e.getMessage(), e);
}
}
+ private PrivateKey privateKey(Node node) {
+ // return sisSecret for public non-enclave hosts. secret otherwise
+ if (zone.system().isPublic() && !node.cloudAccount().isEnclave(zone)) {
+ String keyPem = secretStore.getSecret(athenzProviderServiceConfig.sisSecretName(), athenzProviderServiceConfig.sisSecretVersion());
+ return KeyUtils.fromPemEncodedPrivateKey(keyPem);
+ } else {
+ return keyProvider.getPrivateKey(athenzProviderServiceConfig.secretVersion());
+ }
+ }
+ private String ztsUrl(Node node) {
+ // return sisUrl for public non-enclave hosts, ztsUrl otherwise
+ if (zone.system().isPublic() && !node.cloudAccount().isEnclave(zone)) {
+ return athenzProviderServiceConfig.sisUrl();
+ } else {
+ return athenzProviderServiceConfig.ztsUrl();
+ }
+ }
}
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/InstanceValidator.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/InstanceValidator.java
index d8bbf743d8c..a349bddc76b 100644
--- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/InstanceValidator.java
+++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/InstanceValidator.java
@@ -7,6 +7,9 @@ import com.yahoo.config.model.api.ApplicationInfo;
import com.yahoo.config.model.api.ServiceInfo;
import com.yahoo.config.model.api.SuperModelProvider;
import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.Zone;
+import com.yahoo.container.jdisc.secretstore.SecretStore;
+import com.yahoo.security.KeyUtils;
import com.yahoo.vespa.athenz.api.AthenzService;
import com.yahoo.vespa.athenz.identityprovider.api.ClusterType;
import com.yahoo.vespa.athenz.identityprovider.api.EntityBindingsMapper;
@@ -52,25 +55,32 @@ public class InstanceValidator {
private final KeyProvider keyProvider;
private final SuperModelProvider superModelProvider;
private final NodeRepository nodeRepository;
+ private final SecretStore secretStore;
+ private final String sisSecretName;
@Inject
public InstanceValidator(KeyProvider keyProvider,
SuperModelProvider superModelProvider,
NodeRepository nodeRepository,
- AthenzProviderServiceConfig config) {
- this(keyProvider, superModelProvider, nodeRepository, new IdentityDocumentSigner(), new AthenzService(config.tenantService()));
+ AthenzProviderServiceConfig config,
+ SecretStore secretStore) {
+ this(keyProvider, superModelProvider, nodeRepository, new IdentityDocumentSigner(), new AthenzService(config.tenantService()), secretStore, config.sisSecretName());
}
public InstanceValidator(KeyProvider keyProvider,
SuperModelProvider superModelProvider,
NodeRepository nodeRepository,
IdentityDocumentSigner identityDocumentSigner,
- AthenzService tenantIdentity){
+ AthenzService tenantIdentity,
+ SecretStore secretStore,
+ String sisSecretName) {
this.keyProvider = keyProvider;
this.superModelProvider = superModelProvider;
this.nodeRepository = nodeRepository;
this.signer = identityDocumentSigner;
this.tenantDockerContainerIdentity = tenantIdentity;
+ this.secretStore = secretStore;
+ this.sisSecretName = sisSecretName;
}
public boolean isValidInstance(InstanceConfirmation instanceConfirmation) {
@@ -102,16 +112,30 @@ public class InstanceValidator {
log.log(Level.FINE, () -> String.format("Validating instance %s.", providerUniqueId));
- PublicKey publicKey = keyProvider.getPublicKey(signedIdentityDocument.signingKeyVersion());
+ // Find node matching vespa unique id
+ Node node = getNode(providerUniqueId);
+
+ PublicKey publicKey = publicKey(node, signedIdentityDocument.signingKeyVersion());
if (! signer.hasValidSignature(signedIdentityDocument, publicKey)) {
var msg = String.format("Instance %s has invalid signature.", providerUniqueId);
throw new ValidationException(Level.SEVERE, () -> msg);
}
- validateAttributes(req, providerUniqueId);
+ validateAttributes(node, req, providerUniqueId);
log.log(Level.FINE, () -> String.format("Instance %s is valid.", providerUniqueId));
}
+ private PublicKey publicKey(Node node, int version) {
+ // return sisSecret for public non-enclave hosts.
+ Zone zone = nodeRepository.zone();
+ if (zone.system().isPublic() && !node.cloudAccount().isEnclave(zone)) {
+ String keyPem = secretStore.getSecret(sisSecretName, version);
+ return KeyUtils.extractPublicKey(KeyUtils.fromPemEncodedPrivateKey(keyPem));
+ } else {
+ return keyProvider.getPublicKey(version);
+ }
+ }
+
// TODO Add actual validation. Cannot reuse isValidInstance as identity document is not part of the refresh request.
// We'll have to perform some validation on the instance id and other fields of the attribute map.
// Separate between tenant and node certificate as well.
@@ -121,7 +145,8 @@ public class InstanceValidator {
confirmation.provider,
confirmation.attributes.get(SAN_DNS_ATTRNAME)));
try {
- validateAttributes(confirmation, getVespaUniqueInstanceId(confirmation));
+ VespaUniqueInstanceId vespaUniqueInstanceId = getVespaUniqueInstanceId(confirmation);
+ validateAttributes(getNode(vespaUniqueInstanceId), confirmation, vespaUniqueInstanceId);
return true;
} catch (ValidationException e) {
log.log(e.logLevel(), e.messageSupplier());
@@ -146,24 +171,13 @@ public class InstanceValidator {
.orElse(null);
}
- private void validateAttributes(InstanceConfirmation confirmation, VespaUniqueInstanceId vespaUniqueInstanceId)
+ private void validateAttributes(Node node, InstanceConfirmation confirmation, VespaUniqueInstanceId vespaUniqueInstanceId)
throws ValidationException {
if(vespaUniqueInstanceId == null) {
var msg = "Unable to find unique instance ID in refresh request: " + confirmation.toString();
throw new ValidationException(Level.WARNING, () -> msg);
}
- // Find node matching vespa unique id
- Node node = nodeRepository.nodes().list().stream()
- .filter(n -> n.allocation().isPresent())
- .filter(n -> nodeMatchesVespaUniqueId(n, vespaUniqueInstanceId))
- .findFirst() // Should be only one
- .orElse(null);
- if(node == null) {
- var msg = "Invalid InstanceConfirmation, No nodes matching uniqueId: " + vespaUniqueInstanceId;
- throw new ValidationException(Level.WARNING, () -> msg);
- }
-
// Find list of ipaddresses
List<InetAddress> ips = Optional.ofNullable(confirmation.attributes.get(SAN_IPS_ATTRNAME))
.map(s -> s.split(","))
@@ -199,6 +213,20 @@ public class InstanceValidator {
}
}
+ private Node getNode(VespaUniqueInstanceId vespaUniqueInstanceId) throws ValidationException {
+ // Find node matching vespa unique id
+ Node node = nodeRepository.nodes().list().stream()
+ .filter(n -> n.allocation().isPresent())
+ .filter(n -> nodeMatchesVespaUniqueId(n, vespaUniqueInstanceId))
+ .findFirst() // Should be only one
+ .orElse(null);
+ if(node == null) {
+ var msg = "Invalid InstanceConfirmation, No nodes matching uniqueId: " + vespaUniqueInstanceId;
+ throw new ValidationException(Level.WARNING, () -> msg);
+ }
+ return node;
+ }
+
private boolean nodeMatchesVespaUniqueId(Node node, VespaUniqueInstanceId vespaUniqueInstanceId) {
return node.allocation().map(allocation ->
allocation.membership().index() == vespaUniqueInstanceId.clusterIndex() &&
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/ca/restapi/CertificateAuthorityApiHandler.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/ca/restapi/CertificateAuthorityApiHandler.java
index 531a815922b..231f22ac56b 100644
--- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/ca/restapi/CertificateAuthorityApiHandler.java
+++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/ca/restapi/CertificateAuthorityApiHandler.java
@@ -65,7 +65,7 @@ public class CertificateAuthorityApiHandler extends ThreadedHttpRequestHandler {
super(ctx);
this.secretStore = secretStore;
this.certificates = certificates;
- this.caPrivateKeySecretName = athenzProviderServiceConfig.secretName();
+ this.caPrivateKeySecretName = athenzProviderServiceConfig.sisSecretName();
this.caCertificateSecretName = athenzProviderServiceConfig.caCertSecretName();
this.instanceValidator = instanceValidator;
}
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/ca/restapi/InstanceSerializer.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/ca/restapi/InstanceSerializer.java
index fec03afab69..8c575a6403b 100644
--- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/ca/restapi/InstanceSerializer.java
+++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/ca/restapi/InstanceSerializer.java
@@ -49,6 +49,7 @@ public class InstanceSerializer {
private static final String IDD_IPADDRESSES_FIELD = "ip-addresses";
private static final String IDD_IDENTITY_TYPE_FIELD = "identity-type";
private static final String IDD_CLUSTER_TYPE_FIELD = "cluster-type";
+ private static final String IDD_ZTS_URL_FIELD = "zts-url";
private static final ObjectMapper objectMapper = new ObjectMapper();
static {
@@ -100,10 +101,12 @@ public class InstanceSerializer {
IdentityType identityType = IdentityType.fromId(requireField(IDD_IDENTITY_TYPE_FIELD, root).asString());
var clusterTypeField = root.field(IDD_CLUSTER_TYPE_FIELD);
var clusterType = clusterTypeField.valid() ? ClusterType.from(clusterTypeField.asString()) : null;
+ var ztsUrlField = root.field(IDD_ZTS_URL_FIELD);
+ var ztsUrl = ztsUrlField.valid() ? ztsUrlField.asString() : "";
return new SignedIdentityDocument(signature, (int)signingKeyVersion, providerUniqueId, athenzService, (int)documentVersion,
- configserverHostname, instanceHostname, createdAt, ips, identityType, clusterType);
+ configserverHostname, instanceHostname, createdAt, ips, identityType, clusterType, ztsUrl);
}
private static Instant getJsr310Instant(double v) {
diff --git a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/IdentityDocumentGeneratorTest.java b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/IdentityDocumentGeneratorTest.java
index 9205baff0fc..340be33c2a3 100644
--- a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/IdentityDocumentGeneratorTest.java
+++ b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/IdentityDocumentGeneratorTest.java
@@ -18,6 +18,7 @@ import com.yahoo.vespa.athenz.identityprovider.api.SignedIdentityDocument;
import com.yahoo.vespa.athenz.identityprovider.api.VespaUniqueInstanceId;
import com.yahoo.vespa.athenz.identityprovider.client.IdentityDocumentSigner;
import com.yahoo.vespa.hosted.athenz.instanceproviderservice.config.AthenzProviderServiceConfig;
+import com.yahoo.vespa.hosted.ca.restapi.mock.SecretStoreMock;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.node.Allocation;
@@ -74,11 +75,12 @@ public class IdentityDocumentGeneratorTest {
when(nodes.node(eq(parentHostname))).thenReturn(Optional.of(parentNode));
when(nodes.node(eq(containerHostname))).thenReturn(Optional.of(containerNode));
AutoGeneratedKeyProvider keyProvider = new AutoGeneratedKeyProvider();
+ SecretStoreMock secretStore = new SecretStoreMock();
String dnsSuffix = "vespa.dns.suffix";
AthenzProviderServiceConfig config = getAthenzProviderConfig("domain", "service", dnsSuffix);
IdentityDocumentGenerator identityDocumentGenerator =
- new IdentityDocumentGenerator(config, nodeRepository, ZONE, keyProvider);
+ new IdentityDocumentGenerator(config, nodeRepository, ZONE, keyProvider, secretStore);
SignedIdentityDocument signedIdentityDocument = identityDocumentGenerator.generateSignedIdentityDocument(containerHostname, IdentityType.TENANT);
// Verify attributes
diff --git a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/InstanceValidatorTest.java b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/InstanceValidatorTest.java
index a7947aff283..42d6b92dea1 100644
--- a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/InstanceValidatorTest.java
+++ b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/InstanceValidatorTest.java
@@ -9,9 +9,16 @@ import com.yahoo.config.model.api.ServiceInfo;
import com.yahoo.config.model.api.SuperModel;
import com.yahoo.config.model.api.SuperModelProvider;
import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.ClusterMembership;
+import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.NodeType;
+import com.yahoo.config.provision.RegionName;
+import com.yahoo.config.provision.SystemName;
+import com.yahoo.config.provision.Zone;
+import com.yahoo.security.KeyAlgorithm;
+import com.yahoo.security.KeyUtils;
import com.yahoo.vespa.athenz.api.AthenzService;
import com.yahoo.vespa.athenz.identityprovider.api.ClusterType;
import com.yahoo.vespa.athenz.identityprovider.api.EntityBindingsMapper;
@@ -19,15 +26,19 @@ import com.yahoo.vespa.athenz.identityprovider.api.IdentityType;
import com.yahoo.vespa.athenz.identityprovider.api.SignedIdentityDocument;
import com.yahoo.vespa.athenz.identityprovider.api.VespaUniqueInstanceId;
import com.yahoo.vespa.athenz.identityprovider.client.IdentityDocumentSigner;
+import com.yahoo.vespa.curator.mock.MockCurator;
import com.yahoo.vespa.hosted.athenz.instanceproviderservice.InstanceValidator.ValidationException;
+import com.yahoo.vespa.hosted.ca.restapi.mock.SecretStoreMock;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.node.IP;
import com.yahoo.vespa.hosted.provision.node.Nodes;
import com.yahoo.vespa.hosted.provision.testutils.MockNodeFlavors;
+import com.yahoo.vespa.hosted.provision.testutils.MockNodeRepository;
import org.junit.jupiter.api.Test;
+import java.security.PrivateKey;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
@@ -64,11 +75,13 @@ public class InstanceValidatorTest {
private final AthenzService vespaTenantDomain = new AthenzService("vespa.vespa.tenant");
private final AutoGeneratedKeyProvider keyProvider = new AutoGeneratedKeyProvider();
+ private final SecretStoreMock secretStore = new SecretStoreMock();
+ private final String sisSecretName = "sis-secret-name";
@Test
void application_does_not_exist() {
SuperModelProvider superModelProvider = mockSuperModelProvider();
- InstanceValidator instanceValidator = new InstanceValidator(null, superModelProvider, null, null, vespaTenantDomain);
+ InstanceValidator instanceValidator = new InstanceValidator(null, superModelProvider, null, null, vespaTenantDomain, secretStore, sisSecretName);
assertFalse(instanceValidator.isValidInstance(createRegisterInstanceConfirmation(applicationId, domain, service)));
}
@@ -76,7 +89,7 @@ public class InstanceValidatorTest {
void application_does_not_have_domain_set() {
SuperModelProvider superModelProvider = mockSuperModelProvider(
mockApplicationInfo(applicationId, 5, Collections.emptyList()));
- InstanceValidator instanceValidator = new InstanceValidator(null, superModelProvider, null, new IdentityDocumentSigner(), vespaTenantDomain);
+ InstanceValidator instanceValidator = new InstanceValidator(null, superModelProvider, null, new IdentityDocumentSigner(), vespaTenantDomain, secretStore, sisSecretName);
assertFalse(instanceValidator.isValidInstance(createRegisterInstanceConfirmation(applicationId, domain, service)));
}
@@ -88,7 +101,7 @@ public class InstanceValidatorTest {
SuperModelProvider superModelProvider = mockSuperModelProvider(
mockApplicationInfo(applicationId, 5, Collections.singletonList(serviceInfo)));
- InstanceValidator instanceValidator = new InstanceValidator(null, superModelProvider, null, null, vespaTenantDomain);
+ InstanceValidator instanceValidator = new InstanceValidator(null, superModelProvider, null, null, vespaTenantDomain, secretStore, sisSecretName);
assertFalse(instanceValidator.isValidInstance(createRegisterInstanceConfirmation(applicationId, domain, service)));
}
@@ -106,7 +119,7 @@ public class InstanceValidatorTest {
mockApplicationInfo(applicationId, 5, Collections.singletonList(serviceInfo)));
IdentityDocumentSigner signer = mock(IdentityDocumentSigner.class);
when(signer.hasValidSignature(any(), any())).thenReturn(true);
- InstanceValidator instanceValidator = new InstanceValidator(mock(KeyProvider.class), superModelProvider, mockNodeRepo(), signer, vespaTenantDomain);
+ InstanceValidator instanceValidator = new InstanceValidator(mock(KeyProvider.class), superModelProvider, mockNodeRepo(), signer, vespaTenantDomain, secretStore, sisSecretName);
assertTrue(instanceValidator.isValidInstance(createRegisterInstanceConfirmation(applicationId, domain, service)));
}
@@ -114,7 +127,7 @@ public class InstanceValidatorTest {
@Test
void rejects_invalid_provider_unique_id_in_csr() {
SuperModelProvider superModelProvider = mockSuperModelProvider();
- InstanceValidator instanceValidator = new InstanceValidator(null, superModelProvider, null, null, vespaTenantDomain);
+ InstanceValidator instanceValidator = new InstanceValidator(null, superModelProvider, null, null, vespaTenantDomain, secretStore, sisSecretName);
InstanceConfirmation instanceConfirmation = createRegisterInstanceConfirmation(applicationId, domain, service);
VespaUniqueInstanceId tamperedId = new VespaUniqueInstanceId(0, "default", "instance", "app", "tenant", "us-north-1", "dev", IdentityType.NODE);
instanceConfirmation.set("sanDNS", tamperedId.asDottedString() + ".instanceid.athenz.dev-us-north-1.vespa.yahoo.cloud");
@@ -124,7 +137,7 @@ public class InstanceValidatorTest {
@Test
void rejects_unknown_ips_in_csr() {
NodeRepository nodeRepository = mockNodeRepo();
- InstanceValidator instanceValidator = new InstanceValidator(null, mockSuperModelProvider(), nodeRepository, null, vespaTenantDomain);
+ InstanceValidator instanceValidator = new InstanceValidator(null, mockSuperModelProvider(), nodeRepository, null, vespaTenantDomain, secretStore, sisSecretName);
InstanceConfirmation instanceConfirmation = createRegisterInstanceConfirmation(applicationId, domain, service);
Set<String> nodeIp = nodeRepository.nodes().list().owner(applicationId).stream().findFirst()
.map(Node::ipConfig)
@@ -142,7 +155,7 @@ public class InstanceValidatorTest {
var props = Map.of(SERVICE_PROPERTIES_DOMAIN_KEY, domain, SERVICE_PROPERTIES_SERVICE_KEY, service);
var info = new ServiceInfo("serviceName", "type", List.of(), props, "confId", "hostName");
var provider = mockSuperModelProvider(mockApplicationInfo(applicationId, 5, List.of(info)));
- var instanceValidator = new InstanceValidator(keyProvider, provider, mockNodeRepo(), new IdentityDocumentSigner(), vespaTenantDomain);
+ var instanceValidator = new InstanceValidator(keyProvider, provider, mockNodeRepo(), new IdentityDocumentSigner(), vespaTenantDomain, secretStore, sisSecretName);
var instanceConfirmation = createRegisterInstanceConfirmation(applicationId, domain, service);
instanceConfirmation.set("sanURI", "vespa://cluster-type/content");
var exception = assertThrows(ValidationException.class, () -> instanceValidator.validateInstance(instanceConfirmation));
@@ -155,7 +168,7 @@ public class InstanceValidatorTest {
NodeRepository nodeRepository = mock(NodeRepository.class);
Nodes nodes = mock(Nodes.class);
when(nodeRepository.nodes()).thenReturn(nodes);
- InstanceValidator instanceValidator = new InstanceValidator(null, null, nodeRepository, new IdentityDocumentSigner(), vespaTenantDomain);
+ InstanceValidator instanceValidator = new InstanceValidator(null, null, nodeRepository, new IdentityDocumentSigner(), vespaTenantDomain, secretStore, sisSecretName);
List<Node> nodeList = createNodes(10);
Node node = nodeList.get(0);
@@ -170,7 +183,7 @@ public class InstanceValidatorTest {
@Test
void rejects_refresh_on_ip_mismatch() {
NodeRepository nodeRepository = mockNodeRepo();
- InstanceValidator instanceValidator = new InstanceValidator(null, null, nodeRepository, new IdentityDocumentSigner(), vespaTenantDomain);
+ InstanceValidator instanceValidator = new InstanceValidator(null, null, nodeRepository, new IdentityDocumentSigner(), vespaTenantDomain, secretStore, sisSecretName);
Set<String> nodeIp = nodeRepository.nodes().list().owner(applicationId).stream().findFirst()
.map(Node::ipConfig)
@@ -191,7 +204,7 @@ public class InstanceValidatorTest {
Nodes nodes = mock(Nodes.class);
when(nodeRepository.nodes()).thenReturn(nodes);
- InstanceValidator instanceValidator = new InstanceValidator(null, null, nodeRepository, new IdentityDocumentSigner(), vespaTenantDomain);
+ InstanceValidator instanceValidator = new InstanceValidator(null, null, nodeRepository, new IdentityDocumentSigner(), vespaTenantDomain, secretStore, sisSecretName);
List<Node> nodeList = createNodes(10);
@@ -202,11 +215,40 @@ public class InstanceValidatorTest {
}
+ @Test
+ public void uses_correct_keys_in_public() throws ValidationException {
+ var sisKeyPair = KeyUtils.generateKeypair(KeyAlgorithm.RSA, 2048);
+ secretStore.setSecret(sisSecretName, KeyUtils.toPem(sisKeyPair.getPrivate()));
+
+ var props = Map.of(SERVICE_PROPERTIES_DOMAIN_KEY, domain, SERVICE_PROPERTIES_SERVICE_KEY, service);
+ var info = new ServiceInfo("serviceName", "type", List.of(), props, "confId", "hostName");
+ var provider = mockSuperModelProvider(mockApplicationInfo(applicationId, 5, List.of(info)));
+
+ {
+ // non Enclave hosts in public should use the SIS key
+ var nonEnclaveHosts = createNodes(10, Optional.empty());
+ var instanceValidator = new InstanceValidator(keyProvider, provider, mockNodeRepo(nonEnclaveHosts, SystemName.PublicCd), new IdentityDocumentSigner(), vespaTenantDomain, secretStore, sisSecretName);
+ var instanceConfirmation = createRegisterInstanceConfirmation(applicationId, domain, service, sisKeyPair.getPrivate());
+ instanceValidator.validateInstance(instanceConfirmation);
+ }
+ {
+ // Enclave hosts should use the Vespa provider key
+ var enclaveHosts = createNodes(10, Optional.of(CloudAccount.from("123456789012")));
+ var instanceValidator = new InstanceValidator(keyProvider, provider, mockNodeRepo(enclaveHosts, SystemName.PublicCd), new IdentityDocumentSigner(), vespaTenantDomain, secretStore, sisSecretName);
+ var instanceConfirmation = createRegisterInstanceConfirmation(applicationId, domain, service, keyProvider.getPrivateKey(0));
+ instanceValidator.validateInstance(instanceConfirmation);
+ }
+ }
+
private NodeRepository mockNodeRepo() {
+ return mockNodeRepo(createNodes(10), SystemName.cd);
+ }
+
+ private NodeRepository mockNodeRepo(List<Node> nodeList, SystemName systemName) {
NodeRepository nodeRepository = mock(NodeRepository.class);
Nodes nodes = mock(Nodes.class);
when(nodeRepository.nodes()).thenReturn(nodes);
- List<Node> nodeList = createNodes(10);
+ when(nodeRepository.zone()).thenReturn(new Zone(systemName, Environment.dev, RegionName.from("us-north-1")));
Node node = nodeList.get(0);
nodeList = allocateNode(nodeList, node, applicationId);
when(nodes.list()).thenReturn(NodeList.copyOf(nodeList));
@@ -215,6 +257,11 @@ public class InstanceValidatorTest {
private InstanceConfirmation createRegisterInstanceConfirmation(
ApplicationId applicationId, String domain, String service) {
+ return createRegisterInstanceConfirmation(applicationId, domain, service, keyProvider.getPrivateKey(0));
+ }
+
+ private InstanceConfirmation createRegisterInstanceConfirmation(
+ ApplicationId applicationId, String domain, String service, PrivateKey signingKey) {
VespaUniqueInstanceId vespaUniqueInstanceId = new VespaUniqueInstanceId(0, "default", applicationId.instance().value(), applicationId.application().value(), applicationId.tenant().value(), "us-north-1", "dev", IdentityType.NODE);
var domainService = new AthenzService(domain, service);
var clock = Instant.now();
@@ -222,11 +269,12 @@ public class InstanceValidatorTest {
var signature = new IdentityDocumentSigner()
.generateSignature(
vespaUniqueInstanceId, domainService, "localhost", "localhost", clock, Set.of(),
- IdentityType.NODE, keyProvider.getPrivateKey(0));
+ IdentityType.NODE, signingKey);
SignedIdentityDocument signedIdentityDocument = new SignedIdentityDocument(
signature, 0, vespaUniqueInstanceId, domainService, 0, "localhost", "localhost",
- clock, Collections.emptySet(), IdentityType.NODE, clusterType);
+ clock, Collections.emptySet(), IdentityType.NODE, clusterType, "https://zts.url");
return createInstanceConfirmation(vespaUniqueInstanceId, domain, service, signedIdentityDocument);
+
}
private InstanceConfirmation createRefreshInstanceConfirmation(ApplicationId applicationId, String domain, String service, List<String> ips) {
@@ -275,11 +323,17 @@ public class InstanceValidatorTest {
}
private List<Node> createNodes(int num) {
+ return createNodes(num, Optional.empty());
+ }
+
+ private List<Node> createNodes(int num, Optional<CloudAccount> cloudAccount) {
MockNodeFlavors flavors = new MockNodeFlavors();
List<Node> nodeList = new ArrayList<>();
for (int i = 0; i < num; i++) {
- Node node = Node.create("foo" + i, new IP.Config(Set.of("::1" + i, "::2" + i, "::3" + i), Set.of()),
- "foo" + i, flavors.getFlavorOrThrow("default"), NodeType.tenant).build();
+ Node.Builder builder = Node.create("foo" + i, new IP.Config(Set.of("::1" + i, "::2" + i, "::3" + i), Set.of()),
+ "foo" + i, flavors.getFlavorOrThrow("default"), NodeType.tenant);
+ cloudAccount.ifPresent(builder::cloudAccount);
+ Node node = builder.build();
nodeList.add(node);
}
return nodeList;
diff --git a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/ca/restapi/ContainerTester.java b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/ca/restapi/ContainerTester.java
index 8112f5779e5..d880fd5220b 100644
--- a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/ca/restapi/ContainerTester.java
+++ b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/ca/restapi/ContainerTester.java
@@ -64,6 +64,8 @@ public class ContainerTester {
" <serviceName>servicename</serviceName>\n" +
" <secretName>secretname</secretName>\n" +
" <secretVersion>0</secretVersion>\n" +
+ " <sisSecretName>secretname</sisSecretName>\n" +
+ " <sisSecretVersion>0</sisSecretVersion>\n" +
" <caCertSecretName>vespa.external.ca.cert</caCertSecretName>\n" +
" <certDnsSuffix>suffix</certDnsSuffix>\n" +
" <ztsUrl>https://localhost:123/</ztsUrl>\n" +
diff --git a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/ca/restapi/InstanceSerializerTest.java b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/ca/restapi/InstanceSerializerTest.java
index ca624918beb..02398b19627 100644
--- a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/ca/restapi/InstanceSerializerTest.java
+++ b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/ca/restapi/InstanceSerializerTest.java
@@ -1,6 +1,7 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.ca.restapi;
+import com.yahoo.config.provision.Cloud;
import com.yahoo.security.Pkcs10CsrUtils;
import com.yahoo.security.X509CertificateUtils;
import com.yahoo.slime.Slime;
@@ -48,7 +49,8 @@ public class InstanceSerializerTest {
Instant.now().truncatedTo(ChronoUnit.MICROS), // Truncate to the precision given from EntityBindingsMapper.toAttestationData()
Collections.emptySet(),
IdentityType.NODE,
- ClusterType.CONTAINER);
+ ClusterType.CONTAINER,
+ "https://zts.url");
var json = String.format("{\n" +
" \"provider\": \"provider_prod_us-north-1\",\n" +
diff --git a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/ca/restapi/mock/InstanceValidatorMock.java b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/ca/restapi/mock/InstanceValidatorMock.java
index 4151c1f15d7..163db3e107e 100644
--- a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/ca/restapi/mock/InstanceValidatorMock.java
+++ b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/ca/restapi/mock/InstanceValidatorMock.java
@@ -10,7 +10,7 @@ import com.yahoo.vespa.hosted.athenz.instanceproviderservice.InstanceValidator;
public class InstanceValidatorMock extends InstanceValidator {
public InstanceValidatorMock() {
- super(null, null, null, null, null);
+ super(null, null, null, null, null, null,"");
}
@Override
diff --git a/configdefinitions/src/vespa/athenz-provider-service.def b/configdefinitions/src/vespa/athenz-provider-service.def
index 2131aa88d30..4c9c74f9b8f 100644
--- a/configdefinitions/src/vespa/athenz-provider-service.def
+++ b/configdefinitions/src/vespa/athenz-provider-service.def
@@ -13,6 +13,11 @@ secretName string
# Secret version
secretVersion int
+# Tempory resources
+sisSecretName string default=""
+sisSecretVersion int default=0
+sisUrl string default = ""
+
# Secret name of CA certificate
caCertSecretName string
diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
index 3989b45b9ac..9b4b04a3d62 100644
--- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
+++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java
@@ -345,6 +345,13 @@ public class Flags {
"Takes effect on the next tick.",
ZONE_ID, NODE_TYPE, HOSTNAME);
+ public static final UnboundBooleanFlag VESPA_ATHENZ_PROVIDER = defineFeatureFlag(
+ "vespa-athenz-provider", false,
+ List.of("mortent"), "2023-02-22", "2023-05-01",
+ "Enable athenz provider in public systems",
+ "Takes effect on next config server container start",
+ ZONE_ID);
+
/** WARNING: public for testing: All flags should be defined in {@link Flags}. */
public static UnboundBooleanFlag defineFeatureFlag(String flagId, boolean defaultValue, List<String> owners,
String createdAt, String expiresAt, String description,
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java
index fc49dcc744c..6bd7d98e207 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java
@@ -41,6 +41,7 @@ import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
@@ -189,11 +190,9 @@ public class AthenzCredentialsMaintainer implements CredentialsMaintainer {
Pkcs10Csr csr = csrGenerator.generateInstanceCsr(
context.identity(), doc.providerUniqueId(), doc.ipAddresses(), doc.clusterType(), keyPair);
- // Set up a hostname verified for zts if this is configured to use the config server (internal zts) apis
- HostnameVerifier ztsHostNameVerifier = useInternalZts
- ? new AthenzIdentityVerifier(Set.of(configserverIdentity))
- : null;
- try (ZtsClient ztsClient = new DefaultZtsClient.Builder(ztsEndpoint).withIdentityProvider(hostIdentityProvider).withHostnameVerifier(ztsHostNameVerifier).build()) {
+ // Allow all zts hosts while removing SIS
+ HostnameVerifier ztsHostNameVerifier = (hostname, sslSession) -> true;
+ try (ZtsClient ztsClient = new DefaultZtsClient.Builder(ztsEndpoint(doc)).withIdentityProvider(hostIdentityProvider).withHostnameVerifier(ztsHostNameVerifier).build()) {
InstanceIdentity instanceIdentity =
ztsClient.registerInstance(
configserverIdentity,
@@ -206,6 +205,15 @@ public class AthenzCredentialsMaintainer implements CredentialsMaintainer {
}
}
+ /**
+ * Return zts url from identity document, fallback to ztsEndpoint
+ */
+ private URI ztsEndpoint(SignedIdentityDocument doc) {
+ return Optional.ofNullable(doc.ztsUrl())
+ .filter(s -> !s.isBlank())
+ .map(URI::create)
+ .orElse(ztsEndpoint);
+ }
private void refreshIdentity(NodeAgentContext context, ContainerPath privateKeyFile, ContainerPath certificateFile,
ContainerPath identityDocumentFile, SignedIdentityDocument doc) {
KeyPair keyPair = KeyUtils.generateKeypair(KeyAlgorithm.RSA);
@@ -217,11 +225,9 @@ public class AthenzCredentialsMaintainer implements CredentialsMaintainer {
.build();
try {
- // Set up a hostname verified for zts if this is configured to use the config server (internal zts) apis
- HostnameVerifier ztsHostNameVerifier = useInternalZts
- ? new AthenzIdentityVerifier(Set.of(configserverIdentity))
- : null;
- try (ZtsClient ztsClient = new DefaultZtsClient.Builder(ztsEndpoint).withSslContext(containerIdentitySslContext).withHostnameVerifier(ztsHostNameVerifier).build()) {
+ // Allow all zts hosts while removing SIS
+ HostnameVerifier ztsHostNameVerifier = (hostname, sslSession) -> true;
+ try (ZtsClient ztsClient = new DefaultZtsClient.Builder(ztsEndpoint(doc)).withSslContext(containerIdentitySslContext).withHostnameVerifier(ztsHostNameVerifier).build()) {
InstanceIdentity instanceIdentity =
ztsClient.refreshInstance(
configserverIdentity,
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 9b7b666e353..067e8a6b00f 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
@@ -58,6 +58,7 @@ public class EntityBindingsMapper {
entity.ipAddresses(),
IdentityType.fromId(entity.identityType()),
Optional.ofNullable(entity.clusterType()).map(ClusterType::from).orElse(null),
+ entity.ztsUrl(),
entity.unknownAttributes());
}
@@ -74,6 +75,7 @@ public class EntityBindingsMapper {
model.ipAddresses(),
model.identityType().id(),
Optional.ofNullable(model.clusterType()).map(ClusterType::toConfigValue).orElse(null),
+ model.ztsUrl(),
model.unknownAttributes());
}
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 49a39d25e87..eba89b72d87 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
@@ -3,6 +3,7 @@ package com.yahoo.vespa.athenz.identityprovider.api;
import com.yahoo.vespa.athenz.api.AthenzService;
+import java.net.URL;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
@@ -17,7 +18,7 @@ import java.util.Set;
public record SignedIdentityDocument(String signature, int signingKeyVersion, VespaUniqueInstanceId providerUniqueId,
AthenzService providerService, int documentVersion, String configServerHostname,
String instanceHostname, Instant createdAt, Set<String> ipAddresses,
- IdentityType identityType, ClusterType clusterType, Map<String, Object> unknownAttributes) {
+ IdentityType identityType, ClusterType clusterType, String ztsUrl, Map<String, Object> unknownAttributes) {
public SignedIdentityDocument {
ipAddresses = Set.copyOf(ipAddresses);
@@ -33,9 +34,9 @@ public record SignedIdentityDocument(String signature, int signingKeyVersion, Ve
public SignedIdentityDocument(String signature, int signingKeyVersion, VespaUniqueInstanceId providerUniqueId,
AthenzService providerService, int documentVersion, String configServerHostname,
String instanceHostname, Instant createdAt, Set<String> ipAddresses,
- IdentityType identityType, ClusterType clusterType) {
+ IdentityType identityType, ClusterType clusterType, String ztsUrl) {
this(signature, signingKeyVersion, providerUniqueId, providerService, documentVersion, configServerHostname,
- instanceHostname, createdAt, ipAddresses, identityType, clusterType, Map.of());
+ instanceHostname, createdAt, ipAddresses, identityType, clusterType, ztsUrl, Map.of());
}
public static final int DEFAULT_DOCUMENT_VERSION = 2;
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 c37dd2f9147..edbe032ec26 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
@@ -17,7 +17,7 @@ import java.util.Set;
public record SignedIdentityDocumentEntity(
String signature, int signingKeyVersion, String providerUniqueId, String providerService, int documentVersion,
String configServerHostname, String instanceHostname, Instant createdAt, Set<String> ipAddresses,
- String identityType, String clusterType, Map<String, Object> unknownAttributes) {
+ String identityType, String clusterType, String ztsUrl, Map<String, Object> unknownAttributes) {
@JsonCreator
public SignedIdentityDocumentEntity(@JsonProperty("signature") String signature,
@@ -30,9 +30,10 @@ public record SignedIdentityDocumentEntity(
@JsonProperty("created-at") Instant createdAt,
@JsonProperty("ip-addresses") Set<String> ipAddresses,
@JsonProperty("identity-type") String identityType,
- @JsonProperty("cluster-type") String clusterType) {
+ @JsonProperty("cluster-type") String clusterType,
+ @JsonProperty("zts-url") String ztsUrl) {
this(signature, signingKeyVersion, providerUniqueId, providerService, documentVersion, configServerHostname,
- instanceHostname, createdAt, ipAddresses, identityType, clusterType, new HashMap<>());
+ instanceHostname, createdAt, ipAddresses, identityType, clusterType, ztsUrl, new HashMap<>());
}
@JsonProperty("signature") @Override public String signature() { return signature; }
@@ -46,6 +47,7 @@ public record SignedIdentityDocumentEntity(
@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 String ztsUrl() { return ztsUrl; }
@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/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 f8c119190a6..2a68f6fd231 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
@@ -30,6 +30,7 @@ class EntityBindingsMapperTest {
"ip-addresses": [],
"identity-type": "node",
"cluster-type": "admin",
+ "zts-url": "https://zts.url/",
"unknown-string": "string-value",
"unknown-object": { "member-in-unknown-object": 123 }
}
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 0b8ff4277f1..72798b03fa8 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
@@ -36,6 +36,7 @@ public class IdentityDocumentSignerTest {
private static final Instant createdAt = Instant.EPOCH;
private static final HashSet<String> ipAddresses = new HashSet<>(Arrays.asList("1.2.3.4", "::1"));
private static final ClusterType clusterType = ClusterType.CONTAINER;
+ private static final String ztsUrl = "https://foo";
@Test
void generates_and_validates_signature() {
@@ -46,27 +47,27 @@ public class IdentityDocumentSignerTest {
SignedIdentityDocument signedIdentityDocument = new SignedIdentityDocument(
signature, KEY_VERSION, id, providerService, DEFAULT_DOCUMENT_VERSION, configserverHostname,
- instanceHostname, createdAt, ipAddresses, identityType, clusterType);
+ instanceHostname, createdAt, ipAddresses, identityType, clusterType, ztsUrl);
assertTrue(signer.hasValidSignature(signedIdentityDocument, keyPair.getPublic()));
}
@Test
- void ignores_cluster_type() {
+ void ignores_cluster_type_and_zts_url() {
IdentityDocumentSigner signer = new IdentityDocumentSigner();
String signature =
signer.generateSignature(id, providerService, configserverHostname, instanceHostname, createdAt,
ipAddresses, identityType, keyPair.getPrivate());
- var docWithoutClusterType = new SignedIdentityDocument(
+ var docWithoutIgnoredFields = new SignedIdentityDocument(
signature, KEY_VERSION, id, providerService, DEFAULT_DOCUMENT_VERSION, configserverHostname,
- instanceHostname, createdAt, ipAddresses, identityType, null);
- var docWithClusterType = new SignedIdentityDocument(
+ instanceHostname, createdAt, ipAddresses, identityType, null, null);
+ var docWithIgnoredFields = new SignedIdentityDocument(
signature, KEY_VERSION, id, providerService, DEFAULT_DOCUMENT_VERSION, configserverHostname,
- instanceHostname, createdAt, ipAddresses, identityType, clusterType);
+ instanceHostname, createdAt, ipAddresses, identityType, clusterType, ztsUrl);
- assertTrue(signer.hasValidSignature(docWithoutClusterType, keyPair.getPublic()));
- assertEquals(docWithClusterType.signature(), docWithoutClusterType.signature());
+ assertTrue(signer.hasValidSignature(docWithoutIgnoredFields, keyPair.getPublic()));
+ assertEquals(docWithIgnoredFields.signature(), docWithoutIgnoredFields.signature());
}
} \ No newline at end of file