use of com.yahoo.athenz.common.server.ssh.SSHCertRecord in project athenz by yahoo.
the class ZTSImpl method postInstanceRegisterInformation.
@Override
public Response postInstanceRegisterInformation(ResourceContext ctx, InstanceRegisterInformation info) {
final String caller = ctx.getApiName();
final String principalDomain = logPrincipalAndGetDomain(ctx);
if (readOnlyMode.get()) {
throw requestError("Server in Maintenance Read-Only mode. Please try your request later", caller, ZTSConsts.ZTS_UNKNOWN_DOMAIN, principalDomain);
}
validateRequest(ctx.request(), principalDomain, caller);
validate(info, TYPE_INSTANCE_REGISTER_INFO, principalDomain, 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().toLowerCase();
setRequestDomain(ctx, domain);
final String service = info.getService().toLowerCase();
final String cn = ResourceUtils.serviceResourceName(domain, service);
((RsrcCtxWrapper) ctx).logPrincipal(cn);
// before running any checks make sure it's coming from
// an authorized ip address
final String provider = info.getProvider();
final String ipAddress = ServletRequestUtil.getRemoteAddress(ctx.request());
if (!instanceCertManager.verifyInstanceCertIPAddress(provider, ipAddress)) {
throw forbiddenError("Unknown IP: " + ipAddress + " for Provider: " + provider, caller, domain, principalDomain);
}
// get our domain object and validate the service is correctly registered
DomainData domainData = dataStore.getDomainData(domain);
if (domainData == null) {
setRequestDomain(ctx, ZTSConsts.ZTS_UNKNOWN_DOMAIN);
throw notFoundError("Domain not found: " + domain, caller, ZTSConsts.ZTS_UNKNOWN_DOMAIN, principalDomain);
}
validateInstanceServiceIdentity(domainData, cn, caller);
// 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
Principal providerService = createPrincipalForName(provider);
StringBuilder errorMsg = new StringBuilder(256);
if (!instanceCertManager.authorizeLaunch(providerService, domain, service, errorMsg)) {
throw forbiddenError(errorMsg.toString(), caller, domain, principalDomain);
}
// validate request/csr details
X509ServiceCertRequest certReq;
try {
certReq = new X509ServiceCertRequest(info.getCsr());
} catch (CryptoException ex) {
throw requestError("unable to parse PKCS10 CSR: " + ex.getMessage(), caller, domain, principalDomain);
}
final String serviceDnsSuffix = domainData.getCertDnsDomain();
final DataCache athenzSysDomainCache = dataStore.getDataCache(ATHENZ_SYS_DOMAIN);
if (!certReq.validate(domain, service, provider, validCertSubjectOrgValues, athenzSysDomainCache, serviceDnsSuffix, info.getHostname(), info.getHostCnames(), hostnameResolver, errorMsg)) {
throw requestError("CSR validation failed - " + errorMsg, caller, domain, principalDomain);
}
final String certReqInstanceId = certReq.getInstanceId();
// validate attestation data is included in the request
InstanceProvider instanceProvider = instanceProviderManager.getProvider(provider, hostnameResolver);
if (instanceProvider == null) {
throw requestError("unable to get instance for provider: " + provider, caller, domain, principalDomain);
}
// include instance details in the query access log to help
// with debugging requests
ctx.request().setAttribute(ACCESS_LOG_ADDL_QUERY, getInstanceRegisterQueryLog(provider, certReqInstanceId, info.getHostname()));
InstanceConfirmation instance = newInstanceConfirmationForRegister(ctx, provider, domain, service, info.getAttestationData(), certReqInstanceId, info.getHostname(), certReq, instanceProvider.getProviderScheme());
// Store sanIP from CSR in a variable since instance attributes go through bunch of manipulations.
// This is used to derive workload information from identity
String sanIpStrForWorkloadStore = InstanceUtils.getInstanceProperty(instance.getAttributes(), InstanceProvider.ZTS_INSTANCE_SAN_IP);
// make sure to close our provider when its no longer needed
Object timerProviderMetric = metric.startTiming("providerregister_timing", provider, principalDomain);
try {
instance = instanceProvider.confirmInstance(instance);
} catch (com.yahoo.athenz.instance.provider.ResourceException ex) {
metric.increment("providerconfirm_failure", domain, provider);
int code = (ex.getCode() == ResourceException.GATEWAY_TIMEOUT) ? ResourceException.GATEWAY_TIMEOUT : ResourceException.FORBIDDEN;
throw error(code, getExceptionMsg("unable to verify attestation data: ", ctx, ex, info.getHostname()), caller, domain, principalDomain);
} catch (Exception ex) {
metric.increment("providerconfirm_failure", domain, provider);
throw forbiddenError(getExceptionMsg("unable to verify attestation data: ", ctx, ex, info.getHostname()), caller, domain, principalDomain);
} finally {
metric.stopTiming(timerProviderMetric, provider, principalDomain);
instanceProvider.close();
}
metric.increment("providerconfirm_success", domain, provider);
// 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. Other optional
// attributes we get back from the provider include whether or
// not the certs can be refreshed or ssh certs can be requested
String certUsage = null;
String certSubjectOU = null;
String instancePrivateIp = null;
int certExpiryTime = 0;
boolean certRefresh = true;
boolean sshCertAllowed = false;
Map<String, String> instanceAttrs = instance.getAttributes();
if (instanceAttrs != null) {
certUsage = instanceAttrs.remove(InstanceProvider.ZTS_CERT_USAGE);
certSubjectOU = instanceAttrs.remove(InstanceProvider.ZTS_CERT_SUBJECT_OU);
instancePrivateIp = instanceAttrs.remove(InstanceProvider.ZTS_INSTANCE_PRIVATE_IP);
certExpiryTime = ZTSUtils.parseInt(instanceAttrs.remove(InstanceProvider.ZTS_CERT_EXPIRY_TIME), 0);
certRefresh = ZTSUtils.parseBoolean(instanceAttrs.remove(InstanceProvider.ZTS_CERT_REFRESH), true);
sshCertAllowed = ZTSUtils.parseBoolean(instanceAttrs.remove(InstanceProvider.ZTS_CERT_SSH), false);
}
if (verifyCertSubjectOU && !certReq.validateSubjectOUField(provider, certSubjectOU, validCertSubjectOrgUnitValues)) {
throw requestError("CSR Subject OrgUnit validation failed", caller, domain, principalDomain);
}
// update the expiry time if one is provided in the request
certExpiryTime = getServiceCertRequestExpiryTime(certExpiryTime, info.getExpiryTime());
// generate certificate for the instance
// Initial request from the workload gets highest priority
Priority priority = Priority.High;
Object timerX509CertMetric = metric.startTiming("certsignx509_timing", null, principalDomain);
InstanceIdentity identity = instanceCertManager.generateIdentity(provider, null, info.getCsr(), cn, certUsage, certExpiryTime, priority);
metric.stopTiming(timerX509CertMetric, null, principalDomain);
if (identity == null) {
throw serverError("unable to generate identity", caller, domain, principalDomain);
}
if (sshCertAllowed) {
Object timerSSHCertMetric = metric.startTiming("certsignssh_timing", null, principalDomain);
// generate a ssh object for recording
SSHCertRecord certRecord = generateSSHCertRecord(ctx, cn, certReqInstanceId, instancePrivateIp);
instanceCertManager.generateSSHIdentity(null, identity, info.getHostname(), info.getSsh(), info.getSshCertRequest(), certRecord, ZTSConsts.ZTS_SSH_HOST);
metric.stopTiming(timerSSHCertMetric, null, principalDomain);
}
// 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 (certRefresh) {
if (insertX509CertRecord(ctx, cn, provider, certReqInstanceId, certSerial, InstanceProvider.ZTS_CERT_USAGE_CLIENT.equalsIgnoreCase(certUsage), newCert.getNotAfter(), info.getHostname()) == null) {
throw serverError("unable to update cert db", caller, domain, principalDomain);
}
}
if (enableWorkloadStore && !athenzSysDomainCache.isWorkloadStoreExcludedProvider(provider)) {
// insert into workloads store is on best-effort basis. No errors are thrown if the op is not successful.
insertWorkloadRecord(cn, provider, certReqInstanceId, sanIpStrForWorkloadStore, info.getHostname(), newCert.getNotAfter());
}
if (info.getToken() == Boolean.TRUE) {
PrincipalToken svcToken = new PrincipalToken.Builder("S1", domain, service).expirationWindow(svcTokenTimeout).keyId(privateKey.getId()).host(serverHostName).ip(ipAddress).keyService(ZTSConsts.ZTS_SERVICE).build();
svcToken.sign(privateKey.getKey());
identity.setServiceToken(svcToken.getSignedToken());
}
// log our certificate
instanceCertManager.logX509Cert(null, ipAddress, provider, certReqInstanceId, newCert);
final String location = "/zts/v1/instance/" + provider + "/" + domain + "/" + service + "/" + certReqInstanceId;
return Response.status(ResourceException.CREATED).entity(identity).header("Location", location).build();
}
use of com.yahoo.athenz.common.server.ssh.SSHCertRecord in project athenz by yahoo.
the class ZTSImpl method processProviderX509RefreshRequest.
InstanceIdentity processProviderX509RefreshRequest(ResourceContext ctx, DomainData domainData, final Principal principal, final String domain, final String service, final String provider, final String instanceId, InstanceRefreshInformation info, X509Certificate cert, final String caller) {
// parse and validate our CSR
final String principalDomain = principal.getDomain();
X509ServiceCertRequest certReq;
try {
certReq = new X509ServiceCertRequest(info.getCsr());
} catch (CryptoException ex) {
throw requestError("unable to parse PKCS10 CSR", caller, domain, principalDomain);
}
final String serviceDnsSuffix = domainData.getCertDnsDomain();
final DataCache athenzSysDomainCache = dataStore.getDataCache(ATHENZ_SYS_DOMAIN);
StringBuilder errorMsg = new StringBuilder(256);
if (!certReq.validate(domain, service, provider, validCertSubjectOrgValues, athenzSysDomainCache, serviceDnsSuffix, info.getHostname(), info.getHostCnames(), hostnameResolver, errorMsg)) {
throw requestError("CSR validation failed - " + errorMsg, caller, domain, principalDomain);
}
if (!certReq.validateInstanceId(instanceId, cert)) {
throw requestError("CSR validation failed - instance id mismatch", caller, domain, principalDomain);
}
// Extract Hostname in the certificate to be passed onto the provider
String certHostname = X509CertUtils.extractItemFromURI(Crypto.extractX509CertURIs(cert), ZTSConsts.ZTS_CERT_HOSTNAME_URI);
// validate attestation data is included in the request
InstanceProvider instanceProvider = instanceProviderManager.getProvider(provider, hostnameResolver);
if (instanceProvider == null) {
throw requestError("unable to get instance for provider: " + provider, caller, domain, principalDomain);
}
InstanceConfirmation instance = generateInstanceConfirmObject(ctx, provider, domain, service, info.getAttestationData(), instanceId, info.getHostname(), certHostname, certReq, instanceProvider.getProviderScheme());
// Store sanIP from CSR in a variable since instance attributes go through bunch of manipulations.
// This is used to derive workload information from identity
String sanIpStrForWorkloadStore = InstanceUtils.getInstanceProperty(instance.getAttributes(), InstanceProvider.ZTS_INSTANCE_SAN_IP);
// make sure to close our provider when its no longer needed
Object timerProviderMetric = metric.startTiming("providerrefresh_timing", provider, principalDomain);
try {
instance = instanceProvider.refreshInstance(instance);
} catch (com.yahoo.athenz.instance.provider.ResourceException ex) {
metric.increment("providerconfirm_failure", domain, provider);
int code = (ex.getCode() == ResourceException.GATEWAY_TIMEOUT) ? ResourceException.GATEWAY_TIMEOUT : ResourceException.FORBIDDEN;
throw error(code, getExceptionMsg("unable to verify attestation data: ", ctx, ex, info.getHostname()), caller, domain, principalDomain);
} catch (Exception ex) {
metric.increment("providerconfirm_failure", domain, provider);
throw forbiddenError(getExceptionMsg("unable to verify attestation data: ", ctx, ex, info.getHostname()), caller, domain, principalDomain);
} finally {
metric.stopTiming(timerProviderMetric, provider, principalDomain);
instanceProvider.close();
}
metric.increment("providerconfirm_success", domain, provider);
// 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. Other optional
// attributes we get back from the provider include whether or
// not the certs can be refreshed or ssh certs can be requested
String certUsage = null;
String certSubjectOU = null;
String instancePrivateIp = null;
int certExpiryTime = 0;
boolean sshCertAllowed = false;
boolean certRefreshCheck = true;
Map<String, String> instanceAttrs = instance.getAttributes();
if (instanceAttrs != null) {
certUsage = instanceAttrs.remove(InstanceProvider.ZTS_CERT_USAGE);
instancePrivateIp = instanceAttrs.remove(InstanceProvider.ZTS_INSTANCE_PRIVATE_IP);
certExpiryTime = ZTSUtils.parseInt(instanceAttrs.remove(InstanceProvider.ZTS_CERT_EXPIRY_TIME), 0);
certRefreshCheck = ZTSUtils.parseBoolean(instanceAttrs.remove(InstanceProvider.ZTS_CERT_REFRESH), true);
certSubjectOU = instanceAttrs.remove(InstanceProvider.ZTS_CERT_SUBJECT_OU);
sshCertAllowed = ZTSUtils.parseBoolean(instanceAttrs.remove(InstanceProvider.ZTS_CERT_SSH), false);
}
if (verifyCertSubjectOU && !certReq.validateSubjectOUField(provider, certSubjectOU, validCertSubjectOrgUnitValues)) {
throw requestError("CSR Subject OrgUnit validation failed", caller, domain, principalDomain);
}
// validate that the tenant domain/service matches to the values
// in the cert record when it was initially issued
final String principalName = principal.getFullName();
// if the provider allows the certs to be refreshed then we need
// to extract our instance certificate record to make sure it
// hasn't been revoked already
X509CertRecord x509CertRecord = null;
if (certRefreshCheck) {
x509CertRecord = getValidatedX509CertRecord(ctx, provider, instanceId, principalName, cert, caller, domain, principalDomain, info.getHostname());
}
if (x509CertRecord != null && x509CertRecord.getClientCert()) {
certUsage = InstanceProvider.ZTS_CERT_USAGE_CLIENT;
}
// update the expiry time if one is provided in the request
certExpiryTime = getServiceCertRequestExpiryTime(certExpiryTime, info.getExpiryTime());
// generate identity with the certificate
Priority priority = ZTSUtils.getCertRequestPriority(cert.getNotBefore(), cert.getNotAfter());
Object timerX509CertMetric = metric.startTiming("certsignx509_timing", null, principalDomain);
InstanceIdentity identity = instanceCertManager.generateIdentity(provider, null, info.getCsr(), principalName, certUsage, certExpiryTime, priority);
metric.stopTiming(timerX509CertMetric, null, principalDomain);
if (identity == null) {
throw serverError("unable to generate identity", caller, domain, principalDomain);
}
if (sshCertAllowed) {
Object timerSSHCertMetric = metric.startTiming("certsignssh_timing", null, principalDomain);
// generate an ssh object for recording
SSHCertRecord certRecord = generateSSHCertRecord(ctx, domain + "." + service, instanceId, instancePrivateIp);
instanceCertManager.generateSSHIdentity(principal, identity, info.getHostname(), info.getSsh(), info.getSshCertRequest(), certRecord, ZTSConsts.ZTS_SSH_HOST);
metric.stopTiming(timerSSHCertMetric, null, principalDomain);
}
// set the other required attributes in the identity object
identity.setAttributes(instanceAttrs);
identity.setProvider(provider);
identity.setInstanceId(instanceId);
// need to update our cert record with new certificate details
X509Certificate newCert = Crypto.loadX509Certificate(identity.getX509Certificate());
final String certSerialNumber = newCert.getSerialNumber().toString();
final String reqIp = ServletRequestUtil.getRemoteAddress(ctx.request());
if (x509CertRecord != null) {
// if our current IP or hostname has changed, we'll mark
// the record as svc data updated
processCertRecordChange(x509CertRecord, reqIp, info.getHostname());
// now let's update our record
x509CertRecord.setCurrentSerial(certSerialNumber);
x509CertRecord.setCurrentIP(reqIp);
x509CertRecord.setCurrentTime(new Date());
x509CertRecord.setExpiryTime(newCert.getNotAfter());
x509CertRecord.setHostName(info.getHostname());
if (!instanceCertManager.updateX509CertRecord(x509CertRecord)) {
throw serverError("unable to update cert db", caller, domain, principalDomain);
}
}
if (enableWorkloadStore && !athenzSysDomainCache.isWorkloadStoreExcludedProvider(provider)) {
// workloads store update is on best-effort basis. No errors are thrown if the op is not successful.
updateWorkloadRecord(AthenzUtils.getPrincipalName(domain, service), provider, instanceId, sanIpStrForWorkloadStore, info.getHostname(), newCert.getNotAfter());
}
// log our certificate
instanceCertManager.logX509Cert(principal, reqIp, provider, instanceId, newCert);
if (info.getToken() == Boolean.TRUE) {
PrincipalToken svcToken = new PrincipalToken.Builder("S1", domain, service).expirationWindow(svcTokenTimeout).keyId(privateKey.getId()).host(serverHostName).ip(ServletRequestUtil.getRemoteAddress(ctx.request())).keyService(ZTSConsts.ZTS_SERVICE).build();
svcToken.sign(privateKey.getKey());
identity.setServiceToken(svcToken.getSignedToken());
}
return identity;
}
use of com.yahoo.athenz.common.server.ssh.SSHCertRecord in project athenz by yahoo.
the class SSHCertRecordTest method testSSHCertRecord.
@Test
public void testSSHCertRecord() {
SSHCertRecord certRecord = new SSHCertRecord();
certRecord.setService("cn");
certRecord.setInstanceId("instance-id");
certRecord.setPrincipals("host1,host2");
certRecord.setClientIP("10.1.1.1");
certRecord.setPrivateIP("10.1.1.2");
assertEquals(certRecord.getService(), "cn");
assertEquals(certRecord.getInstanceId(), "instance-id");
assertEquals(certRecord.getPrincipals(), "host1,host2");
assertEquals(certRecord.getClientIP(), "10.1.1.1");
assertEquals(certRecord.getPrivateIP(), "10.1.1.2");
}
use of com.yahoo.athenz.common.server.ssh.SSHCertRecord in project athenz by yahoo.
the class JDBCSSHRecordStoreConnectionTest method testInsertSSHRecordException.
@Test
public void testInsertSSHRecordException() throws Exception {
JDBCSSHRecordStoreConnection jdbcConn = new JDBCSSHRecordStoreConnection(mockConn);
SSHCertRecord certRecord = new SSHCertRecord();
certRecord.setInstanceId("id1");
certRecord.setService("athenz.api");
certRecord.setPrivateIP("10.10.10.11");
certRecord.setClientIP("10.10.10.12");
certRecord.setPrincipals("host1");
Mockito.doThrow(new SQLException("error", "state", 503)).when(mockPrepStmt).executeUpdate();
try {
jdbcConn.insertSSHCertRecord(certRecord);
fail();
} catch (ResourceException ex) {
assertEquals(ex.getCode(), 500);
}
jdbcConn.close();
}
use of com.yahoo.athenz.common.server.ssh.SSHCertRecord in project athenz by yahoo.
the class JDBCSSHRecordStoreConnectionTest method testUpdateSSHRecord.
@Test
public void testUpdateSSHRecord() throws Exception {
JDBCSSHRecordStoreConnection jdbcConn = new JDBCSSHRecordStoreConnection(mockConn);
SSHCertRecord certRecord = new SSHCertRecord();
certRecord.setInstanceId("id1");
certRecord.setService("athenz.api");
certRecord.setPrivateIP("10.10.10.11");
certRecord.setClientIP("10.10.10.12");
certRecord.setPrincipals("host1");
Mockito.doReturn(1).when(mockPrepStmt).executeUpdate();
boolean requestSuccess = jdbcConn.updateSSHCertRecord(certRecord);
assertTrue(requestSuccess);
Mockito.verify(mockPrepStmt, times(1)).setString(1, "host1");
Mockito.verify(mockPrepStmt, times(1)).setString(2, "10.10.10.12");
Mockito.verify(mockPrepStmt, times(1)).setString(3, "10.10.10.11");
Mockito.verify(mockPrepStmt, times(1)).setString(4, "id1");
Mockito.verify(mockPrepStmt, times(1)).setString(5, "athenz.api");
jdbcConn.close();
}
Aggregations