Skip to content

Commit

Permalink
add support to provide server-side bundles per key-id (#2796)
Browse files Browse the repository at this point in the history
Signed-off-by: Henry Avetisyan <[email protected]>
  • Loading branch information
havetisyan authored Nov 12, 2024
1 parent d04a6ff commit c2c242d
Show file tree
Hide file tree
Showing 7 changed files with 410 additions and 24 deletions.
30 changes: 27 additions & 3 deletions servers/zts/conf/zts.properties
Original file line number Diff line number Diff line change
Expand Up @@ -383,23 +383,47 @@ athenz.zts.cert_signer_factory_class=com.yahoo.athenz.zts.cert.impl.SelfCertSign
# CA certificates. This is useful when there are multiple Athenz instances
# running in different regions/locations and each region/location has its own
# CA certificate and during instance register/refresh operation we want to
# return the full set of CA certs
# return the full set of CA certs. This is considered as the default
# CA certificate bundle file name. The admin can also specify additional
# bundles per key-id using the athenz.zts.x509_ca_cert_keyid_fname
# system property.
#athenz.zts.x509_ca_cert_fname=

# If configured, specifies a file names that contains the bundle of Athenz
# CA certificates for a given key-id. The format of the value is comma
# separated list of <key-id>:<bundle-filename> values.
#athenz.zts.x509_ca_cert_keyid_fname=

# If configured, specifies a file name that contains the SSH Host certificate
# Signer certificates. This is useful when there are multiple Athenz instances
# running in different regions/locations and each region/location has its own
# Signer certificate and during instance register/refresh operation we want to
# return the full set of certs
# return the full set of certs. This is considered as the default
# certificate bundle file name. The admin can also specify additional
# bundles per key-id using the athenz.zts.ssh_host_ca_cert_keyid_fname
# system property.
#athenz.zts.ssh_host_ca_cert_fname=

# If configured, specifies a file names that contains the bundle of Athenz
# SSHCA certificates for a given key-id. The format of the value is comma
# separated list of <key-id>:<bundle-filename> values.
#athenz.zts.ssh_host_ca_cert_keyid_fname=

# If configured, specifies a file name that contains the SSH User certificate
# Signer certificates. This is useful when there are multiple Athenz instances
# running in different regions/locations and each region/location has its own
# Signer certificate and during instance register/refresh operation we want to
# return the full set of certs
# return the full set of certs. This is considered as the default
## certificate bundle file name. The admin can also specify additional
## bundles per key-id using the athenz.zts.ssh_user_ca_cert_keyid_fname
## system property.
#athenz.zts.ssh_user_ca_cert_fname=

# If configured, specifies a file names that contains the bundle of Athenz
# SSHCA certificates for a given key-id. The format of the value is comma
# separated list of <key-id>:<bundle-filename> values.
#athenz.zts.ssh_user_ca_cert_keyid_fname=

# The number of milliseconds to sleep between runs of the idle object
# evictor thread. When non-positive, no idle object evictor thread
# will be run. The pool default is -1, but we're using 30 minutes to
Expand Down
2 changes: 1 addition & 1 deletion servers/zts/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<packaging>war</packaging>

<properties>
<code.coverage.min>0.9875</code.coverage.min>
<code.coverage.min>0.9928</code.coverage.min>
</properties>

<dependencies>
Expand Down
17 changes: 10 additions & 7 deletions servers/zts/src/main/java/com/yahoo/athenz/zts/ZTSConsts.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,16 @@ public final class ZTSConsts {
public static final String ZTS_PROP_SYSTEM_AUTHZ_DETAILS_PATH = "athenz.zts.system_authz_details_path";
public static final String ZTS_PROP_SERVICE_CERT_DEFAULT_EXPIRY_MINS = "athenz.zts.service_cert_default_expiry_mins";

public static final String ZTS_PROP_PROVIDER_ENDPOINTS = "athenz.zts.provider_endpoints";
public static final String ZTS_PROP_INSTANCE_NTOKEN_TIMEOUT = "athenz.zts.instance_token_timeout";
public static final String ZTS_PROP_X509_CA_CERT_FNAME = "athenz.zts.x509_ca_cert_fname";
public static final String ZTS_PROP_SSH_HOST_CA_CERT_FNAME = "athenz.zts.ssh_host_ca_cert_fname";
public static final String ZTS_PROP_SSH_USER_CA_CERT_FNAME = "athenz.zts.ssh_user_ca_cert_fname";
public static final String ZTS_PROP_RESP_X509_SIGNER_CERTS = "athenz.zts.resp_x509_signer_certs";
public static final String ZTS_PROP_RESP_SSH_SIGNER_CERTS = "athenz.zts.resp_ssh_signer_certs";
public static final String ZTS_PROP_PROVIDER_ENDPOINTS = "athenz.zts.provider_endpoints";
public static final String ZTS_PROP_INSTANCE_NTOKEN_TIMEOUT = "athenz.zts.instance_token_timeout";
public static final String ZTS_PROP_X509_CA_CERT_FNAME = "athenz.zts.x509_ca_cert_fname";
public static final String ZTS_PROP_X509_CA_CERT_KEYID_FNAME = "athenz.zts.x509_ca_cert_keyid_fname";
public static final String ZTS_PROP_SSH_HOST_CA_CERT_FNAME = "athenz.zts.ssh_host_ca_cert_fname";
public static final String ZTS_PROP_SSH_HOST_CA_CERT_KEYID_FNAME = "athenz.zts.ssh_host_ca_cert_keyid_fname";
public static final String ZTS_PROP_SSH_USER_CA_CERT_FNAME = "athenz.zts.ssh_user_ca_cert_fname";
public static final String ZTS_PROP_SSH_USER_CA_CERT_KEYID_FNAME = "athenz.zts.ssh_user_ca_cert_keyid_fname";
public static final String ZTS_PROP_RESP_X509_SIGNER_CERTS = "athenz.zts.resp_x509_signer_certs";
public static final String ZTS_PROP_RESP_SSH_SIGNER_CERTS = "athenz.zts.resp_ssh_signer_certs";

public static final String DB_PROP_USER = "user";
public static final String DB_PROP_PASSWORD = "password";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,16 +200,13 @@ private boolean loadCertificateAuthorityBundles() {

// if we're not asked to skip sending certificate signers then
// check to see if we need to load them from files instead of
// certsigner directly
// cert-signer directly

if (responseSendX509SignerCerts) {
caX509CertificateSigner = loadCertificateBundle(ZTSConsts.ZTS_PROP_X509_CA_CERT_FNAME);
caX509ProviderCertificateSigners = new ConcurrentHashMap<>();
initializeX509ProviderCertificateSigners();
}
if (responseSendSSHSignerCerts) {
sshUserCertificateSigner = loadCertificateBundle(ZTSConsts.ZTS_PROP_SSH_USER_CA_CERT_FNAME);
sshHostCertificateSigner = loadCertificateBundle(ZTSConsts.ZTS_PROP_SSH_HOST_CA_CERT_FNAME);
caSshProviderCertificateSigners = new ConcurrentHashMap<>();
initializeSSHProviderCertificateSigners();
}

// now let's fetch our configured certificate authority bundles
Expand Down Expand Up @@ -252,6 +249,63 @@ private boolean loadCertificateAuthorityBundles() {
return true;
}

void initializeSSHProviderCertificateSigners() {

// first load our default ssh certificate signers that will be used
// if no key-id specific signer is available

sshUserCertificateSigner = loadCertificateBundle(ZTSConsts.ZTS_PROP_SSH_USER_CA_CERT_FNAME);
sshHostCertificateSigner = loadCertificateBundle(ZTSConsts.ZTS_PROP_SSH_HOST_CA_CERT_FNAME);

// initialize our provider bundle map and then check to see
// if we have configured key-id specific providers. These must
// be configured as a list of key-id:filename pairs

caSshProviderCertificateSigners = new ConcurrentHashMap<>();
iniitializeProviderCertificateSigners(caSshProviderCertificateSigners, ZTSConsts.ZTS_SSH_HOST,
ZTSConsts.ZTS_PROP_SSH_HOST_CA_CERT_KEYID_FNAME);
iniitializeProviderCertificateSigners(caSshProviderCertificateSigners, ZTSConsts.ZTS_SSH_USER,
ZTSConsts.ZTS_PROP_SSH_USER_CA_CERT_KEYID_FNAME);
}

void initializeX509ProviderCertificateSigners() {

// first load our default certificate bundle that will be used
// if no key-id specific bundle is available

caX509CertificateSigner = loadCertificateBundle(ZTSConsts.ZTS_PROP_X509_CA_CERT_FNAME);

// initialize our provider bundle map and then check to see
// if we have configured key-id specific providers. These must
// be configured as a list of key-id:filename pairs

caX509ProviderCertificateSigners = new ConcurrentHashMap<>();
iniitializeProviderCertificateSigners(caX509ProviderCertificateSigners, null,
ZTSConsts.ZTS_PROP_X509_CA_CERT_KEYID_FNAME);
}

void iniitializeProviderCertificateSigners(Map<String, String> certSigners, final String reqType, final String propName) {

final String providerKeyBundles = System.getProperty(propName, "");
for (String providerKeyBundle : providerKeyBundles.split(",")) {
if (providerKeyBundle.isEmpty()) {
continue;
}
String[] providerKey = providerKeyBundle.split(":");
if (providerKey.length != 2) {
throw new ResourceException(ResourceException.INTERNAL_SERVER_ERROR,
"Invalid provider certificate configuration value: " + propName + ": " + providerKeyBundle);
}
byte[] data = ZTSUtils.readFileContents(providerKey[1]);
if (data == null) {
throw new ResourceException(ResourceException.INTERNAL_SERVER_ERROR,
"Unable to load Certificate bundle from: " + providerKey[1]);
}
final String keyName = reqType == null ? providerKey[0] : reqType + "." + providerKey[0];
certSigners.put(keyName, new String(data));
}
}

private boolean processCertificateAuthorityBundle(CertBundle bundle) {

final String name = bundle.getName();
Expand Down Expand Up @@ -736,16 +790,22 @@ public String getX509CertificateSigner(final String provider, final String signe
return null;
}

if (caX509CertificateSigner != null) {
return caX509CertificateSigner;
}
// first check to see if we have a provider specific key configured

final String providerKeyName = getSignerPrimaryKey(provider, signerKeyId);
String certificateSigner = caX509ProviderCertificateSigners.get(providerKeyName);
if (certificateSigner != null) {
return certificateSigner;
}

// check to see if we have a default bundle configured

if (caX509CertificateSigner != null) {
return caX509CertificateSigner;
}

// fetch the bundle from the cert-signer and update our provider map

certificateSigner = getCACertificate(provider, signerKeyId);
if (certificateSigner != null) {
caX509ProviderCertificateSigners.put(providerKeyName, certificateSigner);
Expand Down Expand Up @@ -954,14 +1014,13 @@ String getSSHCertificateSigner(final String sshReqType, final String signerKeyId
return null;
}

String certificateSigner = sshReqType.equals(ZTSConsts.ZTS_SSH_HOST) ?
sshHostCertificateSigner : sshUserCertificateSigner;
final String primaryKeyName = sshReqType + "." + (StringUtil.isEmpty(signerKeyId) ? "default" : signerKeyId);
String certificateSigner = caSshProviderCertificateSigners.get(primaryKeyName);
if (certificateSigner != null) {
return certificateSigner;
}

final String primaryKeyName = sshReqType + "." + (StringUtil.isEmpty(signerKeyId) ? "default" : signerKeyId);
certificateSigner = caSshProviderCertificateSigners.get(primaryKeyName);
certificateSigner = sshReqType.equals(ZTSConsts.ZTS_SSH_HOST) ? sshHostCertificateSigner : sshUserCertificateSigner;
if (certificateSigner != null) {
return certificateSigner;
}
Expand Down
Loading

0 comments on commit c2c242d

Please sign in to comment.