summaryrefslogtreecommitdiffstats
path: root/config-model
diff options
context:
space:
mode:
authorMorten Tokle <mortent@verizonmedia.com>2020-10-14 14:23:45 +0200
committerMorten Tokle <mortent@verizonmedia.com>2020-10-14 14:23:45 +0200
commit7e01a997ee5f918ce32ef2d6bddc44691cc6c530 (patch)
tree2a3e1561abe7d11a3dc8f8ae57a3df5f70820c53 /config-model
parentd27f881027a5fddeefe336da0d84f2e160c01eb1 (diff)
Set up need_auth for connector when access_control configured
Diffstat (limited to 'config-model')
-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/HostedSslConnectorFactory.java23
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java13
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java38
4 files changed, 70 insertions, 11 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 1455b4d8007..2c6608c37ad 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
@@ -52,6 +52,7 @@ public class TestProperties implements ModelContext.Properties {
private AthenzDomain athenzDomain;
private ApplicationRoles applicationRoles;
private Quota quota = Quota.unlimited();
+ private boolean useAccessControlTlsHandshakeClientAuth;
@Override public boolean multitenant() { return multitenant; }
@Override public ApplicationId applicationId() { return applicationId; }
@@ -89,6 +90,7 @@ public class TestProperties implements ModelContext.Properties {
@Override public double visibilityDelay() { return visibilityDelay; }
@Override public boolean tlsUseFSync() { return tlsUseFSync; }
@Override public String tlsCompressionType() { return tlsCompressionType; }
+ @Override public boolean useAccessControlTlsHandshakeClientAuth() { return useAccessControlTlsHandshakeClientAuth; }
public TestProperties setJvmGCOptions(String gcOptions) {
jvmGCOptions = gcOptions;
@@ -200,6 +202,11 @@ public class TestProperties implements ModelContext.Properties {
return this;
}
+ public TestProperties useAccessControlTlsHandshakeClientAuth(boolean useAccessControlTlsHandshakeClientAuth) {
+ this.useAccessControlTlsHandshakeClientAuth = useAccessControlTlsHandshakeClientAuth;
+ 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/HostedSslConnectorFactory.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/HostedSslConnectorFactory.java
index bcc2c9a3d6a..6c4ebec2301 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
@@ -21,14 +21,15 @@ public class HostedSslConnectorFactory extends ConnectorFactory {
private static final String DEFAULT_HOSTED_TRUSTSTORE = "/opt/yahoo/share/ssl/certs/athenz_certificate_bundle.pem";
private final boolean enforceClientAuth;
+ private final boolean enforceHandshakeClientAuth;
/**
* Create connector factory that uses a certificate provided by the config-model / configserver and default hosted Vespa truststore.
*/
// TODO Enforce client authentication
public static HostedSslConnectorFactory withProvidedCertificate(
- String serverName, EndpointCertificateSecrets endpointCertificateSecrets) {
- return new HostedSslConnectorFactory(createConfiguredDirectSslProvider(serverName, endpointCertificateSecrets, DEFAULT_HOSTED_TRUSTSTORE, /*tlsCaCertificates*/null), false);
+ String serverName, EndpointCertificateSecrets endpointCertificateSecrets, boolean enforceHandshakeClientAuth) {
+ return new HostedSslConnectorFactory(createConfiguredDirectSslProvider(serverName, endpointCertificateSecrets, DEFAULT_HOSTED_TRUSTSTORE, /*tlsCaCertificates*/null), false, enforceHandshakeClientAuth);
}
/**
@@ -36,19 +37,20 @@ public class HostedSslConnectorFactory extends ConnectorFactory {
*/
public static HostedSslConnectorFactory withProvidedCertificateAndTruststore(
String serverName, EndpointCertificateSecrets endpointCertificateSecrets, String tlsCaCertificates) {
- return new HostedSslConnectorFactory(createConfiguredDirectSslProvider(serverName, endpointCertificateSecrets, /*tlsCaCertificatesPath*/null, tlsCaCertificates), true);
+ return new HostedSslConnectorFactory(createConfiguredDirectSslProvider(serverName, endpointCertificateSecrets, /*tlsCaCertificatesPath*/null, tlsCaCertificates), true, false);
}
/**
* Create connector factory that uses the default certificate and truststore provided by Vespa (through Vespa-global TLS configuration).
*/
public static HostedSslConnectorFactory withDefaultCertificateAndTruststore(String serverName) {
- return new HostedSslConnectorFactory(new DefaultSslProvider(serverName), true);
+ return new HostedSslConnectorFactory(new DefaultSslProvider(serverName), true, false);
}
- private HostedSslConnectorFactory(SimpleComponent sslProviderComponent, boolean enforceClientAuth) {
+ private HostedSslConnectorFactory(SimpleComponent sslProviderComponent, boolean enforceClientAuth, boolean enforceHandshakeClientAuth) {
super("tls4443", 4443, sslProviderComponent);
this.enforceClientAuth = enforceClientAuth;
+ this.enforceHandshakeClientAuth = enforceHandshakeClientAuth;
}
private static ConfiguredDirectSslProvider createConfiguredDirectSslProvider(
@@ -65,10 +67,15 @@ public class HostedSslConnectorFactory extends ConnectorFactory {
@Override
public void getConfig(ConnectorConfig.Builder connectorBuilder) {
super.getConfig(connectorBuilder);
+ if (enforceHandshakeClientAuth) {
+ connectorBuilder.ssl.clientAuth(ClientAuth.Enum.NEED_AUTH);
+ } else {
+ connectorBuilder
+ .tlsClientAuthEnforcer(new ConnectorConfig.TlsClientAuthEnforcer.Builder()
+ .pathWhitelist(INSECURE_WHITELISTED_PATHS)
+ .enable(enforceClientAuth));
+ }
connectorBuilder
- .tlsClientAuthEnforcer(new ConnectorConfig.TlsClientAuthEnforcer.Builder()
- .pathWhitelist(INSECURE_WHITELISTED_PATHS)
- .enable(enforceClientAuth))
.proxyProtocol(new ConnectorConfig.ProxyProtocol.Builder().enabled(true).mixedMode(true))
.idleTimeout(Duration.ofMinutes(3).toSeconds())
.maxConnectionLife(Duration.ofMinutes(10).toSeconds());
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 bc8b01ec6df..6fd1c9b35fb 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
@@ -318,11 +318,11 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
if (isHostedTenantApplication(context)) {
addHostedImplicitHttpIfNotPresent(cluster);
addHostedImplicitAccessControlIfNotPresent(deployState, cluster);
- addAdditionalHostedConnector(deployState, cluster);
+ addAdditionalHostedConnector(deployState, cluster, context);
}
}
- private void addAdditionalHostedConnector(DeployState deployState, ApplicationContainerCluster cluster) {
+ private void addAdditionalHostedConnector(DeployState deployState, ApplicationContainerCluster cluster, ConfigModelContext context) {
JettyHttpServer server = cluster.getHttp().getHttpServer().get();
String serverName = server.getComponentId().getName();
@@ -333,9 +333,16 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
throw new RuntimeException("Client certificate authority security/clients.pem is missing - see: https://cloud.vespa.ai/security-model#data-plane");
}
EndpointCertificateSecrets endpointCertificateSecrets = deployState.endpointCertificateSecrets().get();
+
+ boolean enforceHandshakeClientAuth = context.properties().useAccessControlTlsHandshakeClientAuth() &&
+ cluster.getHttp().getAccessControl()
+ .map(accessControl -> accessControl.clientAuthentication)
+ .map(clientAuth -> clientAuth.equals(AccessControl.ClientAuthentication.need))
+ .orElse(false);
+
HostedSslConnectorFactory connectorFactory = authorizeClient
? HostedSslConnectorFactory.withProvidedCertificateAndTruststore(serverName, endpointCertificateSecrets, deployState.tlsClientAuthority().get())
- : HostedSslConnectorFactory.withProvidedCertificate(serverName, endpointCertificateSecrets);
+ : HostedSslConnectorFactory.withProvidedCertificate(serverName, endpointCertificateSecrets, enforceHandshakeClientAuth);
server.addConnector(connectorFactory);
} else {
server.addConnector(HostedSslConnectorFactory.withDefaultCertificateAndTruststore(serverName));
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java
index f8046bfe92d..13c1631e0ce 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java
@@ -824,6 +824,7 @@ public class ContainerModelBuilderTest extends ContainerModelBuilderTestBase {
ConnectorConfig connectorConfig = new ConnectorConfig(builder);
assertTrue(connectorConfig.ssl().enabled());
+ assertEquals(ConnectorConfig.Ssl.ClientAuth.Enum.WANT_AUTH, connectorConfig.ssl().clientAuth());
assertEquals("CERT", connectorConfig.ssl().certificate());
assertEquals("KEY", connectorConfig.ssl().privateKey());
assertEquals(4443, connectorConfig.listenPort());
@@ -833,6 +834,43 @@ public class ContainerModelBuilderTest extends ContainerModelBuilderTestBase {
assertThat(connectorConfig.ssl().caCertificate(), isEmptyString());
}
+ @Test
+ public void requireThatClientAuthenticationIsEnforced() {
+ Element clusterElem = DomBuilderTest.parse(
+ "<container version='1.0'>",
+ nodesXml,
+ " <http><filtering>" +
+ " <access-control domain=\"vespa\" tls-handshake-client-auth=\"need\"/>" +
+ " </filtering></http>" +
+ "</container>" );
+
+ DeployState state = new DeployState.Builder().properties(
+ new TestProperties()
+ .setHostedVespa(true)
+ .setEndpointCertificateSecrets(Optional.of(new EndpointCertificateSecrets("CERT", "KEY")))
+ .useAccessControlTlsHandshakeClientAuth(true))
+ .build();
+ createModel(root, state, null, clusterElem);
+ ApplicationContainer container = (ApplicationContainer)root.getProducer("container/container.0");
+
+ List<ConnectorFactory> connectorFactories = container.getHttp().getHttpServer().get().getConnectorFactories();
+ ConnectorFactory tlsPort = connectorFactories.stream().filter(connectorFactory -> connectorFactory.getListenPort() == 4443).findFirst().orElseThrow();
+
+ ConnectorConfig.Builder builder = new ConnectorConfig.Builder();
+ tlsPort.getConfig(builder);
+
+ ConnectorConfig connectorConfig = new ConnectorConfig(builder);
+ assertTrue(connectorConfig.ssl().enabled());
+ assertEquals(ConnectorConfig.Ssl.ClientAuth.Enum.NEED_AUTH, connectorConfig.ssl().clientAuth());
+ assertEquals("CERT", connectorConfig.ssl().certificate());
+ assertEquals("KEY", connectorConfig.ssl().privateKey());
+ assertEquals(4443, connectorConfig.listenPort());
+
+ assertThat("Connector must use Athenz truststore in a non-public system.",
+ connectorConfig.ssl().caCertificateFile(), equalTo("/opt/yahoo/share/ssl/certs/athenz_certificate_bundle.pem"));
+ assertThat(connectorConfig.ssl().caCertificate(), isEmptyString());
+ }
+
private Element generateContainerElementWithRenderer(String rendererId) {
return DomBuilderTest.parse(