From 52f764682095c08f654e59d3041a704b9ac9551c Mon Sep 17 00:00:00 2001 From: Valerij Fredriksen Date: Thu, 2 Nov 2017 12:58:49 +0100 Subject: Validate identity same as in services.xml --- athenz-identity-provider-service/pom.xml | 6 +++ .../AthenzInstanceProviderService.java | 12 ++++-- .../impl/InstanceValidator.java | 50 +++++++++++++++++++++- 3 files changed, 63 insertions(+), 5 deletions(-) (limited to 'athenz-identity-provider-service') diff --git a/athenz-identity-provider-service/pom.xml b/athenz-identity-provider-service/pom.xml index bb82e40f827..26e24be526c 100644 --- a/athenz-identity-provider-service/pom.xml +++ b/athenz-identity-provider-service/pom.xml @@ -82,6 +82,12 @@ ${project.version} provided + + com.yahoo.vespa + config-model-api + ${project.version} + provided + diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderService.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderService.java index e66130332ac..c417675f16d 100644 --- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderService.java +++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderService.java @@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.athenz.instanceproviderservice; import com.google.inject.Inject; import com.yahoo.component.AbstractComponent; +import com.yahoo.config.model.api.SuperModelProvider; import com.yahoo.config.provision.SystemName; import com.yahoo.config.provision.Zone; import com.yahoo.log.LogLevel; @@ -47,14 +48,16 @@ public class AthenzInstanceProviderService extends AbstractComponent { private final Server jetty; @Inject - public AthenzInstanceProviderService(AthenzProviderServiceConfig config, NodeRepository nodeRepository, Zone zone) { + public AthenzInstanceProviderService(AthenzProviderServiceConfig config, SuperModelProvider superModelProvider, + NodeRepository nodeRepository, Zone zone) { this(config, new FileBackedKeyProvider(config.keyPathPrefix()), Executors.newSingleThreadScheduledExecutor(), - nodeRepository, zone, new AthenzCertificateClient(config)); + superModelProvider, nodeRepository, zone, new AthenzCertificateClient(config)); } AthenzInstanceProviderService(AthenzProviderServiceConfig config, KeyProvider keyProvider, ScheduledExecutorService scheduler, + SuperModelProvider superModelProvider, NodeRepository nodeRepository, Zone zone, CertificateClient certificateClient) { @@ -63,7 +66,7 @@ public class AthenzInstanceProviderService extends AbstractComponent { this.scheduler = scheduler; SslContextFactory sslContextFactory = createSslContextFactory(); this.jetty = createJettyServer( - config, keyProvider, sslContextFactory, nodeRepository, zone); + config, keyProvider, sslContextFactory, superModelProvider, nodeRepository, zone); AthenzCertificateUpdater reloader = new AthenzCertificateUpdater(certificateClient, sslContextFactory, keyProvider, config); // TODO Configurable update frequency @@ -82,6 +85,7 @@ public class AthenzInstanceProviderService extends AbstractComponent { private static Server createJettyServer(AthenzProviderServiceConfig config, KeyProvider keyProvider, SslContextFactory sslContextFactory, + SuperModelProvider superModelProvider, NodeRepository nodeRepository, Zone zone) { Server server = new Server(); @@ -91,7 +95,7 @@ public class AthenzInstanceProviderService extends AbstractComponent { ServletHandler handler = new ServletHandler(); InstanceConfirmationServlet instanceConfirmationServlet = - new InstanceConfirmationServlet(new InstanceValidator(keyProvider)); + new InstanceConfirmationServlet(new InstanceValidator(keyProvider, superModelProvider)); handler.addServletWithMapping(new ServletHolder(instanceConfirmationServlet), config.apiPath() + "/instance"); IdentityDocumentServlet identityDocumentServlet = diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/InstanceValidator.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/InstanceValidator.java index 8d76300c2bb..d738b34041a 100644 --- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/InstanceValidator.java +++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/InstanceValidator.java @@ -1,6 +1,10 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl; +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.log.LogLevel; import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.model.InstanceConfirmation; import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.model.ProviderUniqueId; @@ -12,6 +16,7 @@ import java.security.PublicKey; import java.security.Signature; import java.security.SignatureException; import java.util.Base64; +import java.util.Optional; import java.util.logging.Logger; /** @@ -24,14 +29,23 @@ public class InstanceValidator { private static final Logger log = Logger.getLogger(InstanceValidator.class.getName()); private final KeyProvider keyProvider; + private final SuperModelProvider superModelProvider; - public InstanceValidator(KeyProvider keyProvider) { + public InstanceValidator(KeyProvider keyProvider, SuperModelProvider superModelProvider) { this.keyProvider = keyProvider; + this.superModelProvider = superModelProvider; } public boolean isValidInstance(InstanceConfirmation instanceConfirmation) { SignedIdentityDocument signedIdentityDocument = instanceConfirmation.signedIdentityDocument; ProviderUniqueId providerUniqueId = signedIdentityDocument.identityDocument.providerUniqueId; + ApplicationId applicationId = ApplicationId.from( + providerUniqueId.tenant, providerUniqueId.application, providerUniqueId.instance); + + if (! isSameIdentityAsInServicesXml(applicationId, instanceConfirmation.domain, instanceConfirmation.service)) { + return false; + } + log.log(LogLevel.INFO, () -> String.format("Validating instance %s.", providerUniqueId)); PublicKey publicKey = keyProvider.getPublicKey(signedIdentityDocument.signingKeyVersion); if (isSignatureValid(publicKey, signedIdentityDocument.rawIdentityDocument, signedIdentityDocument.signature)) { @@ -52,4 +66,38 @@ public class InstanceValidator { throw new RuntimeException(e); } } + + // If/when we dont care about logging exactly whats wrong, this can be simplified + private boolean isSameIdentityAsInServicesXml(ApplicationId applicationId, String domain, String service) { + Optional applicationInfo = superModelProvider.getSuperModel().getApplicationInfo(applicationId); + + if (!applicationInfo.isPresent()) { + log.info(String.format("Could not find application info for %s", applicationId.serializedForm())); + return false; + } + + Optional matchingServiceInfo = applicationInfo.get() + .getModel() + .getHosts() + .stream() + .flatMap(hostInfo -> hostInfo.getServices().stream()) + .filter(serviceInfo -> serviceInfo.getProperty("identity.domain").isPresent()) + .filter(serviceInfo -> serviceInfo.getProperty("identity.service").isPresent()) + .findFirst(); + + if (!matchingServiceInfo.isPresent()) { + log.info(String.format("Application %s has not specified domain/service", applicationId.serializedForm())); + return false; + } + + String domainInConfig = matchingServiceInfo.get().getProperty("identity.domain").get(); + String serviceInConfig = matchingServiceInfo.get().getProperty("identity.service").get(); + if (domainInConfig.equals(domain) && serviceInConfig.equals(service)) { + return true; + } else { + log.info(String.format("domain '%s' or service '%s' does not match the one in config for application %s", + domain, service, applicationId.serializedForm())); + return false; + } + } } -- cgit v1.2.3