diff options
author | Harald Musum <musum@verizonmedia.com> | 2020-05-28 18:31:38 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-28 18:31:38 +0200 |
commit | ab6c2c71d7d98120b09345b8e2cc59ec8374bb89 (patch) | |
tree | 78f5fcf60e8ce01af7c04b2b9b334ca0da4dbffb /vespa-athenz | |
parent | fd776f01675f8e86a03e07e98fd84cf5ba5f4372 (diff) |
Revert "Expose underlying certificate and private key from SiaIdentityProvider "
Diffstat (limited to 'vespa-athenz')
6 files changed, 63 insertions, 122 deletions
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identity/ServiceIdentityProvider.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identity/ServiceIdentityProvider.java index f6888acb018..e5ed885b316 100644 --- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identity/ServiceIdentityProvider.java +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identity/ServiceIdentityProvider.java @@ -2,56 +2,18 @@ package com.yahoo.vespa.athenz.identity; import com.yahoo.container.jdisc.athenz.AthenzIdentityProvider; -import com.yahoo.security.X509CertificateWithKey; import com.yahoo.vespa.athenz.api.AthenzIdentity; +import com.yahoo.vespa.athenz.api.AthenzService; import javax.net.ssl.SSLContext; -import java.nio.file.Path; /** - * A interface for types that provides the Athenz service identity (SIA) from the environment. - * Some similarities to {@link AthenzIdentityProvider}, but this type is not public API and intended for internal use. + * A interface for types that provides a service identity. + * Some similarities to {@link AthenzIdentityProvider}, but this type is not public api and intended for internal use. * * @author bjorncs */ public interface ServiceIdentityProvider { - /** - * - * @return The Athenz identity of the environment - */ AthenzIdentity identity(); - - /** - * @return {@link SSLContext} that is automatically updated. - */ SSLContext getIdentitySslContext(); - - /** - * @return Current certificate and private key. Unlike {@link #getIdentitySslContext()} underlying credentials are not automatically updated. - */ - X509CertificateWithKey getIdentityCertificateWithKey(); - - /** - * @return Path to X.509 certificate in PEM format - */ - Path certificatePath(); - - /** - * @return Path to private key in PEM format - */ - Path privateKeyPath(); - - /** - * @return Path to Athenz truststore in PEM format - */ - Path athenzTruststorePath(); - - /** - * The client truststore contains the Athenz certificates from {@link #athenzTruststorePath()} - * and additional certificate authorities that issues trusted server certificates. - * - * @return Path to client truststore in PEM format - */ - Path clientTruststorePath(); - } diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identity/SiaIdentityProvider.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identity/SiaIdentityProvider.java index a2a773ac751..4981b80998f 100644 --- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identity/SiaIdentityProvider.java +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identity/SiaIdentityProvider.java @@ -3,14 +3,15 @@ package com.yahoo.vespa.athenz.identity; import com.google.inject.Inject; import com.yahoo.component.AbstractComponent; +import com.yahoo.security.KeyStoreType; import com.yahoo.security.SslContextBuilder; -import com.yahoo.security.X509CertificateWithKey; import com.yahoo.security.tls.AutoReloadingX509KeyManager; import com.yahoo.vespa.athenz.api.AthenzIdentity; import com.yahoo.vespa.athenz.api.AthenzService; import com.yahoo.vespa.athenz.utils.SiaUtils; import javax.net.ssl.SSLContext; +import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; @@ -25,43 +26,34 @@ public class SiaIdentityProvider extends AbstractComponent implements ServiceIde private final AutoReloadingX509KeyManager keyManager; private final SSLContext sslContext; private final AthenzIdentity service; - private final Path certificateFile; - private final Path privateKeyFile; - private final Path clientTruststoreFile; - private final Path athenzTruststoreFile; @Inject public SiaIdentityProvider(SiaProviderConfig config) { this(new AthenzService(config.athenzDomain(), config.athenzService()), - SiaUtils.getPrivateKeyFile(Paths.get(config.keyPathPrefix()), new AthenzService(config.athenzDomain(), config.athenzService())), - SiaUtils.getCertificateFile(Paths.get(config.keyPathPrefix()), new AthenzService(config.athenzDomain(), config.athenzService())), - Paths.get(config.trustStorePath()), - Paths.get(config.athenzTruststorePath())); + SiaUtils.getPrivateKeyFile(Paths.get(config.keyPathPrefix()), new AthenzService(config.athenzDomain(), config.athenzService())).toFile(), + SiaUtils.getCertificateFile(Paths.get(config.keyPathPrefix()), new AthenzService(config.athenzDomain(), config.athenzService())).toFile(), + new File(config.trustStorePath()), + config.trustStoreType()); } public SiaIdentityProvider(AthenzIdentity service, Path siaPath, - Path clientTruststoreFile, - Path athenzTruststoreFile) { + File trustStoreFile) { this(service, - SiaUtils.getPrivateKeyFile(siaPath, service), - SiaUtils.getCertificateFile(siaPath, service), - athenzTruststoreFile, - clientTruststoreFile); + SiaUtils.getPrivateKeyFile(siaPath, service).toFile(), + SiaUtils.getCertificateFile(siaPath, service).toFile(), + trustStoreFile, + SiaProviderConfig.TrustStoreType.Enum.jks); } public SiaIdentityProvider(AthenzIdentity service, - Path privateKeyFile, - Path certificateFile, - Path athenzTruststoreFile, - Path clientTruststoreFile) { + File privateKeyFile, + File certificateFile, + File trustStoreFile, + SiaProviderConfig.TrustStoreType.Enum trustStoreType) { this.service = service; - this.keyManager = AutoReloadingX509KeyManager.fromPemFiles(privateKeyFile, certificateFile); - this.sslContext = createIdentitySslContext(keyManager, clientTruststoreFile); - this.certificateFile = certificateFile; - this.privateKeyFile = privateKeyFile; - this.athenzTruststoreFile = athenzTruststoreFile; - this.clientTruststoreFile = clientTruststoreFile; + this.keyManager = AutoReloadingX509KeyManager.fromPemFiles(privateKeyFile.toPath(), certificateFile.toPath()); + this.sslContext = createIdentitySslContext(keyManager, trustStoreFile.toPath(), trustStoreType); } @Override @@ -74,17 +66,17 @@ public class SiaIdentityProvider extends AbstractComponent implements ServiceIde return sslContext; } - @Override public X509CertificateWithKey getIdentityCertificateWithKey() { return keyManager.getCurrentCertificateWithKey(); } - @Override public Path certificatePath() { return certificateFile; } - @Override public Path privateKeyPath() { return privateKeyFile; } - @Override public Path athenzTruststorePath() { return athenzTruststoreFile; } - @Override public Path clientTruststorePath() { return clientTruststoreFile; } - - private static SSLContext createIdentitySslContext(AutoReloadingX509KeyManager keyManager, Path trustStoreFile) { - return new SslContextBuilder() - .withTrustStore(trustStoreFile) - .withKeyManager(keyManager) - .build(); + private static SSLContext createIdentitySslContext(AutoReloadingX509KeyManager keyManager, Path trustStoreFile, + SiaProviderConfig.TrustStoreType.Enum trustStoreType) { + var builder = new SslContextBuilder(); + if (trustStoreType == SiaProviderConfig.TrustStoreType.Enum.pem) { + builder = builder.withTrustStore(trustStoreFile); + } else if (trustStoreType == SiaProviderConfig.TrustStoreType.Enum.jks) { + builder = builder.withTrustStore(trustStoreFile, KeyStoreType.JKS); + } else { + throw new IllegalArgumentException("Unsupported trust store type: " + trustStoreType); + } + return builder.withKeyManager(keyManager).build(); } @Override diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzCredentialsService.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzCredentialsService.java index 8e029906c30..3b733e05708 100644 --- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzCredentialsService.java +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzCredentialsService.java @@ -64,9 +64,6 @@ class AthenzCredentialsService { this.clock = clock; } - Path certificatePath() { return SiaUtils.getCertificateFile(VESPA_SIA_DIRECTORY, tenantIdentity); } - Path privateKeyPath() { return SiaUtils.getPrivateKeyFile(VESPA_SIA_DIRECTORY, tenantIdentity); } - AthenzCredentials registerInstance() { Optional<AthenzCredentials> athenzCredentialsFromDisk = tryReadCredentialsFromDisk(); if (athenzCredentialsFromDisk.isPresent()) { diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java index 62c5820c927..b816acfad38 100644 --- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java @@ -11,9 +11,9 @@ import com.yahoo.container.jdisc.athenz.AthenzIdentityProvider; import com.yahoo.container.jdisc.athenz.AthenzIdentityProviderException; import com.yahoo.jdisc.Metric; import com.yahoo.security.KeyStoreBuilder; +import com.yahoo.security.KeyStoreType; import com.yahoo.security.Pkcs10Csr; import com.yahoo.security.SslContextBuilder; -import com.yahoo.security.X509CertificateWithKey; import com.yahoo.security.tls.MutableX509KeyManager; import com.yahoo.vespa.athenz.api.AthenzAccessToken; import com.yahoo.vespa.athenz.api.AthenzDomain; @@ -47,6 +47,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; +import static com.yahoo.security.KeyStoreType.JKS; import static com.yahoo.security.KeyStoreType.PKCS12; /** @@ -55,8 +56,6 @@ import static com.yahoo.security.KeyStoreType.PKCS12; * @author mortent * @author bjorncs */ -// This class should probably not implement ServiceIdentityProvider, -// as that interface is intended for providing the node's identity, not the tenant's application identity. public final class AthenzIdentityProviderImpl extends AbstractComponent implements AthenzIdentityProvider, ServiceIdentityProvider { private static final Logger log = Logger.getLogger(AthenzIdentityProviderImpl.class.getName()); @@ -68,9 +67,8 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen private final static Duration ROLE_SSL_CONTEXT_EXPIRY = Duration.ofHours(24); private final static Duration ROLE_TOKEN_EXPIRY = Duration.ofMinutes(30); - // TODO Make path to trust store paths config - private static final Path CLIENT_TRUST_STORE = Paths.get("/opt/yahoo/share/ssl/certs/yahoo_certificate_bundle.pem"); - private static final Path ATHENZ_TRUST_STORE = Paths.get("/opt/yahoo/share/ssl/certs/athenz_certificate_bundle.pem"); + // TODO Make path to trust store config + private static final Path DEFAULT_TRUST_STORE = Paths.get("/opt/yahoo/share/ssl/certs/yahoo_certificate_bundle.jks"); public static final String CERTIFICATE_EXPIRY_METRIC_NAME = "athenz-tenant-cert.expiry.seconds"; @@ -96,9 +94,9 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen public AthenzIdentityProviderImpl(IdentityConfig config, Metric metric) { this(config, metric, - CLIENT_TRUST_STORE, + DEFAULT_TRUST_STORE, new AthenzCredentialsService(config, - createNodeIdentityProvider(config), + createNodeIdentityProvider(config, DEFAULT_TRUST_STORE), Defaults.getDefaults().vespaHostname(), Clock.systemUTC()), new ScheduledThreadPoolExecutor(1), @@ -144,7 +142,7 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen private static SSLContext createIdentitySslContext(X509ExtendedKeyManager keyManager, Path trustStore) { return new SslContextBuilder() .withKeyManager(keyManager) - .withTrustStore(trustStore) + .withTrustStore(trustStore, JKS) .build(); } @@ -179,20 +177,6 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen } @Override - public X509CertificateWithKey getIdentityCertificateWithKey() { - AthenzCredentials copy = this.credentials; - return new X509CertificateWithKey(copy.getCertificate(), copy.getKeyPair().getPrivate()); - } - - @Override public Path certificatePath() { return athenzCredentialsService.certificatePath(); } - - @Override public Path privateKeyPath() { return athenzCredentialsService.privateKeyPath(); } - - @Override public Path athenzTruststorePath() { return ATHENZ_TRUST_STORE; } - - @Override public Path clientTruststorePath() { return CLIENT_TRUST_STORE; } - - @Override public SSLContext getRoleSslContext(String domain, String role) { // This ssl context should ideally be cached as it is quite expensive to create. try { @@ -271,7 +255,7 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen X509Certificate roleCertificate = client.getRoleCertificate(role, csr); return new SslContextBuilder() .withKeyStore(credentials.getKeyPair().getPrivate(), roleCertificate) - .withTrustStore(trustStore) + .withTrustStore(trustStore, KeyStoreType.JKS) .build(); } } @@ -314,9 +298,9 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen } } - private static SiaIdentityProvider createNodeIdentityProvider(IdentityConfig config) { + private static SiaIdentityProvider createNodeIdentityProvider(IdentityConfig config, Path trustStore) { return new SiaIdentityProvider( - new AthenzService(config.nodeIdentityName()), SiaUtils.DEFAULT_SIA_DIRECTORY, CLIENT_TRUST_STORE, ATHENZ_TRUST_STORE); + new AthenzService(config.nodeIdentityName()), SiaUtils.DEFAULT_SIA_DIRECTORY, trustStore.toFile()); } private boolean isExpired(AthenzCredentials credentials) { diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/SiaUtils.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/SiaUtils.java index 894c04df233..12a8c3f911e 100644 --- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/SiaUtils.java +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/utils/SiaUtils.java @@ -53,11 +53,10 @@ public class SiaUtils { } public static Path getCaCertificatesFile() { - return getCaCertificatesFile(DEFAULT_SIA_DIRECTORY); - } - - public static Path getCaCertificatesFile(Path root) { - return root.resolve("certs").resolve("ca.cert.pem"); + // The contents of this is the same as /opt/yahoo/share/ssl/certs/athenz_certificate_bundle.pem installed + // by the yahoo_certificates_bundle RPM package, except the latter also contains a textual description + // (decoded) of the certificates. + return DEFAULT_SIA_DIRECTORY.resolve("certs").resolve("ca.cert.pem"); } public static Optional<PrivateKey> readPrivateKeyFile(AthenzIdentity service) { diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identity/SiaIdentityProviderTest.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identity/SiaIdentityProviderTest.java index b7db502b1d0..ce02860cc78 100644 --- a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identity/SiaIdentityProviderTest.java +++ b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identity/SiaIdentityProviderTest.java @@ -2,11 +2,15 @@ package com.yahoo.vespa.athenz.identity; import com.yahoo.security.KeyAlgorithm; +import com.yahoo.security.KeyStoreBuilder; +import com.yahoo.security.KeyStoreType; +import com.yahoo.security.KeyStoreUtils; import com.yahoo.security.KeyUtils; import com.yahoo.security.SignatureAlgorithm; import com.yahoo.security.X509CertificateBuilder; import com.yahoo.security.X509CertificateUtils; import com.yahoo.vespa.athenz.api.AthenzService; +import com.yahoo.yolean.Exceptions; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -17,11 +21,11 @@ import java.io.IOException; import java.math.BigInteger; import java.nio.file.Files; import java.security.KeyPair; +import java.security.KeyStore; import java.security.cert.X509Certificate; import java.time.Duration; import java.time.Instant; -import static com.yahoo.yolean.Exceptions.uncheck; import static org.junit.Assert.assertNotNull; /** @@ -48,10 +52,10 @@ public class SiaIdentityProviderTest { SiaIdentityProvider provider = new SiaIdentityProvider( new AthenzService("domain", "service-name"), - keyFile.toPath(), - certificateFile.toPath(), - trustStoreFile.toPath(), - trustStoreFile.toPath()); + keyFile, + certificateFile, + trustStoreFile, + SiaProviderConfig.TrustStoreType.Enum.jks); assertNotNull(provider.getIdentitySslContext()); } @@ -72,10 +76,10 @@ public class SiaIdentityProviderTest { SiaIdentityProvider provider = new SiaIdentityProvider( new AthenzService("domain", "service-name"), - keyFile.toPath(), - certificateFile.toPath(), - trustStoreFile.toPath(), - trustStoreFile.toPath()); + keyFile, + certificateFile, + trustStoreFile, + SiaProviderConfig.TrustStoreType.Enum.pem); assertNotNull(provider.getIdentitySslContext()); } @@ -105,11 +109,14 @@ public class SiaIdentityProviderTest { private void createPemTrustStoreFile(X509Certificate certificate, File trustStoreFile) { var pemEncoded = X509CertificateUtils.toPem(certificate); - uncheck(() -> Files.writeString(trustStoreFile.toPath(), pemEncoded)); + Exceptions.uncheck(() -> Files.writeString(trustStoreFile.toPath(), pemEncoded)); } private void createTrustStoreFile(X509Certificate certificate, File trustStoreFile) { - uncheck(() -> Files.writeString(trustStoreFile.toPath(), X509CertificateUtils.toPem(certificate))); + KeyStore keystore = KeyStoreBuilder.withType(KeyStoreType.JKS) + .withCertificateEntry("dummy-cert", certificate) + .build(); + KeyStoreUtils.writeKeyStoreToFile(keystore, trustStoreFile.toPath()); } } |