aboutsummaryrefslogtreecommitdiffstats
path: root/configserver/src/main/java/com/yahoo
diff options
context:
space:
mode:
authorMorten Tokle <mortent@yahooinc.com>2024-02-13 13:58:51 +0100
committerMorten Tokle <mortent@yahooinc.com>2024-02-13 14:06:27 +0100
commit05ab6800a9a9d2119aba89b2bf9d15aa29b11a48 (patch)
tree798fb3ef69c3d9447d04967e8332aefc673e1f6e /configserver/src/main/java/com/yahoo
parent283af757b42ccb5ac6bfa8339a0a0674ae51c733 (diff)
Proxy endpoint certificate secrets through EndpointCertificateSecretStore
Diffstat (limited to 'configserver/src/main/java/com/yahoo')
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java9
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java13
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java9
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/tenant/DefaultEndpointCertificateSecretStore.java44
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/tenant/EndpointCertificateRetriever.java30
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java19
6 files changed, 103 insertions, 21 deletions
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java
index ad785a33d5b..5017f25b2f8 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java
@@ -6,6 +6,7 @@ import com.yahoo.cloud.config.ConfigserverConfig;
import com.yahoo.component.Version;
import com.yahoo.config.application.api.ApplicationPackage;
import com.yahoo.config.model.api.ConfigDefinitionRepo;
+import com.yahoo.config.model.api.EndpointCertificateSecretStore;
import com.yahoo.config.model.api.Model;
import com.yahoo.config.model.api.ModelContext;
import com.yahoo.config.model.api.ModelFactory;
@@ -39,6 +40,7 @@ import com.yahoo.vespa.model.container.ApplicationContainerCluster;
import com.yahoo.vespa.model.content.cluster.ContentCluster;
import java.util.Comparator;
+import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
@@ -65,6 +67,7 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> {
private final SecretStore secretStore;
private final ExecutorService executor;
private final OnnxModelCost onnxModelCost;
+ private final List<EndpointCertificateSecretStore> endpointCertificateSecretStores;
public ActivatedModelsBuilder(TenantName tenant,
long applicationGeneration,
@@ -80,7 +83,8 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> {
Zone zone,
ModelFactoryRegistry modelFactoryRegistry,
ConfigDefinitionRepo configDefinitionRepo,
- OnnxModelCost onnxModelCost) {
+ OnnxModelCost onnxModelCost,
+ List<EndpointCertificateSecretStore> endpointCertificateSecretStores) {
super(modelFactoryRegistry, configserverConfig, zone, hostProvisionerProvider, new SilentDeployLogger());
this.tenant = tenant;
this.applicationGeneration = applicationGeneration;
@@ -93,6 +97,7 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> {
this.secretStore = secretStore;
this.executor = executor;
this.onnxModelCost = onnxModelCost;
+ this.endpointCertificateSecretStores = endpointCertificateSecretStores;
}
@Override
@@ -160,7 +165,7 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> {
LegacyFlags.from(applicationPackage, flagSource),
new EndpointCertificateMetadataStore(curator, TenantRepository.getTenantPath(tenant))
.readEndpointCertificateMetadata(applicationId)
- .flatMap(new EndpointCertificateRetriever(secretStore)::readEndpointCertificateSecrets),
+ .flatMap(new EndpointCertificateRetriever(endpointCertificateSecretStores)::readEndpointCertificateSecrets),
zkClient.readAthenzDomain(),
zkClient.readQuota(),
zkClient.readTenantSecretStores(),
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java
index b3772127636..fffa77fc419 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java
@@ -16,6 +16,7 @@ import com.yahoo.config.application.api.FileRegistry;
import com.yahoo.config.model.api.ConfigDefinitionRepo;
import com.yahoo.config.model.api.ContainerEndpoint;
import com.yahoo.config.model.api.EndpointCertificateMetadata;
+import com.yahoo.config.model.api.EndpointCertificateSecretStore;
import com.yahoo.config.model.api.EndpointCertificateSecrets;
import com.yahoo.config.model.api.FileDistribution;
import com.yahoo.config.model.api.OnnxModelCost;
@@ -95,6 +96,7 @@ public class SessionPreparer {
private final ExecutorService executor;
private final BooleanFlag writeSessionData;
private final OnnxModelCost onnxModelCost;
+ private final List<EndpointCertificateSecretStore> endpointCertificateSecretStores;
public SessionPreparer(ModelFactoryRegistry modelFactoryRegistry,
FileDistributionFactory fileDistributionFactory,
@@ -106,7 +108,8 @@ public class SessionPreparer {
Zone zone,
FlagSource flagSource,
SecretStore secretStore,
- OnnxModelCost onnxModelCost) {
+ OnnxModelCost onnxModelCost,
+ List<EndpointCertificateSecretStore> endpointCertificateSecretStores) {
this.modelFactoryRegistry = modelFactoryRegistry;
this.fileDistributionFactory = fileDistributionFactory;
this.hostProvisionerProvider = hostProvisionerProvider;
@@ -119,6 +122,7 @@ public class SessionPreparer {
this.executor = executor;
this.writeSessionData = Flags.WRITE_CONFIG_SERVER_SESSION_DATA_AS_ONE_BLOB.bindTo(flagSource);
this.onnxModelCost = onnxModelCost;
+ this.endpointCertificateSecretStores = endpointCertificateSecretStores;
}
ExecutorService getExecutor() { return executor; }
@@ -139,7 +143,7 @@ public class SessionPreparer {
Preparation preparation = new Preparation(hostValidator, logger, params, activeApplicationVersions,
TenantRepository.getTenantPath(applicationId.tenant()),
serverDbSessionDir, applicationPackage, sessionZooKeeperClient,
- onnxModelCost);
+ onnxModelCost, endpointCertificateSecretStores);
preparation.preprocess();
try {
AllocatedHosts allocatedHosts = preparation.buildModels(now);
@@ -191,7 +195,8 @@ public class SessionPreparer {
Preparation(HostValidator hostValidator, DeployLogger logger, PrepareParams params,
Optional<ApplicationVersions> activeApplicationVersions, Path tenantPath,
File serverDbSessionDir, ApplicationPackage applicationPackage,
- SessionZooKeeperClient sessionZooKeeperClient, OnnxModelCost onnxModelCost) {
+ SessionZooKeeperClient sessionZooKeeperClient, OnnxModelCost onnxModelCost,
+ List<EndpointCertificateSecretStore> endpointCertificateSecretStores) {
this.logger = logger;
this.params = params;
this.applicationPackage = applicationPackage;
@@ -201,7 +206,7 @@ public class SessionPreparer {
this.vespaVersion = params.vespaVersion().orElse(Vtag.currentVersion);
this.containerEndpointsCache = new ContainerEndpointsCache(tenantPath, curator);
this.endpointCertificateMetadataStore = new EndpointCertificateMetadataStore(curator, tenantPath);
- EndpointCertificateRetriever endpointCertificateRetriever = new EndpointCertificateRetriever(secretStore);
+ EndpointCertificateRetriever endpointCertificateRetriever = new EndpointCertificateRetriever(endpointCertificateSecretStores);
this.endpointCertificateMetadata = params.endpointCertificateMetadata();
Optional<EndpointCertificateSecrets> endpointCertificateSecrets = endpointCertificateMetadata
.or(() -> endpointCertificateMetadataStore.readEndpointCertificateMetadata(applicationId))
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java
index 2f0d8b4065d..546277c4aba 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java
@@ -9,6 +9,7 @@ import com.yahoo.concurrent.StripedExecutor;
import com.yahoo.config.application.api.ApplicationPackage;
import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.config.model.api.ConfigDefinitionRepo;
+import com.yahoo.config.model.api.EndpointCertificateSecretStore;
import com.yahoo.config.model.api.OnnxModelCost;
import com.yahoo.config.model.application.provider.DeployData;
import com.yahoo.config.model.application.provider.FilesApplicationPackage;
@@ -121,6 +122,7 @@ public class SessionRepository {
private final Path sessionsPath;
private final TenantName tenantName;
private final OnnxModelCost onnxModelCost;
+ private final List<EndpointCertificateSecretStore> endpointCertificateSecretStores;
private final SessionCounter sessionCounter;
private final SecretStore secretStore;
private final HostProvisionerProvider hostProvisionerProvider;
@@ -152,9 +154,11 @@ public class SessionRepository {
ModelFactoryRegistry modelFactoryRegistry,
ConfigDefinitionRepo configDefinitionRepo,
int maxNodeSize,
- OnnxModelCost onnxModelCost) {
+ OnnxModelCost onnxModelCost,
+ List<EndpointCertificateSecretStore> endpointCertificateSecretStores) {
this.tenantName = tenantName;
this.onnxModelCost = onnxModelCost;
+ this.endpointCertificateSecretStores = endpointCertificateSecretStores;
sessionCounter = new SessionCounter(curator, tenantName);
this.sessionsPath = TenantRepository.getSessionsPath(tenantName);
this.clock = clock;
@@ -561,7 +565,8 @@ public class SessionRepository {
zone,
modelFactoryRegistry,
configDefinitionRepo,
- onnxModelCost);
+ onnxModelCost,
+ endpointCertificateSecretStores);
return ApplicationVersions.fromList(builder.buildModels(session.getApplicationId(),
session.getDockerImageRepository(),
session.getVespaVersion(),
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/DefaultEndpointCertificateSecretStore.java b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/DefaultEndpointCertificateSecretStore.java
new file mode 100644
index 00000000000..575fd155bdd
--- /dev/null
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/DefaultEndpointCertificateSecretStore.java
@@ -0,0 +1,44 @@
+// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+package com.yahoo.vespa.config.server.tenant;
+
+import com.yahoo.config.model.api.EndpointCertificateMetadata;
+import com.yahoo.config.model.api.EndpointCertificateSecretStore;
+import com.yahoo.container.jdisc.secretstore.SecretNotFoundException;
+import com.yahoo.container.jdisc.secretstore.SecretStore;
+
+import javax.inject.Inject;
+import java.util.Optional;
+
+public class DefaultEndpointCertificateSecretStore extends EndpointCertificateSecretStore {
+
+ private final SecretStore secretStore;
+
+ @Inject
+ public DefaultEndpointCertificateSecretStore(SecretStore secretStore) {
+ this.secretStore = secretStore;
+ }
+
+
+ @Override
+ public Optional<String> getPrivateKey(EndpointCertificateMetadata metadata) {
+ return getValue(metadata.keyName(), metadata.version());
+ }
+
+ @Override
+ public Optional<String> getCertificate(EndpointCertificateMetadata metadata) {
+ return getValue(metadata.certName(), metadata.version());
+ }
+
+ private Optional<String> getValue(String key, int version) {
+ try {
+ return Optional.ofNullable(secretStore.getSecret(key, version));
+ } catch (SecretNotFoundException e) {
+ return Optional.empty();
+ }
+ }
+ @Override
+ public boolean supports(EndpointCertificateMetadata.Provider provider) {
+ return provider == EndpointCertificateMetadata.Provider.digicert || provider == EndpointCertificateMetadata.Provider.globalsign;
+ }
+}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/EndpointCertificateRetriever.java b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/EndpointCertificateRetriever.java
index 10f59290572..43baac8fec9 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/EndpointCertificateRetriever.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/EndpointCertificateRetriever.java
@@ -2,14 +2,17 @@
package com.yahoo.vespa.config.server.tenant;
import com.yahoo.config.model.api.EndpointCertificateMetadata;
+import com.yahoo.config.model.api.EndpointCertificateSecretStore;
import com.yahoo.config.model.api.EndpointCertificateSecrets;
import com.yahoo.container.jdisc.secretstore.SecretStore;
import com.yahoo.security.KeyUtils;
import com.yahoo.security.X509CertificateUtils;
+import com.yahoo.stream.CustomCollectors;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
+import java.util.List;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -19,7 +22,13 @@ import java.util.logging.Logger;
*
* @author andreer
*/
-public record EndpointCertificateRetriever(SecretStore secretStore) {
+public class EndpointCertificateRetriever {
+
+ private final List<EndpointCertificateSecretStore> secretStores;
+
+ public EndpointCertificateRetriever(List<EndpointCertificateSecretStore> secretStores) {
+ this.secretStores = List.copyOf(secretStores);
+ }
private static final Logger log = Logger.getLogger(EndpointCertificateRetriever.class.getName());
@@ -29,12 +38,17 @@ public record EndpointCertificateRetriever(SecretStore secretStore) {
private EndpointCertificateSecrets readFromSecretStore(EndpointCertificateMetadata endpointCertificateMetadata) {
try {
- String cert = secretStore.getSecret(endpointCertificateMetadata.certName(), endpointCertificateMetadata.version());
- String key = secretStore.getSecret(endpointCertificateMetadata.keyName(), endpointCertificateMetadata.version());
+ EndpointCertificateSecrets endpointCertificateSecrets = secretStores.stream()
+ .filter(store -> store.supports(endpointCertificateMetadata.issuer()))
+ .collect(CustomCollectors.singleton())
+ .orElseThrow(() -> new RuntimeException("No provider of secrets for issuer " + endpointCertificateMetadata.issuer()))
+ .getSecret(endpointCertificateMetadata);
- verifyKeyMatchesCertificate(endpointCertificateMetadata, cert, key);
+ if (endpointCertificateSecrets.isMissing())
+ return endpointCertificateSecrets;
- return new EndpointCertificateSecrets(cert, key, endpointCertificateMetadata.version());
+ verifyKeyMatchesCertificate(endpointCertificateMetadata, endpointCertificateSecrets);
+ return endpointCertificateSecrets;
} catch (RuntimeException e) {
log.log(Level.WARNING, "Exception thrown during certificate retrieval", e);
// Assume not ready yet
@@ -42,10 +56,10 @@ public record EndpointCertificateRetriever(SecretStore secretStore) {
}
}
- private void verifyKeyMatchesCertificate(EndpointCertificateMetadata endpointCertificateMetadata, String cert, String key) {
- X509Certificate x509Certificate = X509CertificateUtils.fromPem(cert);
+ private void verifyKeyMatchesCertificate(EndpointCertificateMetadata endpointCertificateMetadata, EndpointCertificateSecrets endpointCertificateSecrets) {
+ X509Certificate x509Certificate = X509CertificateUtils.fromPem(endpointCertificateSecrets.certificate());
- PrivateKey privateKey = KeyUtils.fromPemEncodedPrivateKey(key);
+ PrivateKey privateKey = KeyUtils.fromPemEncodedPrivateKey(endpointCertificateSecrets.key());
PublicKey publicKey = x509Certificate.getPublicKey();
if(!X509CertificateUtils.privateKeyMatchesPublicKey(privateKey, publicKey)) {
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java
index 895c9819a03..8c4445f897c 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantRepository.java
@@ -5,12 +5,14 @@ import com.google.common.collect.ImmutableSet;
import com.yahoo.cloud.config.ConfigserverConfig;
import com.yahoo.cloud.config.ZookeeperServerConfig;
import com.yahoo.component.annotation.Inject;
+import com.yahoo.component.provider.ComponentRegistry;
import com.yahoo.concurrent.DaemonThreadFactory;
import com.yahoo.concurrent.Lock;
import com.yahoo.concurrent.Locks;
import com.yahoo.concurrent.StripedExecutor;
import com.yahoo.concurrent.ThreadFactoryFactory;
import com.yahoo.config.model.api.ConfigDefinitionRepo;
+import com.yahoo.config.model.api.EndpointCertificateSecretStore;
import com.yahoo.config.model.api.OnnxModelCost;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.TenantName;
@@ -120,6 +122,7 @@ public class TenantRepository {
new ScheduledThreadPoolExecutor(1, new DaemonThreadFactory("check for removed applications"));
private final Curator.DirectoryCache directoryCache;
private final ZookeeperServerConfig zookeeperServerConfig;
+ private final List<EndpointCertificateSecretStore> endpointCertificateSecretStores;
private final OnnxModelCost onnxModelCost;
/**
@@ -141,7 +144,8 @@ public class TenantRepository {
TenantListener tenantListener,
ZookeeperServerConfig zookeeperServerConfig,
FileDirectory fileDirectory,
- OnnxModelCost onnxModelCost) {
+ OnnxModelCost onnxModelCost,
+ ComponentRegistry<EndpointCertificateSecretStore> endpointCertificateSecretStores) {
this(hostRegistry,
curator,
metrics,
@@ -161,7 +165,8 @@ public class TenantRepository {
configActivationListener,
tenantListener,
zookeeperServerConfig,
- onnxModelCost);
+ onnxModelCost,
+ endpointCertificateSecretStores.allComponents());
}
public TenantRepository(HostRegistry hostRegistry,
@@ -183,7 +188,8 @@ public class TenantRepository {
ConfigActivationListener configActivationListener,
TenantListener tenantListener,
ZookeeperServerConfig zookeeperServerConfig,
- OnnxModelCost onnxModelCost) {
+ OnnxModelCost onnxModelCost,
+ List<EndpointCertificateSecretStore> endpointCertificateSecretStores) {
this.hostRegistry = hostRegistry;
this.configserverConfig = configserverConfig;
this.curator = curator;
@@ -204,6 +210,7 @@ public class TenantRepository {
this.configActivationListener = configActivationListener;
this.tenantListener = tenantListener;
this.zookeeperServerConfig = zookeeperServerConfig;
+ this.endpointCertificateSecretStores = endpointCertificateSecretStores;
// This we should control with a feature flag.
this.deployHelperExecutor = createModelBuilderExecutor();
this.onnxModelCost = onnxModelCost;
@@ -360,7 +367,8 @@ public class TenantRepository {
zone,
flagSource,
secretStore,
- onnxModelCost);
+ onnxModelCost,
+ endpointCertificateSecretStores);
SessionRepository sessionRepository = new SessionRepository(tenantName,
applicationRepo,
sessionPreparer,
@@ -379,7 +387,8 @@ public class TenantRepository {
modelFactoryRegistry,
configDefinitionRepo,
zookeeperServerConfig.juteMaxBuffer(),
- onnxModelCost);
+ onnxModelCost,
+ endpointCertificateSecretStores);
log.log(Level.FINE, "Adding tenant '" + tenantName + "'" + ", created " + created +
". Bootstrapping in " + Duration.between(start, clock.instant()));
Tenant tenant = new Tenant(tenantName, sessionRepository, applicationRepo, created);