use of com.yahoo.athenz.instance.provider.InstanceConfirmation 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;
}
use of com.yahoo.athenz.instance.provider.InstanceConfirmation 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);
}
use of com.yahoo.athenz.instance.provider.InstanceConfirmation in project athenz by yahoo.
the class ZTSImplTest method testPostInstanceRefreshInformationCertDNSMismatch.
@Test
public void testPostInstanceRefreshInformationCertDNSMismatch() throws IOException {
ChangeLogStore structStore = new ZMSFileChangeLogStore("/tmp/zts_server_unit_tests/zts_root", privateKey, "0");
DataStore store = new DataStore(structStore, null);
ZTSImpl ztsImpl = new ZTSImpl(mockCloudStore, store);
SignedDomain providerDomain = signedAuthorizedProviderDomain();
store.processDomain(providerDomain, false);
SignedDomain tenantDomain = signedBootstrapTenantDomain("athenz.provider", "athenz", "production");
store.processDomain(tenantDomain, false);
Path path = Paths.get("src/test/resources/athenz.instanceid.csr");
String certCsr = new String(Files.readAllBytes(path));
InstanceProviderManager instanceProviderManager = Mockito.mock(InstanceProviderManager.class);
InstanceProvider providerClient = Mockito.mock(InstanceProvider.class);
InstanceConfirmation confirmation = new InstanceConfirmation().setDomain("athenz").setService("production").setProvider("athenz.provider");
InstanceCertManager instanceManager = Mockito.spy(ztsImpl.instanceCertManager);
X509CertRecord certRecord = new X509CertRecord();
certRecord.setInstanceId("1001");
certRecord.setProvider("athenz.provider");
certRecord.setService("athenz.production");
certRecord.setCurrentSerial("16503746516960996918");
certRecord.setPrevSerial("16503746516960996918");
Mockito.when(instanceManager.getX509CertRecord("athenz.provider", "1001")).thenReturn(certRecord);
Mockito.when(instanceProviderManager.getProvider("athenz.provider")).thenReturn(providerClient);
Mockito.when(providerClient.refreshInstance(Mockito.any())).thenReturn(confirmation);
path = Paths.get("src/test/resources/valid_cn_x509.cert");
String pem = new String(Files.readAllBytes(path));
InstanceIdentity identity = new InstanceIdentity().setName("athenz.production").setX509Certificate(pem);
Mockito.doReturn(identity).when(instanceManager).generateIdentity(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyInt());
ztsImpl.instanceProviderManager = instanceProviderManager;
ztsImpl.instanceCertManager = instanceManager;
InstanceRefreshInformation info = new InstanceRefreshInformation().setCsr(certCsr);
CertificateAuthority certAuthority = new CertificateAuthority();
SimplePrincipal principal = (SimplePrincipal) SimplePrincipal.create("athenz", "production", "v=S1;d=athenz;n=production;s=signature", 0, certAuthority);
X509Certificate cert = Crypto.loadX509Certificate(pem);
principal.setX509Certificate(cert);
ResourceContext context = createResourceContext(principal);
try {
ztsImpl.postInstanceRefreshInformation(context, "athenz.provider", "athenz", "production", "1001", info);
fail();
} catch (ResourceException ex) {
assertEquals(ex.getCode(), 400);
assertTrue(ex.getMessage().contains("dnsName attribute mismatch in CSR"));
}
}
use of com.yahoo.athenz.instance.provider.InstanceConfirmation in project athenz by yahoo.
the class ZTSImplTest method testPostInstanceRefreshInformation.
@Test
public void testPostInstanceRefreshInformation() throws IOException {
ChangeLogStore structStore = new ZMSFileChangeLogStore("/tmp/zts_server_unit_tests/zts_root", privateKey, "0");
DataStore store = new DataStore(structStore, null);
ZTSImpl ztsImpl = new ZTSImpl(mockCloudStore, store);
SignedDomain providerDomain = signedAuthorizedProviderDomain();
store.processDomain(providerDomain, false);
SignedDomain tenantDomain = signedBootstrapTenantDomain("athenz.provider", "athenz", "production");
store.processDomain(tenantDomain, false);
Path path = Paths.get("src/test/resources/athenz.instanceid.csr");
String certCsr = new String(Files.readAllBytes(path));
InstanceProviderManager instanceProviderManager = Mockito.mock(InstanceProviderManager.class);
InstanceProvider providerClient = Mockito.mock(InstanceProvider.class);
InstanceConfirmation confirmation = new InstanceConfirmation().setDomain("athenz").setService("production").setProvider("athenz.provider");
InstanceCertManager instanceManager = Mockito.spy(ztsImpl.instanceCertManager);
Mockito.when(instanceProviderManager.getProvider("athenz.provider")).thenReturn(providerClient);
Mockito.when(providerClient.refreshInstance(Mockito.any())).thenReturn(confirmation);
X509CertRecord certRecord = new X509CertRecord();
certRecord.setInstanceId("1001");
certRecord.setProvider("athenz.provider");
certRecord.setService("athenz.production");
certRecord.setCurrentSerial("16503746516960996918");
certRecord.setPrevSerial("16503746516960996918");
Mockito.when(instanceManager.getX509CertRecord("athenz.provider", "1001")).thenReturn(certRecord);
Mockito.when(instanceManager.updateX509CertRecord(Mockito.any())).thenReturn(true);
path = Paths.get("src/test/resources/athenz.instanceid.pem");
String pem = new String(Files.readAllBytes(path));
InstanceIdentity identity = new InstanceIdentity().setName("athenz.production").setX509Certificate(pem);
Mockito.doReturn(identity).when(instanceManager).generateIdentity(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyInt());
ztsImpl.instanceProviderManager = instanceProviderManager;
ztsImpl.instanceCertManager = instanceManager;
InstanceRefreshInformation info = new InstanceRefreshInformation().setCsr(certCsr).setToken(true);
CertificateAuthority certAuthority = new CertificateAuthority();
SimplePrincipal principal = (SimplePrincipal) SimplePrincipal.create("athenz", "production", "v=S1;d=athenz;n=production;s=signature", 0, certAuthority);
X509Certificate cert = Crypto.loadX509Certificate(pem);
principal.setX509Certificate(cert);
ResourceContext context = createResourceContext(principal);
InstanceIdentity instanceIdentity = ztsImpl.postInstanceRefreshInformation(context, "athenz.provider", "athenz", "production", "1001", info);
assertNotNull(instanceIdentity);
assertNotNull(instanceIdentity.getServiceToken());
}
use of com.yahoo.athenz.instance.provider.InstanceConfirmation in project athenz by yahoo.
the class ZTSImplTest method testPostInstanceRefreshInformationSerialMismatch.
@Test
public void testPostInstanceRefreshInformationSerialMismatch() throws IOException {
ChangeLogStore structStore = new ZMSFileChangeLogStore("/tmp/zts_server_unit_tests/zts_root", privateKey, "0");
DataStore store = new DataStore(structStore, null);
ZTSImpl ztsImpl = new ZTSImpl(mockCloudStore, store);
SignedDomain providerDomain = signedAuthorizedProviderDomain();
store.processDomain(providerDomain, false);
SignedDomain tenantDomain = signedBootstrapTenantDomain("athenz.provider", "athenz", "production");
store.processDomain(tenantDomain, false);
Path path = Paths.get("src/test/resources/athenz.instanceid.csr");
String certCsr = new String(Files.readAllBytes(path));
InstanceProviderManager instanceProviderManager = Mockito.mock(InstanceProviderManager.class);
InstanceProvider providerClient = Mockito.mock(InstanceProvider.class);
InstanceConfirmation confirmation = new InstanceConfirmation().setDomain("athenz").setService("production").setProvider("athenz.provider");
InstanceCertManager instanceManager = Mockito.spy(ztsImpl.instanceCertManager);
Mockito.when(instanceProviderManager.getProvider("athenz.provider")).thenReturn(providerClient);
Mockito.when(providerClient.refreshInstance(Mockito.any())).thenReturn(confirmation);
X509CertRecord certRecord = new X509CertRecord();
certRecord.setInstanceId("1001");
certRecord.setProvider("athenz.provider");
certRecord.setService("athenz.production");
certRecord.setCurrentSerial("101");
certRecord.setPrevSerial("101");
Mockito.when(instanceManager.getX509CertRecord("athenz.provider", "1001")).thenReturn(certRecord);
Mockito.when(instanceManager.updateX509CertRecord(Mockito.any())).thenReturn(true);
path = Paths.get("src/test/resources/athenz.instanceid.pem");
String pem = new String(Files.readAllBytes(path));
InstanceIdentity identity = new InstanceIdentity().setName("athenz.production").setX509Certificate(pem);
Mockito.doReturn(identity).when(instanceManager).generateIdentity(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyInt());
ztsImpl.instanceProviderManager = instanceProviderManager;
ztsImpl.instanceCertManager = instanceManager;
InstanceRefreshInformation info = new InstanceRefreshInformation().setCsr(certCsr);
CertificateAuthority certAuthority = new CertificateAuthority();
SimplePrincipal principal = (SimplePrincipal) SimplePrincipal.create("athenz", "production", "v=S1;d=athenz;n=production;s=signature", 0, certAuthority);
X509Certificate cert = Crypto.loadX509Certificate(pem);
principal.setX509Certificate(cert);
ResourceContext context = createResourceContext(principal);
try {
ztsImpl.postInstanceRefreshInformation(context, "athenz.provider", "athenz", "production", "1001", info);
fail();
} catch (ResourceException ex) {
assertEquals(ex.getCode(), 403);
assertTrue(ex.getMessage().contains("Certificate revoked"));
}
}
Aggregations