diff options
9 files changed, 228 insertions, 100 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() diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/CloudDataPlaneFilterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/CloudDataPlaneFilterTest.java index 02ff7b8a03f..94d92b355f9 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/CloudDataPlaneFilterTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/CloudDataPlaneFilterTest.java @@ -6,7 +6,6 @@ import com.yahoo.config.model.builder.xml.test.DomBuilderTest; import com.yahoo.config.model.deploy.DeployState; import com.yahoo.config.model.deploy.TestProperties; import com.yahoo.config.model.test.MockApplicationPackage; -import com.yahoo.config.provision.DataplaneToken; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.RegionName; import com.yahoo.config.provision.SystemName; @@ -35,17 +34,14 @@ import java.nio.file.Files; import java.nio.file.Path; import java.security.KeyPair; import java.security.cert.X509Certificate; -import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; -import java.util.Collection; import java.util.List; import java.util.Optional; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertIterableEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -89,7 +85,6 @@ public class CloudDataPlaneFilterTest extends ContainerModelBuilderTestBase { CloudDataPlaneFilterConfig.Clients client = clients.get(0); assertEquals("foo", client.id()); assertIterableEquals(List.of("read", "write"), client.permissions()); - assertTrue(client.tokens().isEmpty()); assertIterableEquals(List.of(X509CertificateUtils.toPem(certificate)), client.certificates()); ConnectorConfig connectorConfig = connectorConfig(); @@ -123,43 +118,6 @@ public class CloudDataPlaneFilterTest 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())); - createCertificate(certFile); - buildModel(clusterElem); - - var cfg = root.getConfig(CloudDataPlaneFilterConfig.class, cloudDataPlaneFilterConfigId); - var tokenClient = cfg.clients().stream().filter(c -> c.id().equals("bar")).findAny().orElse(null); - assertNotNull(tokenClient); - assertEquals(List.of("read"), tokenClient.permissions()); - assertTrue(tokenClient.certificates().isEmpty()); - var expectedTokenCfg = tokenConfig( - "my-token", List.of("myfingerprint1", "myfingerprint2"), List.of("myaccesshash1", "myaccesshash2"), - List.of("<none>", "2243-10-17T00:00:00Z")); - assertEquals(List.of(expectedTokenCfg), tokenClient.tokens()); - } - - private static CloudDataPlaneFilterConfig.Clients.Tokens tokenConfig( - String id, Collection<String> fingerprints, Collection<String> accessCheckHashes, Collection<String> expirations) { - return new CloudDataPlaneFilterConfig.Clients.Tokens.Builder() - .id(id).fingerprints(fingerprints).checkAccessHashes(accessCheckHashes).expirations(expirations).build(); - } - - @Test public void it_rejects_files_without_certificates() throws IOException { Path certFile = securityFolder.resolve("foo.pem"); Element clusterElem = DomBuilderTest.parse( @@ -231,9 +189,6 @@ public class CloudDataPlaneFilterTest extends ContainerModelBuilderTestBase { .properties( new TestProperties() .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)) .zone(new Zone(SystemName.PublicCd, Environment.dev, RegionName.defaultName())) .build(); 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 new file mode 100644 index 00000000000..15e1d61c951 --- /dev/null +++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/CloudTokenDataPlaneFilterTest.java @@ -0,0 +1,105 @@ +// 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.config.model.api.EndpointCertificateSecrets; +import com.yahoo.config.model.builder.xml.test.DomBuilderTest; +import com.yahoo.config.model.deploy.DeployState; +import com.yahoo.config.model.deploy.TestProperties; +import com.yahoo.config.model.test.MockApplicationPackage; +import com.yahoo.config.provision.DataplaneToken; +import com.yahoo.config.provision.Environment; +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.vespa.model.container.ContainerModel; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.w3c.dom.Element; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Duration; +import java.time.Instant; +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +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.assertNotNull; + +public class CloudTokenDataPlaneFilterTest extends ContainerModelBuilderTestBase { + + @TempDir + public File applicationFolder; + + Path securityFolder; + private static final String filterConfigId = "container/filters/chain/cloud-token-data-plane-secure/component/" + + "com.yahoo.jdisc.http.filter.security.cloud.CloudTokenDataPlaneFilter"; + + @BeforeEach + public void setup() throws IOException { + securityFolder = applicationFolder.toPath().resolve("security"); + Files.createDirectories(securityFolder); + } + + @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())); + createCertificate(certFile); + buildModel(clusterElem); + + var cfg = root.getConfig(CloudTokenDataPlaneFilterConfig.class, filterConfigId); + var tokenClient = cfg.clients().stream().filter(c -> c.id().equals("bar")).findAny().orElse(null); + assertNotNull(tokenClient); + assertEquals(List.of("read"), tokenClient.permissions()); + var expectedTokenCfg = tokenConfig( + "my-token", List.of("myfingerprint1", "myfingerprint2"), List.of("myaccesshash1", "myaccesshash2"), + List.of("<none>", "2243-10-17T00:00:00Z")); + assertEquals(List.of(expectedTokenCfg), tokenClient.tokens()); + } + + 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) { + var applicationPackage = new MockApplicationPackage.Builder() + .withRoot(applicationFolder) + .build(); + + DeployState state = new DeployState.Builder() + .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)) + .zone(new Zone(SystemName.PublicCd, Environment.dev, RegionName.defaultName())) + .build(); + return createModel(root, state, null, clusterElem); + } +} diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/CloudSslContextProvider.java b/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/CloudTokenSslContextProvider.java index cdfd4aa938e..fe71d1b24c6 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/CloudSslContextProvider.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/CloudTokenSslContextProvider.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.jdisc.http.ssl.impl; +import com.yahoo.component.annotation.Inject; import com.yahoo.jdisc.http.ConnectorConfig; import com.yahoo.jdisc.http.server.jetty.DataplaneProxyCredentials; @@ -14,29 +15,23 @@ import java.util.Optional; * * @author mortent */ -public class CloudSslContextProvider extends ConfiguredSslContextFactoryProvider { +public class CloudTokenSslContextProvider extends ConfiguredSslContextFactoryProvider { private final DataplaneProxyCredentials dataplaneProxyCredentials; - public CloudSslContextProvider(ConnectorConfig connectorConfig, DataplaneProxyCredentials dataplaneProxyCredentials) { + @Inject + public CloudTokenSslContextProvider(ConnectorConfig connectorConfig, + DataplaneProxyCredentials dataplaneProxyCredentials) { super(connectorConfig); this.dataplaneProxyCredentials = dataplaneProxyCredentials; } @Override Optional<String> getCaCertificates(ConnectorConfig.Ssl sslConfig) { - String proxyCert; try { - proxyCert = Files.readString(dataplaneProxyCredentials.certificateFile(), StandardCharsets.UTF_8); + return Optional.of(Files.readString(dataplaneProxyCredentials.certificateFile(), StandardCharsets.UTF_8)); } catch (IOException e) { throw new IllegalArgumentException("Dataplane proxy certificate not available", e); } - if (!sslConfig.caCertificate().isBlank()) { - return Optional.of(sslConfig.caCertificate() + "\n" + proxyCert); - } else if (!sslConfig.caCertificateFile().isBlank()) { - return Optional.of(readToString(sslConfig.caCertificateFile()) + "\n" + proxyCert); - } else { - return Optional.of(proxyCert); - } } } |