summaryrefslogtreecommitdiffstats
path: root/config-model/src
diff options
context:
space:
mode:
Diffstat (limited to 'config-model/src')
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java6
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java58
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/xml/CloudTokenDataPlaneFilterTest.java89
3 files changed, 94 insertions, 59 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 da81f7a90f2..815c32e3c8f 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
@@ -85,7 +85,6 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea
private Optional<CloudAccount> cloudAccount = Optional.empty();
private boolean allowUserFilters = true;
private List<DataplaneToken> dataplaneTokens;
- private boolean enableDataplaneProxy;
private int contentLayerMetadataFeatureLevel = 0;
@Override public ModelContext.FeatureFlags featureFlags() { return this; }
@@ -375,11 +374,6 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea
return this;
}
- public TestProperties setEnableDataplaneProxy(boolean enable) {
- this.enableDataplaneProxy = enable;
- return this;
- }
-
public TestProperties setContentLayerMetadataFeatureLevel(int level) {
this.contentLayerMetadataFeatureLevel = level;
return this;
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 9804cb0b10d..35b0213bf59 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
@@ -459,7 +459,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
private static void addCloudDataPlaneFilter(DeployState deployState, ApplicationContainerCluster cluster) {
if (!deployState.isHosted() || !deployState.zone().system().isPublic()) return;
- var dataplanePort = getMtlsDataplanePort(deployState);
+ var dataplanePort = getMtlsDataplanePort(deployState, cluster);
// Setup secure filter chain
var secureChain = new HttpFilterChain("cloud-data-plane-secure", HttpFilterChain.Type.SYSTEM);
secureChain.addInnerComponent(new CloudDataPlaneFilter(cluster, deployState));
@@ -594,7 +594,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
String serverName = server.getComponentId().getName();
// If the deployment contains certificate/private key reference, setup TLS port
- var builder = HostedSslConnectorFactory.builder(serverName, getMtlsDataplanePort(state))
+ var builder = HostedSslConnectorFactory.builder(serverName, getMtlsDataplanePort(state, cluster))
.proxyProtocol(true, state.getProperties().featureFlags().enableProxyProtocolMixedMode())
.tlsCiphersOverride(state.getProperties().tlsCiphersOverride())
.endpointConnectionTtl(state.getProperties().endpointConnectionTtl());
@@ -627,23 +627,19 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
private void addCloudTokenSupport(DeployState state, ApplicationContainerCluster cluster) {
var server = cluster.getHttp().getHttpServer().get();
+ if (!enableTokenSupport(state, cluster)) return;
Set<String> tokenEndpoints = tokenEndpoints(state).stream()
.map(ContainerEndpoint::names)
.flatMap(Collection::stream)
.collect(Collectors.toSet());
-
- boolean enableTokenSupport = state.isHosted() && state.zone().system().isPublic()
- && cluster.getClients().stream().anyMatch(c -> !c.tokens().isEmpty())
- && ! tokenEndpoints.isEmpty();
- if (!enableTokenSupport) return;
var endpointCert = state.endpointCertificateSecrets().orElseThrow();
- int tokenPort = getTokenDataplanePort(state).orElseThrow();
+ int tokenPort = getTokenDataplanePort(state, cluster).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),
+ getMtlsDataplanePort(state, cluster),
tokenPort,
endpointCert.certificate(),
endpointCert.key(),
@@ -714,7 +710,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
}
private Http buildHttp(DeployState deployState, ApplicationContainerCluster cluster, Element httpElement, ConfigModelContext context) {
- Http http = new HttpBuilder(portBindingOverride(deployState, context)).build(deployState, cluster, httpElement);
+ Http http = new HttpBuilder(portBindingOverride(deployState, context, cluster)).build(deployState, cluster, httpElement);
if (networking == Networking.disable)
http.removeAllServers();
@@ -819,7 +815,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
cluster.addSearchAndDocprocBundles();
addIncludes(processingElement);
cluster.setProcessingChains(new DomProcessingBuilder(null).build(deployState, cluster, processingElement),
- serverBindings(deployState, context, processingElement, ProcessingChains.defaultBindings).toArray(BindingPattern[]::new));
+ serverBindings(deployState, context, processingElement, ProcessingChains.defaultBindings, cluster).toArray(BindingPattern[]::new));
validateAndAddConfiguredComponents(deployState, cluster, processingElement, "renderer", ContainerModelBuilder::validateRendererElement);
}
@@ -844,7 +840,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
private void addUserHandlers(DeployState deployState, ApplicationContainerCluster cluster, Element spec, ConfigModelContext context) {
for (Element component: XML.getChildren(spec, "handler")) {
cluster.addComponent(
- new DomHandlerBuilder(cluster, portBindingOverride(deployState, context)).build(deployState, cluster, component));
+ new DomHandlerBuilder(cluster, portBindingOverride(deployState, context, cluster)).build(deployState, cluster, component));
}
}
@@ -1132,10 +1128,10 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
private void addSearchHandler(DeployState deployState, ApplicationContainerCluster cluster, Element searchElement, ConfigModelContext context) {
var bindingPatterns = List.<BindingPattern>of(SearchHandler.DEFAULT_BINDING);
if (isHostedTenantApplication(context)) {
- bindingPatterns = SearchHandler.bindingPattern(getDataplanePorts(deployState));
+ bindingPatterns = SearchHandler.bindingPattern(getDataplanePorts(deployState, cluster));
}
SearchHandler searchHandler = new SearchHandler(cluster,
- serverBindings(deployState, context, searchElement, bindingPatterns),
+ serverBindings(deployState, context, searchElement, bindingPatterns, cluster),
ContainerThreadpool.UserOptions.fromXml(searchElement).orElse(null));
cluster.addComponent(searchHandler);
@@ -1143,17 +1139,17 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
searchHandler.addComponent(Component.fromClassAndBundle(SearchHandler.EXECUTION_FACTORY, PlatformBundles.SEARCH_AND_DOCPROC_BUNDLE));
}
- private List<BindingPattern> serverBindings(DeployState deployState, ConfigModelContext context, Element searchElement, Collection<BindingPattern> defaultBindings) {
+ private List<BindingPattern> serverBindings(DeployState deployState, ConfigModelContext context, Element searchElement, Collection<BindingPattern> defaultBindings, ApplicationContainerCluster cluster) {
List<Element> bindings = XML.getChildren(searchElement, "binding");
if (bindings.isEmpty())
return List.copyOf(defaultBindings);
- return toBindingList(deployState, context, bindings);
+ return toBindingList(deployState, context, bindings, cluster);
}
- private List<BindingPattern> toBindingList(DeployState deployState, ConfigModelContext context, List<Element> bindingElements) {
+ private List<BindingPattern> toBindingList(DeployState deployState, ConfigModelContext context, List<Element> bindingElements, ApplicationContainerCluster cluster) {
List<BindingPattern> result = new ArrayList<>();
- var portOverride = isHostedTenantApplication(context) ? getDataplanePorts(deployState) : Set.<Integer>of();
+ var portOverride = isHostedTenantApplication(context) ? getDataplanePorts(deployState, cluster) : Set.<Integer>of();
for (Element element: bindingElements) {
String text = element.getTextContent().trim();
if (!text.isEmpty())
@@ -1178,12 +1174,12 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
ContainerDocumentApi.HandlerOptions documentApiOptions = DocumentApiOptionsBuilder.build(documentApiElement);
Element ignoreUndefinedFields = XML.getChild(documentApiElement, "ignore-undefined-fields");
return new ContainerDocumentApi(cluster, documentApiOptions,
- "true".equals(XML.getValue(ignoreUndefinedFields)), portBindingOverride(deployState, context));
+ "true".equals(XML.getValue(ignoreUndefinedFields)), portBindingOverride(deployState, context, cluster));
}
- private Set<Integer> portBindingOverride(DeployState deployState, ConfigModelContext context) {
+ private Set<Integer> portBindingOverride(DeployState deployState, ConfigModelContext context, ApplicationContainerCluster cluster) {
return isHostedTenantApplication(context)
- ? getDataplanePorts(deployState)
+ ? getDataplanePorts(deployState, cluster)
: Set.<Integer>of();
}
@@ -1442,20 +1438,18 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
}
- private static Set<Integer> getDataplanePorts(DeployState ds) {
- var tokenPort = getTokenDataplanePort(ds);
- var mtlsPort = getMtlsDataplanePort(ds);
+ private static Set<Integer> getDataplanePorts(DeployState ds, ApplicationContainerCluster cluster) {
+ var tokenPort = getTokenDataplanePort(ds, cluster);
+ var mtlsPort = getMtlsDataplanePort(ds, cluster);
return tokenPort.isPresent() ? Set.of(mtlsPort, tokenPort.getAsInt()) : Set.of(mtlsPort);
}
- private static int getMtlsDataplanePort(DeployState ds) {
- boolean enableDataplaneProxy = ! tokenEndpoints(ds).isEmpty();
- return enableDataplaneProxy ? 8443 : 4443;
+ private static int getMtlsDataplanePort(DeployState ds, ApplicationContainerCluster cluster) {
+ return enableTokenSupport(ds, cluster) ? 8443 : 4443;
}
- private static OptionalInt getTokenDataplanePort(DeployState ds) {
- boolean enableDataplaneProxy = ! tokenEndpoints(ds).isEmpty();
- return enableDataplaneProxy ? OptionalInt.of(8444) : OptionalInt.empty();
+ private static OptionalInt getTokenDataplanePort(DeployState ds, ApplicationContainerCluster cluster) {
+ return enableTokenSupport(ds, cluster) ? OptionalInt.of(8444) : OptionalInt.empty();
}
private static Set<ContainerEndpoint> tokenEndpoints(DeployState deployState) {
@@ -1464,4 +1458,8 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
.collect(Collectors.toSet());
}
+ private static boolean enableTokenSupport(DeployState state, ApplicationContainerCluster cluster) {
+ Set<ContainerEndpoint> tokenEndpoints = tokenEndpoints(state);
+ return state.isHosted() && state.zone().system().isPublic() && ! tokenEndpoints.isEmpty();
+ }
}
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/CloudTokenDataPlaneFilterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/CloudTokenDataPlaneFilterTest.java
index b4e2f53bb87..fba2ef891be 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/CloudTokenDataPlaneFilterTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/CloudTokenDataPlaneFilterTest.java
@@ -1,6 +1,7 @@
// 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.cloud.config.DataplaneProxyConfig;
import com.yahoo.config.model.api.ApplicationClusterEndpoint;
import com.yahoo.config.model.api.ContainerEndpoint;
import com.yahoo.config.model.api.EndpointCertificateSecrets;
@@ -14,6 +15,7 @@ import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.Zone;
import com.yahoo.jdisc.http.filter.security.cloud.config.CloudTokenDataPlaneFilterConfig;
+import com.yahoo.processing.response.Data;
import com.yahoo.vespa.model.container.ContainerModel;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -34,10 +36,30 @@ import java.util.Set;
import static com.yahoo.vespa.model.container.xml.CloudDataPlaneFilterTest.createCertificate;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
public class CloudTokenDataPlaneFilterTest extends ContainerModelBuilderTestBase {
+ private static final String servicesXmlTemplate = """
+ <container version='1.0'>
+ <clients>
+ <client id="foo" permissions="read,write">
+ <certificate file="%s"/>
+ </client>
+ <client id="bar" permissions="read">
+ <token id="my-token"/>
+ </client>
+ </clients>
+ </container>
+ """;
+
+ private static final List<DataplaneToken> defaultTokens = List.of(new DataplaneToken("my-token", List.of(
+ new DataplaneToken.Version("myfingerprint1", "myaccesshash1", Optional.empty()),
+ new DataplaneToken.Version("myfingerprint2", "myaccesshash2", Optional.of(Instant.EPOCH.plus(Duration.ofDays(100000)))))));
+ private static final ContainerEndpoint tokenEndpoint = new ContainerEndpoint("cluster", ApplicationClusterEndpoint.Scope.zone, List.of("token"), OptionalInt.empty(), ApplicationClusterEndpoint.RoutingMethod.exclusive, ApplicationClusterEndpoint.AuthMethod.token);
+ private static final ContainerEndpoint mtlsEndpoint = new ContainerEndpoint("cluster", ApplicationClusterEndpoint.Scope.zone, List.of("mtls"), OptionalInt.empty(), ApplicationClusterEndpoint.RoutingMethod.exclusive, ApplicationClusterEndpoint.AuthMethod.mtls);
@TempDir
public File applicationFolder;
@@ -54,22 +76,9 @@ public class CloudTokenDataPlaneFilterTest extends ContainerModelBuilderTestBase
@Test
void generates_correct_config_for_tokens() throws IOException {
var certFile = securityFolder.resolve("foo.pem");
- var clusterElem = DomBuilderTest.parse(
- """
- <container version='1.0'>
- <clients>
- <client id="foo" permissions="read,write">
- <certificate file="%s"/>
- </client>
- <client id="bar" permissions="read">
- <token id="my-token"/>
- </client>
- </clients>
- </container>
- """
- .formatted(applicationFolder.toPath().relativize(certFile).toString()));
+ var clusterElem = DomBuilderTest.parse(servicesXmlTemplate.formatted(applicationFolder.toPath().relativize(certFile).toString()));
createCertificate(certFile);
- buildModel(clusterElem);
+ buildModel(Set.of(tokenEndpoint, mtlsEndpoint), defaultTokens, clusterElem);
var cfg = root.getConfig(CloudTokenDataPlaneFilterConfig.class, filterConfigId);
var tokenClient = cfg.clients().stream().filter(c -> c.id().equals("bar")).findAny().orElse(null);
@@ -81,13 +90,50 @@ public class CloudTokenDataPlaneFilterTest extends ContainerModelBuilderTestBase
assertEquals(List.of(expectedTokenCfg), tokenClient.tokens());
}
+ @Test
+ void configures_dataplane_proxy_when_token_defined() throws IOException {
+ var certFile = securityFolder.resolve("foo.pem");
+ var clusterElem = DomBuilderTest.parse(servicesXmlTemplate.formatted(applicationFolder.toPath().relativize(certFile).toString()));
+ createCertificate(certFile);
+ buildModel(Set.of(tokenEndpoint, mtlsEndpoint), defaultTokens, clusterElem);
+
+ var configId = "container/component/com.yahoo.container.jdisc.DataplaneProxyConfigurator";
+ var cfg = root.getConfig(DataplaneProxyConfig.class, configId);
+ assertEquals(8443, cfg.mtlsPort());
+ assertEquals(8444, cfg.tokenPort());
+ }
+
+ @Test
+ void configures_dataplane_proxy_when_token_defined_but_missing() throws IOException {
+ var certFile = securityFolder.resolve("foo.pem");
+ var clusterElem = DomBuilderTest.parse(servicesXmlTemplate.formatted(applicationFolder.toPath().relativize(certFile).toString()));
+ createCertificate(certFile);
+ buildModel(Set.of(tokenEndpoint, mtlsEndpoint), List.of(), clusterElem);
+
+ var configId = "container/component/com.yahoo.container.jdisc.DataplaneProxyConfigurator";
+ var cfg = root.getConfig(DataplaneProxyConfig.class, configId);
+ assertNotNull(cfg);
+ assertEquals(8443, cfg.mtlsPort());
+ assertEquals(8444, cfg.tokenPort());
+ }
+
+ @Test
+ void does_notconfigure_dataplane_proxy_when_token_endpoints_not_defined() throws IOException {
+ var certFile = securityFolder.resolve("foo.pem");
+ var clusterElem = DomBuilderTest.parse(servicesXmlTemplate.formatted(applicationFolder.toPath().relativize(certFile).toString()));
+ createCertificate(certFile);
+ buildModel(Set.of(mtlsEndpoint), List.of(), clusterElem);
+
+ assertFalse(root.getConfigIds().stream().anyMatch(id -> id.contains("DataplaneProxyConfigurator")));
+ }
+
private static CloudTokenDataPlaneFilterConfig.Clients.Tokens tokenConfig(
String id, Collection<String> fingerprints, Collection<String> accessCheckHashes, Collection<String> expirations) {
return new CloudTokenDataPlaneFilterConfig.Clients.Tokens.Builder()
.id(id).fingerprints(fingerprints).checkAccessHashes(accessCheckHashes).expirations(expirations).build();
}
- public List<ContainerModel> buildModel(Element... clusterElem) {
+ public List<ContainerModel> buildModel(Set<ContainerEndpoint> endpoints, List<DataplaneToken> definedTokens, Element... clusterElem) {
var applicationPackage = new MockApplicationPackage.Builder()
.withRoot(applicationFolder)
.build();
@@ -96,14 +142,11 @@ public class CloudTokenDataPlaneFilterTest extends ContainerModelBuilderTestBase
.applicationPackage(applicationPackage)
.properties(
new TestProperties()
- .setEnableDataplaneProxy(true)
- .setEndpointCertificateSecrets(Optional.of(new EndpointCertificateSecrets("CERT", "KEY")))
- .setDataplaneTokens(List.of(new DataplaneToken("my-token", List.of(
- new DataplaneToken.Version("myfingerprint1", "myaccesshash1", Optional.empty()),
- new DataplaneToken.Version("myfingerprint2", "myaccesshash2", Optional.of(Instant.EPOCH.plus(Duration.ofDays(100000))))))))
- .setHostedVespa(true))
+ .setEndpointCertificateSecrets(Optional.of(new EndpointCertificateSecrets("CERT", "KEY")))
+ .setDataplaneTokens(definedTokens)
+ .setHostedVespa(true))
.zone(new Zone(SystemName.PublicCd, Environment.dev, RegionName.defaultName()))
- .endpoints(Set.of(new ContainerEndpoint("cluster", ApplicationClusterEndpoint.Scope.zone, List.of("name"), OptionalInt.empty(), ApplicationClusterEndpoint.RoutingMethod.exclusive, ApplicationClusterEndpoint.AuthMethod.token)))
+ .endpoints(endpoints)
.build();
return createModel(root, state, null, clusterElem);
}