summaryrefslogtreecommitdiffstats
path: root/config-model/src/main/java/com/yahoo
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@yahooinc.com>2023-07-18 15:55:54 +0200
committerBjørn Christian Seime <bjorncs@yahooinc.com>2023-07-19 16:12:37 +0200
commit172128afece1d218ad16f4b7415c1f2bf9663d08 (patch)
tree65980fab05cbe6b62115d0775898bf9c3518d389 /config-model/src/main/java/com/yahoo
parentb630d4ed852ba0ad802667995f3f8238db2c9c3f (diff)
Add separate connector for token endpoint
Diffstat (limited to 'config-model/src/main/java/com/yahoo')
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java7
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/CloudSslProvider.java12
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/HostedSslConnectorFactory.java2
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/CloudDataPlaneFilter.java18
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/CloudTokenDataPlaneFilter.java61
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java61
6 files changed, 117 insertions, 44 deletions
diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java
index 2b55b1f1d10..66a23c79fbb 100644
--- a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java
+++ b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java
@@ -88,6 +88,7 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea
private boolean allowMoreThanOneContentGroupDown = false;
private boolean enableConditionalPutRemoveWriteRepair = false;
private List<DataplaneToken> dataplaneTokens;
+ private boolean enableDataplaneProxy;
@Override public ModelContext.FeatureFlags featureFlags() { return this; }
@Override public boolean multitenant() { return multitenant; }
@@ -148,6 +149,7 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea
@Override public boolean allowMoreThanOneContentGroupDown(ClusterSpec.Id id) { return allowMoreThanOneContentGroupDown; }
@Override public boolean enableConditionalPutRemoveWriteRepair() { return enableConditionalPutRemoveWriteRepair; }
@Override public List<DataplaneToken> dataplaneTokens() { return dataplaneTokens; }
+ @Override public boolean enableDataplaneProxy() { return enableDataplaneProxy; }
public TestProperties sharedStringRepoNoReclaim(boolean sharedStringRepoNoReclaim) {
this.sharedStringRepoNoReclaim = sharedStringRepoNoReclaim;
@@ -393,6 +395,11 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea
return this;
}
+ public TestProperties setEnableDataplaneProxy(boolean enable) {
+ this.enableDataplaneProxy = enable;
+ return this;
+ }
+
public static class Spec implements ConfigServerSpec {
private final String hostName;
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/CloudSslProvider.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/CloudSslProvider.java
index b231a4ad847..ab163719aac 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/CloudSslProvider.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/CloudSslProvider.java
@@ -2,8 +2,6 @@
package com.yahoo.vespa.model.container.http.ssl;
import com.yahoo.jdisc.http.ConnectorConfig;
-import com.yahoo.jdisc.http.ssl.impl.CloudSslContextProvider;
-import com.yahoo.jdisc.http.ssl.impl.ConfiguredSslContextFactoryProvider;
import java.util.Optional;
@@ -16,10 +14,6 @@ import static com.yahoo.jdisc.http.ConnectorConfig.Ssl.ClientAuth;
* @author andreer
*/
public class CloudSslProvider extends SslProvider {
- public static final String COMPONENT_ID_PREFIX = "configured-ssl-provider@";
- public static final String MTLSONLY_COMPONENT_CLASS = ConfiguredSslContextFactoryProvider.class.getName();
- public static final String TOKEN_COMPONENT_CLASS = CloudSslContextProvider.class.getName();
-
private final String privateKey;
private final String certificate;
private final String caCertificatePath;
@@ -28,7 +22,7 @@ public class CloudSslProvider extends SslProvider {
public CloudSslProvider(String servername, String privateKey, String certificate, String caCertificatePath,
String caCertificate, ClientAuth.Enum clientAuthentication, boolean enableTokenSupport) {
- super(COMPONENT_ID_PREFIX, servername, componentClass(enableTokenSupport), null);
+ super("cloud-ssl-provider@", servername, componentClass(enableTokenSupport), null);
this.privateKey = privateKey;
this.certificate = certificate;
this.caCertificatePath = caCertificatePath;
@@ -37,7 +31,9 @@ public class CloudSslProvider extends SslProvider {
}
private static String componentClass(boolean enableTokenSupport) {
- return enableTokenSupport ? TOKEN_COMPONENT_CLASS : MTLSONLY_COMPONENT_CLASS;
+ return enableTokenSupport
+ ? "com.yahoo.jdisc.http.ssl.impl.CloudTokenSslContextProvider"
+ : "com.yahoo.jdisc.http.ssl.impl.ConfiguredSslContextFactoryProvider";
}
@Override
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/HostedSslConnectorFactory.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/HostedSslConnectorFactory.java
index 243d14a006f..cebe08288f6 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/HostedSslConnectorFactory.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/HostedSslConnectorFactory.java
@@ -81,7 +81,7 @@ public class HostedSslConnectorFactory extends ConnectorFactory {
final List<String> remoteAddressHeaders = new ArrayList<>();
final List<String> remotePortHeaders = new ArrayList<>();
SslClientAuth clientAuth;
- List<String> tlsCiphersOverride;
+ List<String> tlsCiphersOverride = List.of();
boolean proxyProtocolEnabled;
boolean proxyProtocolMixedMode;
Duration endpointConnectionTtl;
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/CloudDataPlaneFilter.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/CloudDataPlaneFilter.java
index efa5ee01506..2d0d47288d1 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/CloudDataPlaneFilter.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/CloudDataPlaneFilter.java
@@ -5,7 +5,6 @@ import com.yahoo.component.ComponentSpecification;
import com.yahoo.component.chain.dependencies.Dependencies;
import com.yahoo.component.chain.model.ChainedComponentModel;
import com.yahoo.config.model.deploy.DeployState;
-import com.yahoo.config.provision.DataplaneToken;
import com.yahoo.container.bundle.BundleInstantiationSpecification;
import com.yahoo.jdisc.http.filter.security.cloud.config.CloudDataPlaneFilterConfig;
import com.yahoo.security.X509CertificateUtils;
@@ -13,7 +12,6 @@ import com.yahoo.vespa.model.container.ApplicationContainerCluster;
import com.yahoo.vespa.model.container.http.Client;
import com.yahoo.vespa.model.container.http.Filter;
-import java.time.Instant;
import java.util.Collection;
import java.util.List;
@@ -24,15 +22,11 @@ class CloudDataPlaneFilter extends Filter implements CloudDataPlaneFilterConfig.
private final Collection<Client> clients;
private final boolean clientsLegacyMode;
- private final String tokenContext;
CloudDataPlaneFilter(ApplicationContainerCluster cluster, DeployState state) {
super(model());
this.clients = List.copyOf(cluster.getClients());
this.clientsLegacyMode = cluster.clientsLegacyMode();
- // Token domain must be identical to the domain used for generating the tokens
- this.tokenContext = "Vespa Cloud tenant data plane:%s"
- .formatted(state.getProperties().applicationId().tenant().value());
}
private static ChainedComponentModel model() {
@@ -51,21 +45,11 @@ class CloudDataPlaneFilter extends Filter implements CloudDataPlaneFilterConfig.
.map(x -> new CloudDataPlaneFilterConfig.Clients.Builder()
.id(x.id())
.certificates(x.certificates().stream().map(X509CertificateUtils::toPem).toList())
- .tokens(tokensConfig(x.tokens()))
.permissions(x.permissions()))
.toList();
- builder.clients(clientsCfg).legacyMode(false).tokenContext(tokenContext);
+ builder.clients(clientsCfg).legacyMode(false);
}
}
- private static List<CloudDataPlaneFilterConfig.Clients.Tokens.Builder> tokensConfig(Collection<DataplaneToken> tokens) {
- return tokens.stream()
- .map(token -> new CloudDataPlaneFilterConfig.Clients.Tokens.Builder()
- .id(token.tokenId())
- .fingerprints(token.versions().stream().map(DataplaneToken.Version::fingerprint).toList())
- .checkAccessHashes(token.versions().stream().map(DataplaneToken.Version::checkAccessHash).toList())
- .expirations(token.versions().stream().map(v -> v.expiration().map(Instant::toString).orElse("<none>")).toList()))
- .toList();
- }
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/CloudTokenDataPlaneFilter.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/CloudTokenDataPlaneFilter.java
new file mode 100644
index 00000000000..5b57682e759
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/CloudTokenDataPlaneFilter.java
@@ -0,0 +1,61 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.model.container.xml;
+
+import com.yahoo.component.ComponentSpecification;
+import com.yahoo.component.chain.dependencies.Dependencies;
+import com.yahoo.component.chain.model.ChainedComponentModel;
+import com.yahoo.config.model.deploy.DeployState;
+import com.yahoo.config.provision.DataplaneToken;
+import com.yahoo.container.bundle.BundleInstantiationSpecification;
+import com.yahoo.jdisc.http.filter.security.cloud.config.CloudTokenDataPlaneFilterConfig;
+import com.yahoo.vespa.model.container.ApplicationContainerCluster;
+import com.yahoo.vespa.model.container.http.Client;
+import com.yahoo.vespa.model.container.http.Filter;
+
+import java.time.Instant;
+import java.util.Collection;
+import java.util.List;
+
+class CloudTokenDataPlaneFilter extends Filter implements CloudTokenDataPlaneFilterConfig.Producer {
+ private final Collection<Client> clients;
+ private final String tokenContext;
+
+ CloudTokenDataPlaneFilter(ApplicationContainerCluster cluster, DeployState state) {
+ super(model());
+ this.clients = List.copyOf(cluster.getClients());
+ // Token domain must be identical to the domain used for generating the tokens
+ this.tokenContext = "Vespa Cloud tenant data plane:%s"
+ .formatted(state.getProperties().applicationId().tenant().value());
+ }
+
+ private static ChainedComponentModel model() {
+ return new ChainedComponentModel(
+ new BundleInstantiationSpecification(
+ new ComponentSpecification("com.yahoo.jdisc.http.filter.security.cloud.CloudTokenDataPlaneFilter"),
+ null,
+ new ComponentSpecification("jdisc-security-filters")),
+ Dependencies.emptyDependencies());
+ }
+
+ @Override
+ public void getConfig(CloudTokenDataPlaneFilterConfig.Builder builder) {
+ var clientsCfg = clients.stream()
+ .map(x -> new CloudTokenDataPlaneFilterConfig.Clients.Builder()
+ .id(x.id())
+ .tokens(tokensConfig(x.tokens()))
+ .permissions(x.permissions()))
+ .toList();
+ builder.clients(clientsCfg).tokenContext(tokenContext);
+ }
+
+ private static List<CloudTokenDataPlaneFilterConfig.Clients.Tokens.Builder> tokensConfig(Collection<DataplaneToken> tokens) {
+ return tokens.stream()
+ .map(token -> new CloudTokenDataPlaneFilterConfig.Clients.Tokens.Builder()
+ .id(token.tokenId())
+ .fingerprints(token.versions().stream().map(DataplaneToken.Version::fingerprint).toList())
+ .checkAccessHashes(token.versions().stream().map(DataplaneToken.Version::checkAccessHash).toList())
+ .expirations(token.versions().stream().map(v -> v.expiration().map(Instant::toString).orElse("<none>")).toList()))
+ .toList();
+ }
+
+}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
index d9b725bae40..a4a373a89a0 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
@@ -458,8 +458,9 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
addHostedImplicitHttpIfNotPresent(deployState, cluster);
addHostedImplicitAccessControlIfNotPresent(deployState, cluster);
addDefaultConnectorHostedFilterBinding(cluster);
- addAdditionalHostedConnector(deployState, cluster);
+ addCloudMtlsConnector(deployState, cluster);
addCloudDataPlaneFilter(deployState, cluster);
+ addCloudTokenSupport(deployState, cluster);
}
}
@@ -596,7 +597,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
.ifPresent(accessControl -> accessControl.configureDefaultHostedConnector(cluster.getHttp())); ;
}
- private void addAdditionalHostedConnector(DeployState state, ApplicationContainerCluster cluster) {
+ private void addCloudMtlsConnector(DeployState state, ApplicationContainerCluster cluster) {
JettyHttpServer server = cluster.getHttp().getHttpServer().get();
String serverName = server.getComponentId().getName();
@@ -624,22 +625,6 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
.orElse(false);
builder.clientAuth(needAuth ? SslClientAuth.NEED : SslClientAuth.WANT);
}
-
- boolean enableTokenSupport = state.featureFlags().enableDataplaneProxy()
- && cluster.getClients().stream().anyMatch(c -> !c.tokens().isEmpty());
-
- // Set up component to generate proxy cert if token support is enabled
- if (enableTokenSupport) {
- cluster.addSimpleComponent(DataplaneProxyCredentials.class);
- cluster.addSimpleComponent(DataplaneProxyService.class);
-
- var dataplaneProxy = new DataplaneProxy(
- getMtlsDataplanePort(state),
- endpointCert.certificate(),
- endpointCert.key());
- cluster.addComponent(dataplaneProxy);
- builder.tokenEndpoint(true);
- }
} else {
builder.clientAuth(SslClientAuth.WANT_WITH_ENFORCER);
}
@@ -648,6 +633,46 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
server.addConnector(connectorFactory);
}
+ private void addCloudTokenSupport(DeployState state, ApplicationContainerCluster cluster) {
+ var server = cluster.getHttp().getHttpServer().get();
+ boolean enableTokenSupport = state.isHosted() && state.zone().system().isPublic()
+ && state.featureFlags().enableDataplaneProxy()
+ && cluster.getClients().stream().anyMatch(c -> !c.tokens().isEmpty());
+ if (!enableTokenSupport) return;
+ var endpointCert = state.endpointCertificateSecrets().orElseThrow();
+ int tokenPort = getTokenDataplanePort(state).orElseThrow();
+
+ // Set up component to generate proxy cert if token support is enabled
+ cluster.addSimpleComponent(DataplaneProxyCredentials.class);
+ cluster.addSimpleComponent(DataplaneProxyService.class);
+ var dataplaneProxy = new DataplaneProxy(
+ getMtlsDataplanePort(state),
+ endpointCert.certificate(),
+ endpointCert.key());
+ cluster.addComponent(dataplaneProxy);
+
+ // Setup dedicated connector
+ var connector = HostedSslConnectorFactory.builder(server.getComponentId().getName()+"-token", tokenPort)
+ .tokenEndpoint(true)
+ .proxyProtocol(false, false)
+ .endpointCertificate(endpointCert)
+ .remoteAddressHeader("X-Forwarded-For")
+ .remotePortHeader("X-Forwarded-Port")
+ .clientAuth(SslClientAuth.NEED)
+ .build();
+ server.addConnector(connector);
+
+ // Setup token filter chain
+ var tokenChain = new HttpFilterChain("cloud-token-data-plane-secure", HttpFilterChain.Type.SYSTEM);
+ tokenChain.addInnerComponent(new CloudTokenDataPlaneFilter(cluster, state));
+ cluster.getHttp().getFilterChains().add(tokenChain);
+
+ // Set as default filter for token port
+ cluster.getHttp().getHttpServer().orElseThrow().getConnectorFactories().stream()
+ .filter(c -> c.getListenPort() == tokenPort).findAny().orElseThrow()
+ .setDefaultRequestFilterChain(tokenChain.getComponentId());
+ }
+
// Returns the client certificates of the clients defined for an application cluster
private List<X509Certificate> getClientCertificates(ApplicationContainerCluster cluster) {
return cluster.getClients()