summaryrefslogtreecommitdiffstats
path: root/athenz-identity-provider-service/src/main
diff options
context:
space:
mode:
authorMorten Tokle <mortent@yahooinc.com>2023-02-28 09:24:03 +0100
committerAndreas Eriksen <andreer@yahooinc.com>2023-03-02 15:07:40 +0100
commitbbec3fdb956f1af1a9beaabf15c1426726cebb92 (patch)
tree319713965c5e19d0465de602d1a1b977f651594e /athenz-identity-provider-service/src/main
parent572476ad52aff07de49ce56297954871696ea86c (diff)
Validate using correct key
Diffstat (limited to 'athenz-identity-provider-service/src/main')
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/InstanceValidator.java64
1 files changed, 46 insertions, 18 deletions
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() &&