diff options
Diffstat (limited to 'athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/ca/restapi/CertificateAuthorityApiHandler.java')
-rw-r--r-- | athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/ca/restapi/CertificateAuthorityApiHandler.java | 72 |
1 files changed, 3 insertions, 69 deletions
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 4c01b0943e4..1b9bdcdb987 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 @@ -6,24 +6,16 @@ import com.yahoo.container.jdisc.HttpRequest; import com.yahoo.container.jdisc.HttpResponse; import com.yahoo.container.jdisc.LoggingRequestHandler; import com.yahoo.container.jdisc.secretstore.SecretStore; -import com.yahoo.jdisc.http.servlet.ServletRequest; -import com.yahoo.log.LogLevel; import com.yahoo.restapi.ErrorResponse; import com.yahoo.restapi.Path; import com.yahoo.restapi.SlimeJsonResponse; import com.yahoo.security.KeyUtils; -import com.yahoo.security.SubjectAlternativeName; import com.yahoo.security.X509CertificateUtils; import com.yahoo.slime.Slime; -import com.yahoo.vespa.athenz.api.AthenzService; -import com.yahoo.vespa.athenz.identityprovider.api.EntityBindingsMapper; import com.yahoo.vespa.config.SlimeUtils; import com.yahoo.vespa.hosted.athenz.instanceproviderservice.config.AthenzProviderServiceConfig; -import com.yahoo.vespa.hosted.athenz.instanceproviderservice.instanceconfirmation.InstanceConfirmation; -import com.yahoo.vespa.hosted.athenz.instanceproviderservice.instanceconfirmation.InstanceValidator; import com.yahoo.vespa.hosted.ca.Certificates; import com.yahoo.vespa.hosted.ca.instance.InstanceIdentity; -import com.yahoo.vespa.hosted.ca.instance.InstanceRefresh; import com.yahoo.yolean.Exceptions; import java.io.IOException; @@ -31,10 +23,6 @@ import java.io.UncheckedIOException; import java.security.PrivateKey; import java.security.cert.X509Certificate; import java.time.Clock; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Objects; import java.util.Optional; import java.util.function.Function; import java.util.logging.Level; @@ -55,20 +43,18 @@ public class CertificateAuthorityApiHandler extends LoggingRequestHandler { private final Certificates certificates; private final String caPrivateKeySecretName; private final String caCertificateSecretName; - private final InstanceValidator instanceValidator; @Inject - public CertificateAuthorityApiHandler(Context ctx, SecretStore secretStore, AthenzProviderServiceConfig athenzProviderServiceConfig, InstanceValidator instanceValidator) { - this(ctx, secretStore, new Certificates(Clock.systemUTC()), athenzProviderServiceConfig, instanceValidator); + public CertificateAuthorityApiHandler(Context ctx, SecretStore secretStore, AthenzProviderServiceConfig athenzProviderServiceConfig) { + this(ctx, secretStore, new Certificates(Clock.systemUTC()), athenzProviderServiceConfig); } - CertificateAuthorityApiHandler(Context ctx, SecretStore secretStore, Certificates certificates, AthenzProviderServiceConfig athenzProviderServiceConfig, InstanceValidator instanceValidator) { + CertificateAuthorityApiHandler(Context ctx, SecretStore secretStore, Certificates certificates, AthenzProviderServiceConfig athenzProviderServiceConfig) { super(ctx); this.secretStore = secretStore; this.certificates = certificates; this.caPrivateKeySecretName = athenzProviderServiceConfig.secretName(); this.caCertificateSecretName = athenzProviderServiceConfig.domain() + ".ca.cert"; - this.instanceValidator = instanceValidator; } @Override @@ -95,14 +81,6 @@ public class CertificateAuthorityApiHandler extends LoggingRequestHandler { private HttpResponse registerInstance(HttpRequest request) { var instanceRegistration = deserializeRequest(request, InstanceSerializer::registrationFromSlime); - - InstanceConfirmation confirmation = new InstanceConfirmation(instanceRegistration.provider(), instanceRegistration.domain(), instanceRegistration.service(), EntityBindingsMapper.toSignedIdentityDocumentEntity(instanceRegistration.attestationData())); - confirmation.set(InstanceValidator.SAN_IPS_ATTRNAME, Certificates.getSubjectAlternativeNames(instanceRegistration.csr(), SubjectAlternativeName.Type.IP_ADDRESS)); - confirmation.set(InstanceValidator.SAN_DNS_ATTRNAME, Certificates.getSubjectAlternativeNames(instanceRegistration.csr(), SubjectAlternativeName.Type.DNS_NAME)); - if (!instanceValidator.isValidInstance(confirmation)) { - log.log(LogLevel.INFO, "Invalid instance registration for " + instanceRegistration.toString()); - return ErrorResponse.forbidden("Unable to launch service: " +instanceRegistration.service()); - } var certificate = certificates.create(instanceRegistration.csr(), caCertificate(), caPrivateKey()); var instanceId = Certificates.instanceIdFrom(instanceRegistration.csr()); var identity = new InstanceIdentity(instanceRegistration.provider(), instanceRegistration.service(), instanceId, @@ -113,65 +91,21 @@ public class CertificateAuthorityApiHandler extends LoggingRequestHandler { private HttpResponse refreshInstance(HttpRequest request, String provider, String service, String instanceId) { var instanceRefresh = deserializeRequest(request, InstanceSerializer::refreshFromSlime); var instanceIdFromCsr = Certificates.instanceIdFrom(instanceRefresh.csr()); - var athenzService = new AthenzService(request.getJDiscRequest().getUserPrincipal().getName()); if (!instanceIdFromCsr.equals(instanceId)) { throw new IllegalArgumentException("Mismatch between instance ID in URL path and instance ID in CSR " + "[instanceId=" + instanceId + ",instanceIdFromCsr=" + instanceIdFromCsr + "]"); } - - // Verify that the csr instance id matches one of the certificates in the chain - refreshesSameInstanceId(instanceIdFromCsr, request); - - - // Validate that there is no privilege escalation (can only refresh same service) - refreshesSameService(instanceRefresh, athenzService); - - InstanceConfirmation instanceConfirmation = new InstanceConfirmation(provider, athenzService.getDomain().getName(), athenzService.getName(), null); - instanceConfirmation.set(InstanceValidator.SAN_IPS_ATTRNAME, Certificates.getSubjectAlternativeNames(instanceRefresh.csr(), SubjectAlternativeName.Type.IP_ADDRESS)); - instanceConfirmation.set(InstanceValidator.SAN_DNS_ATTRNAME, Certificates.getSubjectAlternativeNames(instanceRefresh.csr(), SubjectAlternativeName.Type.DNS_NAME)); - if(!instanceValidator.isValidRefresh(instanceConfirmation)) { - return ErrorResponse.forbidden("Unable to refresh cert: " + instanceRefresh.csr().getSubject().toString()); - } - var certificate = certificates.create(instanceRefresh.csr(), caCertificate(), caPrivateKey()); var identity = new InstanceIdentity(provider, service, instanceIdFromCsr, Optional.of(certificate)); return new SlimeJsonResponse(InstanceSerializer.identityToSlime(identity)); } - public void refreshesSameInstanceId(String csrInstanceId, HttpRequest request) { - String certificateInstanceId = getRequestCertificateChain(request).stream() - .map(Certificates::instanceIdFrom) - .filter(Optional::isPresent) - .map(Optional::get) - .findAny().orElseThrow(() -> new IllegalArgumentException("No client certificate with instance id in request.")); - - if(! Objects.equals(certificateInstanceId, csrInstanceId)) { - throw new IllegalArgumentException("Mismatch between instance ID in client certificate and instance ID in CSR " + - "[instanceId=" + certificateInstanceId + ",instanceIdFromCsr=" + csrInstanceId + - "]"); - } - } - - private void refreshesSameService(InstanceRefresh instanceRefresh, AthenzService athenzService) { - List<String> commonNames = X509CertificateUtils.getCommonNames(instanceRefresh.csr().getSubject()); - if(commonNames.size() != 1 && !Objects.equals(commonNames.get(0), athenzService.getFullName())) { - throw new IllegalArgumentException(String.format("Invalid request, trying to refresh service %s using service %s.", instanceRefresh.csr().getSubject().getName(), athenzService.getFullName())); - } - } - /** Returns CA certificate from secret store */ private X509Certificate caCertificate() { return X509CertificateUtils.fromPem(secretStore.getSecret(caCertificateSecretName)); } - private List<X509Certificate> getRequestCertificateChain(HttpRequest request) { - return Optional.ofNullable(request.getJDiscRequest().context().get(ServletRequest.JDISC_REQUEST_X509CERT)) - .map(X509Certificate[].class::cast) - .map(Arrays::asList) - .orElse(Collections.emptyList()); - } - /** Returns CA private key from secret store */ private PrivateKey caPrivateKey() { return KeyUtils.fromPemEncodedPrivateKey(secretStore.getSecret(caPrivateKeySecretName)); |