Search in sources :

Example 1 with X509CertRequest

use of com.yahoo.athenz.zts.cert.X509CertRequest in project athenz by yahoo.

the class ZTSImpl method processProviderX509RefreshRequest.

InstanceIdentity processProviderX509RefreshRequest(ResourceContext ctx, final Principal principal, final String domain, final String service, final String provider, final Principal providerService, final String instanceId, InstanceRefreshInformation info, X509CertRecord x509CertRecord, final String caller) {
    // parse and validate our CSR
    X509CertRequest certReq = null;
    try {
        certReq = new X509CertRequest(info.getCsr());
    } catch (CryptoException ex) {
        throw requestError("unable to parse PKCS10 CSR", caller, domain);
    }
    StringBuilder errorMsg = new StringBuilder(256);
    if (!certReq.validate(providerService, domain, service, instanceId, authorizer, errorMsg)) {
        throw requestError("CSR validation failed - " + errorMsg.toString(), caller, domain);
    }
    // retrieve the certificate that was used for authentication
    // and verify that the dns names in the certificate match to
    // the values specified in the CSR
    X509Certificate cert = principal.getX509Certificate();
    if (!certReq.compareDnsNames(cert)) {
        throw requestError("dnsName attribute mismatch in CSR", caller, domain);
    }
    // validate attestation data is included in the request
    InstanceProvider instanceProvider = instanceProviderManager.getProvider(provider);
    if (instanceProvider == null) {
        throw requestError("unable to get instance for provider: " + provider, caller, domain);
    }
    InstanceConfirmation instance = generateInstanceConfirmObject(ctx, provider, domain, service, info.getAttestationData(), certReq);
    try {
        instance = instanceProvider.refreshInstance(instance);
    } catch (com.yahoo.athenz.instance.provider.ResourceException ex) {
        if (ex.getCode() == com.yahoo.athenz.instance.provider.ResourceException.FORBIDDEN) {
            throw forbiddenError("unable to verify attestation data: " + ex.getMessage(), caller, domain);
        }
    } finally {
        instanceProvider.close();
    }
    // determine what type of certificate the provider is authorizing
    // this instance to refresh - possible values are: server, client or
    // null (indicating both client and server). Additionally, we're
    // going to see if the provider wants to impose an expiry time
    // though the certificate signer might decide to ignore that
    // request and override it with its own value.
    String certUsage = null;
    int certExpiryTime = 0;
    Map<String, String> instanceAttrs = instance.getAttributes();
    if (instanceAttrs != null) {
        certUsage = instanceAttrs.remove(ZTSConsts.ZTS_CERT_USAGE);
        final String expiryTime = instanceAttrs.remove(ZTSConsts.ZTS_CERT_EXPIRY_TIME);
        if (expiryTime != null && !expiryTime.isEmpty()) {
            certExpiryTime = Integer.parseInt(expiryTime);
        }
    }
    // validate that the tenant domain/service matches to the values
    // in the cert record when it was initially issued
    final String principalName = principal.getFullName();
    // now we need to make sure the serial number for the certificate
    // matches to what we had issued previously. If we have a mismatch
    // then we're going to revoke this instance as it has been possibly
    // compromised
    String serialNumber = cert.getSerialNumber().toString();
    if (x509CertRecord.getCurrentSerial().equals(serialNumber)) {
        // update the record to mark current as previous
        // and we'll update the current set with our existing
        // details
        x509CertRecord.setPrevIP(x509CertRecord.getCurrentIP());
        x509CertRecord.setPrevTime(x509CertRecord.getCurrentTime());
        x509CertRecord.setPrevSerial(x509CertRecord.getCurrentSerial());
    } else if (!x509CertRecord.getPrevSerial().equals(serialNumber)) {
        // we have a mismatch for both current and previous serial
        // numbers so we're going to revoke it
        LOGGER.error("Revoking certificate refresh for cn: {} instance id: {}," + " current serial: {}, previous serial: {}, cert serial: {}", principalName, x509CertRecord.getInstanceId(), x509CertRecord.getCurrentSerial(), x509CertRecord.getPrevSerial(), serialNumber);
        x509CertRecord.setPrevSerial("-1");
        x509CertRecord.setCurrentSerial("-1");
        instanceCertManager.updateX509CertRecord(x509CertRecord);
        throw forbiddenError("Certificate revoked", caller, domain);
    }
    // generate identity with the certificate
    InstanceIdentity identity = instanceCertManager.generateIdentity(info.getCsr(), principalName, x509CertRecord.getClientCert() ? ZTSConsts.ZTS_CERT_USAGE_CLIENT : certUsage, certExpiryTime);
    if (identity == null) {
        throw serverError("unable to generate identity", caller, domain);
    }
    // if we're asked then we should also generate a ssh
    // certificate for the instance as well
    instanceCertManager.generateSshIdentity(identity, info.getSsh(), null);
    // set the other required attributes in the identity object
    identity.setProvider(provider);
    identity.setInstanceId(instanceId);
    // need to update our cert record with new certificate details
    X509Certificate newCert = Crypto.loadX509Certificate(identity.getX509Certificate());
    x509CertRecord.setCurrentSerial(newCert.getSerialNumber().toString());
    x509CertRecord.setCurrentIP(ServletRequestUtil.getRemoteAddress(ctx.request()));
    x509CertRecord.setCurrentTime(new Date());
    if (!instanceCertManager.updateX509CertRecord(x509CertRecord)) {
        throw serverError("unable to update cert db", caller, domain);
    }
    if (info.getToken() == Boolean.TRUE) {
        PrincipalToken svcToken = new PrincipalToken.Builder("S1", domain, service).expirationWindow(svcTokenTimeout).keyId(privateKeyId).host(serverHostName).ip(ServletRequestUtil.getRemoteAddress(ctx.request())).keyService(ZTSConsts.ZTS_SERVICE).build();
        svcToken.sign(privateKey);
        identity.setServiceToken(svcToken.getSignedToken());
    }
    // create our audit log entry
    AuditLogMsgBuilder msgBldr = getAuditLogMsgBuilder(ctx, domain, caller, HTTP_POST);
    msgBldr.whatEntity(instanceId);
    StringBuilder auditLogDetails = new StringBuilder(512);
    auditLogDetails.append("Provider: ").append(provider).append(" Domain: ").append(domain).append(" Service: ").append(service).append(" InstanceId: ").append(instanceId).append(" Serial: ").append(x509CertRecord.getCurrentSerial()).append(" Type: x509");
    msgBldr.whatDetails(auditLogDetails.toString());
    auditLogger.log(msgBldr);
    return identity;
}
Also used : InstanceConfirmation(com.yahoo.athenz.instance.provider.InstanceConfirmation) AuditLogMsgBuilder(com.yahoo.athenz.common.server.log.AuditLogMsgBuilder) AuditLogMsgBuilder(com.yahoo.athenz.common.server.log.AuditLogMsgBuilder) PrincipalToken(com.yahoo.athenz.auth.token.PrincipalToken) X509Certificate(java.security.cert.X509Certificate) Date(java.util.Date) X509CertRequest(com.yahoo.athenz.zts.cert.X509CertRequest) CryptoException(com.yahoo.athenz.auth.util.CryptoException) InstanceProvider(com.yahoo.athenz.instance.provider.InstanceProvider)

Example 2 with X509CertRequest

use of com.yahoo.athenz.zts.cert.X509CertRequest in project athenz by yahoo.

the class ZTSImpl method postInstanceRegisterInformation.

@Override
public void postInstanceRegisterInformation(ResourceContext ctx, InstanceRegisterInformation info, PostInstanceRegisterInformationResult instanceResult) {
    final String caller = "postinstanceregisterinformation";
    final String callerTiming = "postinstanceregisterinformation_timing";
    metric.increment(HTTP_POST);
    validateRequest(ctx.request(), caller);
    validate(info, TYPE_INSTANCE_REGISTER_INFO, caller);
    // for consistent handling of all requests, we're going to convert
    // all incoming object values into lower case (e.g. domain, role,
    // policy, service, etc name)
    AthenzObject.INSTANCE_REGISTER_INFO.convertToLowerCase(info);
    final String domain = info.getDomain();
    final String service = info.getService();
    final String cn = domain + "." + service;
    ((RsrcCtxWrapper) ctx).logPrincipal(cn);
    Object timerMetric = metric.startTiming(callerTiming, domain);
    metric.increment(HTTP_REQUEST, domain);
    metric.increment(caller, domain);
    // before running any checks make sure it's coming from
    // an authorized ip address
    final String ipAddress = ServletRequestUtil.getRemoteAddress(ctx.request());
    if (!instanceCertManager.verifyInstanceCertIPAddress(ipAddress)) {
        throw forbiddenError("Unknown IP: " + ipAddress, caller, domain);
    }
    // run the authorization checks to make sure the provider has been
    // authorized to launch instances in Athenz and the service has
    // authorized this provider to launch its instances
    final String provider = info.getProvider();
    Principal providerService = createPrincipalForName(provider);
    StringBuilder errorMsg = new StringBuilder(256);
    if (!instanceCertManager.authorizeLaunch(providerService, domain, service, authorizer, errorMsg)) {
        throw forbiddenError(errorMsg.toString(), caller, domain);
    }
    // validate request/csr details
    X509CertRequest certReq = null;
    try {
        certReq = new X509CertRequest(info.getCsr());
    } catch (CryptoException ex) {
        throw requestError("unable to parse PKCS10 CSR: " + ex.getMessage(), caller, domain);
    }
    if (!certReq.validate(providerService, domain, service, null, authorizer, errorMsg)) {
        throw requestError("CSR validation failed - " + errorMsg.toString(), caller, domain);
    }
    final String certReqInstanceId = certReq.getInstanceId();
    // validate attestation data is included in the request
    InstanceProvider instanceProvider = instanceProviderManager.getProvider(provider);
    if (instanceProvider == null) {
        throw requestError("unable to get instance for provider: " + provider, caller, domain);
    }
    InstanceConfirmation instance = generateInstanceConfirmObject(ctx, provider, domain, service, info.getAttestationData(), certReq);
    try {
        instance = instanceProvider.confirmInstance(instance);
    } catch (Exception ex) {
        throw forbiddenError("unable to verify attestation data: " + ex.getMessage(), caller, domain);
    } finally {
        instanceProvider.close();
    }
    // determine what type of certificate the provider is authorizing
    // this instance to get - possible values are: server, client or
    // null (indicating both client and server). Additionally, we're
    // going to see if the provider wants to impose an expiry time
    // though the certificate signer might decide to ignore that
    // request and override it with its own value.
    String certUsage = null;
    int certExpiryTime = 0;
    boolean certRefreshAllowed = true;
    Map<String, String> instanceAttrs = instance.getAttributes();
    if (instanceAttrs != null) {
        certUsage = instanceAttrs.remove(ZTSConsts.ZTS_CERT_USAGE);
        final String expiryTime = instanceAttrs.remove(ZTSConsts.ZTS_CERT_EXPIRY_TIME);
        if (expiryTime != null && !expiryTime.isEmpty()) {
            certExpiryTime = Integer.parseInt(expiryTime);
        }
        final String certRefreshState = instanceAttrs.remove(ZTSConsts.ZTS_CERT_REFRESH);
        if (certRefreshState != null && !certRefreshState.isEmpty()) {
            certRefreshAllowed = Boolean.parseBoolean(certRefreshState);
        }
    }
    // generate certificate for the instance
    InstanceIdentity identity = instanceCertManager.generateIdentity(info.getCsr(), cn, certUsage, certExpiryTime);
    if (identity == null) {
        throw serverError("unable to generate identity", caller, domain);
    }
    // if we're asked then we should also generate a ssh
    // certificate for the instance as well
    instanceCertManager.generateSshIdentity(identity, info.getSsh(), ZTSConsts.ZTS_SSH_HOST);
    // set the other required attributes in the identity object
    identity.setAttributes(instanceAttrs);
    identity.setProvider(provider);
    identity.setInstanceId(certReqInstanceId);
    X509Certificate newCert = Crypto.loadX509Certificate(identity.getX509Certificate());
    final String certSerial = newCert.getSerialNumber().toString();
    if (certRefreshAllowed) {
        X509CertRecord x509CertRecord = new X509CertRecord();
        x509CertRecord.setService(cn);
        x509CertRecord.setProvider(provider);
        x509CertRecord.setInstanceId(certReqInstanceId);
        x509CertRecord.setCurrentSerial(certSerial);
        x509CertRecord.setCurrentIP(ServletRequestUtil.getRemoteAddress(ctx.request()));
        x509CertRecord.setCurrentTime(new Date());
        x509CertRecord.setPrevSerial(x509CertRecord.getCurrentSerial());
        x509CertRecord.setPrevIP(x509CertRecord.getCurrentIP());
        x509CertRecord.setPrevTime(x509CertRecord.getCurrentTime());
        x509CertRecord.setClientCert(ZTSConsts.ZTS_CERT_USAGE_CLIENT.equalsIgnoreCase(certUsage));
        if (!instanceCertManager.insertX509CertRecord(x509CertRecord)) {
            throw serverError("unable to update cert db", caller, domain);
        }
    }
    if (info.getToken() == Boolean.TRUE) {
        PrincipalToken svcToken = new PrincipalToken.Builder("S1", domain, service).expirationWindow(svcTokenTimeout).keyId(privateKeyId).host(serverHostName).ip(ServletRequestUtil.getRemoteAddress(ctx.request())).keyService(ZTSConsts.ZTS_SERVICE).build();
        svcToken.sign(privateKey);
        identity.setServiceToken(svcToken.getSignedToken());
    }
    // create our audit log entry
    AuditLogMsgBuilder msgBldr = getAuditLogMsgBuilder(ctx, domain, caller, HTTP_POST);
    msgBldr.whatEntity(certReqInstanceId);
    StringBuilder auditLogDetails = new StringBuilder(512);
    auditLogDetails.append("Provider: ").append(provider).append(" Domain: ").append(domain).append(" Service: ").append(service).append(" InstanceId: ").append(certReqInstanceId).append(" Serial: ").append(certSerial);
    msgBldr.whatDetails(auditLogDetails.toString());
    auditLogger.log(msgBldr);
    final String location = "/zts/v1/instance/" + provider + "/" + domain + "/" + service + "/" + certReqInstanceId;
    metric.stopTiming(timerMetric);
    instanceResult.done(ResourceException.CREATED, identity, location);
}
Also used : InstanceConfirmation(com.yahoo.athenz.instance.provider.InstanceConfirmation) AuditLogMsgBuilder(com.yahoo.athenz.common.server.log.AuditLogMsgBuilder) AuditLogMsgBuilder(com.yahoo.athenz.common.server.log.AuditLogMsgBuilder) PrincipalToken(com.yahoo.athenz.auth.token.PrincipalToken) UnsupportedEncodingException(java.io.UnsupportedEncodingException) CryptoException(com.yahoo.athenz.auth.util.CryptoException) X509Certificate(java.security.cert.X509Certificate) X509CertRecord(com.yahoo.athenz.zts.cert.X509CertRecord) Date(java.util.Date) X509CertRequest(com.yahoo.athenz.zts.cert.X509CertRequest) CryptoException(com.yahoo.athenz.auth.util.CryptoException) SimplePrincipal(com.yahoo.athenz.auth.impl.SimplePrincipal) Principal(com.yahoo.athenz.auth.Principal) InstanceProvider(com.yahoo.athenz.instance.provider.InstanceProvider)

Example 3 with X509CertRequest

use of com.yahoo.athenz.zts.cert.X509CertRequest in project athenz by yahoo.

the class ZTSImplTest method testValidateServiceX509RefreshRequestMismatchDns.

@Test
public void testValidateServiceX509RefreshRequestMismatchDns() throws IOException {
    ChangeLogStore structStore = new ZMSFileChangeLogStore("/tmp/zts_server_unit_tests/zts_root", privateKey, "0");
    DataStore store = new DataStore(structStore, null, ztsMetric);
    ZTSImpl ztsImpl = new ZTSImpl(mockCloudStore, store);
    Path path = Paths.get("src/test/resources/athenz.mismatch.dns.csr");
    String csr = new String(Files.readAllBytes(path));
    X509CertRequest certReq = new X509CertRequest(csr);
    assertNotNull(certReq);
    path = Paths.get("src/test/resources/athenz.instanceid.pem");
    String pem = new String(Files.readAllBytes(path));
    X509Certificate cert = Crypto.loadX509Certificate(pem);
    SimplePrincipal principal = (SimplePrincipal) SimplePrincipal.create("athenz", "syncer", "v=S1,d=athenz;n=syncer;s=sig", 0, new CertificateAuthority());
    assertNotNull(principal);
    principal.setX509Certificate(cert);
    assertSame(ztsImpl.validateServiceX509RefreshRequest(principal, certReq, "10.0.0.1"), ServiceX509RefreshRequestStatus.DNS_NAME_MISMATCH);
}
Also used : Path(java.nio.file.Path) X509CertRequest(com.yahoo.athenz.zts.cert.X509CertRequest) ZMSFileChangeLogStore(com.yahoo.athenz.common.server.store.impl.ZMSFileChangeLogStore) ChangeLogStore(com.yahoo.athenz.common.server.store.ChangeLogStore) MockZMSFileChangeLogStore(com.yahoo.athenz.zts.store.MockZMSFileChangeLogStore) ZMSFileChangeLogStore(com.yahoo.athenz.common.server.store.impl.ZMSFileChangeLogStore) MockZMSFileChangeLogStore(com.yahoo.athenz.zts.store.MockZMSFileChangeLogStore) DataStore(com.yahoo.athenz.zts.store.DataStore) X509Certificate(java.security.cert.X509Certificate) Test(org.testng.annotations.Test)

Example 4 with X509CertRequest

use of com.yahoo.athenz.zts.cert.X509CertRequest in project athenz by yahoo.

the class ZTSImplTest method testValidateServiceX509RefreshRequestNotAllowedIP.

@Test
public void testValidateServiceX509RefreshRequestNotAllowedIP() throws IOException {
    ChangeLogStore structStore = new ZMSFileChangeLogStore("/tmp/zts_server_unit_tests/zts_root", privateKey, "0");
    DataStore store = new DataStore(structStore, null, ztsMetric);
    ZTSImpl ztsImpl = new ZTSImpl(mockCloudStore, store);
    Path path = Paths.get("src/test/resources/valid_provider_refresh.csr");
    String csr = new String(Files.readAllBytes(path));
    X509CertRequest certReq = new X509CertRequest(csr);
    assertNotNull(certReq);
    path = Paths.get("src/test/resources/valid_provider_refresh.pem");
    String pem = new String(Files.readAllBytes(path));
    X509Certificate cert = Crypto.loadX509Certificate(pem);
    SimplePrincipal principal = (SimplePrincipal) SimplePrincipal.create("athenz", "syncer", "v=S1,d=athenz;n=syncer;s=sig", 0, new CertificateAuthority());
    assertNotNull(principal);
    principal.setX509Certificate(cert);
    // our ip will not match 10.0.0.1 thus failure
    assertSame(ztsImpl.validateServiceX509RefreshRequest(principal, certReq, "10.0.0.2"), ServiceX509RefreshRequestStatus.IP_NOT_ALLOWED);
}
Also used : Path(java.nio.file.Path) X509CertRequest(com.yahoo.athenz.zts.cert.X509CertRequest) ZMSFileChangeLogStore(com.yahoo.athenz.common.server.store.impl.ZMSFileChangeLogStore) ChangeLogStore(com.yahoo.athenz.common.server.store.ChangeLogStore) MockZMSFileChangeLogStore(com.yahoo.athenz.zts.store.MockZMSFileChangeLogStore) ZMSFileChangeLogStore(com.yahoo.athenz.common.server.store.impl.ZMSFileChangeLogStore) MockZMSFileChangeLogStore(com.yahoo.athenz.zts.store.MockZMSFileChangeLogStore) DataStore(com.yahoo.athenz.zts.store.DataStore) X509Certificate(java.security.cert.X509Certificate) Test(org.testng.annotations.Test)

Example 5 with X509CertRequest

use of com.yahoo.athenz.zts.cert.X509CertRequest in project athenz by yahoo.

the class ZTSImplTest method testValidateServiceX509RefreshRequest.

@Test
public void testValidateServiceX509RefreshRequest() throws IOException {
    ChangeLogStore structStore = new ZMSFileChangeLogStore("/tmp/zts_server_unit_tests/zts_root", privateKey, "0");
    DataStore store = new DataStore(structStore, null, ztsMetric);
    ZTSImpl ztsImpl = new ZTSImpl(mockCloudStore, store);
    Path path = Paths.get("src/test/resources/valid_provider_refresh.csr");
    String csr = new String(Files.readAllBytes(path));
    X509CertRequest certReq = new X509CertRequest(csr);
    assertNotNull(certReq);
    path = Paths.get("src/test/resources/valid_provider_refresh.pem");
    String pem = new String(Files.readAllBytes(path));
    X509Certificate cert = Crypto.loadX509Certificate(pem);
    SimplePrincipal principal = (SimplePrincipal) SimplePrincipal.create("athenz", "syncer", "v=S1,d=athenz;n=syncer;s=sig", 0, new CertificateAuthority());
    assertNotNull(principal);
    principal.setX509Certificate(cert);
    assertSame(ztsImpl.validateServiceX509RefreshRequest(principal, certReq, "10.0.0.1"), ServiceX509RefreshRequestStatus.SUCCESS);
}
Also used : Path(java.nio.file.Path) X509CertRequest(com.yahoo.athenz.zts.cert.X509CertRequest) ZMSFileChangeLogStore(com.yahoo.athenz.common.server.store.impl.ZMSFileChangeLogStore) ChangeLogStore(com.yahoo.athenz.common.server.store.ChangeLogStore) MockZMSFileChangeLogStore(com.yahoo.athenz.zts.store.MockZMSFileChangeLogStore) ZMSFileChangeLogStore(com.yahoo.athenz.common.server.store.impl.ZMSFileChangeLogStore) MockZMSFileChangeLogStore(com.yahoo.athenz.zts.store.MockZMSFileChangeLogStore) DataStore(com.yahoo.athenz.zts.store.DataStore) X509Certificate(java.security.cert.X509Certificate) Test(org.testng.annotations.Test)

Aggregations

X509CertRequest (com.yahoo.athenz.zts.cert.X509CertRequest)7 X509Certificate (java.security.cert.X509Certificate)7 ChangeLogStore (com.yahoo.athenz.common.server.store.ChangeLogStore)5 ZMSFileChangeLogStore (com.yahoo.athenz.common.server.store.impl.ZMSFileChangeLogStore)5 DataStore (com.yahoo.athenz.zts.store.DataStore)5 MockZMSFileChangeLogStore (com.yahoo.athenz.zts.store.MockZMSFileChangeLogStore)5 Path (java.nio.file.Path)5 Test (org.testng.annotations.Test)5 InstanceConfirmation (com.yahoo.athenz.instance.provider.InstanceConfirmation)3 PrincipalToken (com.yahoo.athenz.auth.token.PrincipalToken)2 CryptoException (com.yahoo.athenz.auth.util.CryptoException)2 AuditLogMsgBuilder (com.yahoo.athenz.common.server.log.AuditLogMsgBuilder)2 InstanceProvider (com.yahoo.athenz.instance.provider.InstanceProvider)2 Date (java.util.Date)2 Principal (com.yahoo.athenz.auth.Principal)1 SimplePrincipal (com.yahoo.athenz.auth.impl.SimplePrincipal)1 X509CertRecord (com.yahoo.athenz.zts.cert.X509CertRecord)1 X509ServiceCertRequest (com.yahoo.athenz.zts.cert.X509ServiceCertRequest)1 UnsupportedEncodingException (java.io.UnsupportedEncodingException)1 HttpServletRequest (javax.servlet.http.HttpServletRequest)1