diff options
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.java | 64 |
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() && |