aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorØyvind Grønnesby <oyving@verizonmedia.com>2019-08-14 14:46:50 +0200
committerGitHub <noreply@github.com>2019-08-14 14:46:50 +0200
commit73757bb8992ce337cb26640834f928577fe9125a (patch)
tree6341e9bf8d230a41e76781993e452648b1da8762
parent0a4669d973810e02fd7a6be10b5a1ee03142d5b4 (diff)
parent6db214234310b8e2841d964c610cf5dcf01b747b (diff)
Merge pull request #10238 from vespa-engine/ogronnesby/propagate-ca-in-config
Add the CA certificates to configuration and read it from app package
-rw-r--r--config-model-api/abi-spec.json2
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/ApplicationPackage.java6
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/TlsSecrets.java16
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java19
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainer.java19
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainerCluster.java11
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/ConfiguredDirectSslProvider.java5
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java18
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerServiceBuilder.java9
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/content/Content.java2
-rwxr-xr-xconfig-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java2
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilderTest.java43
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClient.java3
-rw-r--r--jdisc_http_service/abi-spec.json2
-rw-r--r--jdisc_http_service/src/main/resources/configdefinitions/jdisc.http.connector.def7
15 files changed, 143 insertions, 21 deletions
diff --git a/config-model-api/abi-spec.json b/config-model-api/abi-spec.json
index 9f86fe4dea2..8d83d16a272 100644
--- a/config-model-api/abi-spec.json
+++ b/config-model-api/abi-spec.json
@@ -111,6 +111,7 @@
"public java.util.List getQueryProfileFiles()",
"public java.util.List getQueryProfileTypeFiles()",
"public java.util.List getPageTemplateFiles()",
+ "public com.yahoo.config.application.api.ApplicationFile getClientSecurityFile()",
"public abstract java.lang.String getHostSource()",
"public abstract java.lang.String getServicesSource()",
"public abstract java.util.Optional getDeployment()",
@@ -148,6 +149,7 @@
"public static final com.yahoo.path.Path RULES_DIR",
"public static final com.yahoo.path.Path DEPLOYMENT_FILE",
"public static final com.yahoo.path.Path VALIDATION_OVERRIDES",
+ "public static final com.yahoo.path.Path SECURITY_DIR",
"public static final java.lang.String SD_NAME_SUFFIX",
"public static final java.lang.String RANKEXPRESSION_NAME_SUFFIX",
"public static final java.lang.String RULES_NAME_SUFFIX",
diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/ApplicationPackage.java b/config-model-api/src/main/java/com/yahoo/config/application/api/ApplicationPackage.java
index 06f8034453d..5cd119dcf65 100644
--- a/config-model-api/src/main/java/com/yahoo/config/application/api/ApplicationPackage.java
+++ b/config-model-api/src/main/java/com/yahoo/config/application/api/ApplicationPackage.java
@@ -27,7 +27,6 @@ import java.util.Map;
import java.util.Optional;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
-import java.util.stream.Collectors;
/**
* Represents an application package, that is, used as input when creating a VespaModel and as
@@ -73,6 +72,8 @@ public interface ApplicationPackage {
Path DEPLOYMENT_FILE = Path.fromString("deployment.xml");
Path VALIDATION_OVERRIDES = Path.fromString("validation-overrides.xml");
+ Path SECURITY_DIR = Path.fromString("security");
+
String SD_NAME_SUFFIX = ".sd";
String RANKEXPRESSION_NAME_SUFFIX = ".expression";
String RULES_NAME_SUFFIX = ".sr";
@@ -178,6 +179,9 @@ public interface ApplicationPackage {
/** Does {@link #getFiles} on the page template directory and gets all xml files */
default List<NamedReader> getPageTemplateFiles() { return getFiles(PAGE_TEMPLATES_DIR,".xml"); }
+ /** Returns handle for the file containing client certificate authorities */
+ default ApplicationFile getClientSecurityFile() { return getFile(SECURITY_DIR.append("clients.pem")); }
+
//For generating error messages
String getHostSource();
String getServicesSource();
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/TlsSecrets.java b/config-model-api/src/main/java/com/yahoo/config/model/api/TlsSecrets.java
index 3cb4cedcbac..6a8b5a237ab 100644
--- a/config-model-api/src/main/java/com/yahoo/config/model/api/TlsSecrets.java
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/TlsSecrets.java
@@ -1,30 +1,30 @@
// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.config.model.api;
- public class TlsSecrets {
+public class TlsSecrets {
public static final TlsSecrets MISSING = new TlsSecrets();
- private final String certificate;
+ private final String certificate;
private final String key;
- private TlsSecrets() {
- this(null,null);
+ private TlsSecrets() {
+ this(null, null);
}
- public TlsSecrets(String certificate, String key) {
+ public TlsSecrets(String certificate, String key) {
this.certificate = certificate;
this.key = key;
}
- public String certificate() {
+ public String certificate() {
return certificate;
}
- public String key() {
+ public String key() {
return key;
}
- public boolean isMissing() {
+ public boolean isMissing() {
return this == MISSING;
}
}
diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java b/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java
index 86c20bf96af..e8e12888768 100644
--- a/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java
+++ b/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java
@@ -24,6 +24,7 @@ import com.yahoo.config.model.provision.SingleNodeProvisioner;
import com.yahoo.config.model.test.MockApplicationPackage;
import com.yahoo.config.provision.Rotation;
import com.yahoo.config.provision.Zone;
+import com.yahoo.io.IOUtils;
import com.yahoo.io.reader.NamedReader;
import com.yahoo.searchdefinition.RankProfileRegistry;
import com.yahoo.searchdefinition.SearchBuilder;
@@ -39,8 +40,10 @@ import com.yahoo.vespa.model.container.search.SemanticRules;
import com.yahoo.vespa.model.search.SearchDefinition;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Reader;
+import java.io.UncheckedIOException;
import java.time.Instant;
import java.util.Collection;
import java.util.Collections;
@@ -263,6 +266,22 @@ public class DeployState implements ConfigDefinitionStore {
public Optional<TlsSecrets> tlsSecrets() { return properties.tlsSecrets(); }
+ public Optional<String> tlsClientAuthority() {
+ var caFile = applicationPackage.getClientSecurityFile();
+ if (caFile.exists()) {
+ try {
+ var caPem = IOUtils.readAll(caFile.createReader());
+ return Optional.of(caPem);
+ } catch (FileNotFoundException e) {
+ return Optional.empty();
+ } catch (IOException e) {
+ throw new UncheckedIOException("Failed reading certificate from application: " + caFile.getPath(), e);
+ }
+ } else {
+ return Optional.empty();
+ }
+ }
+
public static class Builder {
private ApplicationPackage applicationPackage = MockApplicationPackage.createEmpty();
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainer.java b/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainer.java
index d27812a80dd..82f0c87d074 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainer.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainer.java
@@ -26,11 +26,11 @@ public final class ApplicationContainer extends Container {
private final boolean isHostedVespa;
- public ApplicationContainer(AbstractConfigProducer parent, String name, int index, boolean isHostedVespa, Optional<TlsSecrets> tlsSecrets) {
- this(parent, name, false, index, isHostedVespa, tlsSecrets);
+ public ApplicationContainer(AbstractConfigProducer parent, String name, int index, boolean isHostedVespa, Optional<TlsSecrets> tlsSecrets, Optional<String> tlsCa) {
+ this(parent, name, false, index, isHostedVespa, tlsSecrets, tlsCa);
}
- public ApplicationContainer(AbstractConfigProducer parent, String name, boolean retired, int index, boolean isHostedVespa, Optional<TlsSecrets> tlsSecrets) {
+ public ApplicationContainer(AbstractConfigProducer parent, String name, boolean retired, int index, boolean isHostedVespa, Optional<TlsSecrets> tlsSecrets, Optional<String> tlsCa) {
super(parent, name, retired, index);
this.isHostedVespa = isHostedVespa;
@@ -40,8 +40,17 @@ public final class ApplicationContainer extends Container {
JettyHttpServer server = Optional.ofNullable(getHttp())
.map(Http::getHttpServer)
.orElse(getDefaultHttpServer());
- server.addConnector(new ConnectorFactory(connectorName, 4443,
- new ConfiguredDirectSslProvider(server.getComponentId().getName(), tlsSecrets.get().key(), tlsSecrets.get().certificate(), null, null)));
+
+ var sslProvider = new ConfiguredDirectSslProvider(
+ server.getComponentId().getName(),
+ tlsSecrets.get().key(),
+ tlsSecrets.get().certificate(),
+ null,
+ tlsCa.orElse(null),
+ null
+ );
+
+ server.addConnector(new ConnectorFactory(connectorName, 4443, sslProvider));
}
addComponent(getFS4ResourcePool()); // TODO Remove when FS4 based search protocol is gone
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainerCluster.java
index 473971c5e7a..2b9cd18d64b 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainerCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/ApplicationContainerCluster.java
@@ -56,6 +56,8 @@ public final class ApplicationContainerCluster extends ContainerCluster<Applicat
private ContainerModelEvaluation modelEvaluation;
private Optional<TlsSecrets> tlsSecrets;
+ private Optional<String> tlsClientAuthority;
+ private boolean useTlsClientAuthority = false;
private final boolean enableGroupingSessionCache;
private MbusParams mbusParams;
@@ -65,6 +67,7 @@ public final class ApplicationContainerCluster extends ContainerCluster<Applicat
super(parent, subId, name, deployState);
this.tlsSecrets = deployState.tlsSecrets();
+ this.tlsClientAuthority = deployState.tlsClientAuthority();
this.enableGroupingSessionCache = deployState.getProperties().enableGroupingSessionCache();
restApiGroup = new ConfigProducerGroup<>(this, "rest-api");
servletGroup = new ConfigProducerGroup<>(this, "servlet");
@@ -183,6 +186,10 @@ public final class ApplicationContainerCluster extends ContainerCluster<Applicat
return tlsSecrets;
}
+ public Optional<String> getTlsClientAuthority() {
+ return tlsClientAuthority;
+ }
+
public boolean enableGroupingSessionCache() {
return enableGroupingSessionCache;
}
@@ -205,6 +212,10 @@ public final class ApplicationContainerCluster extends ContainerCluster<Applicat
null))));
}
+ public void useTlsClientAuthority(boolean value) {
+ this.useTlsClientAuthority = value;
+ }
+
public static class MbusParams {
// the amount of the maxpendingbytes to process concurrently, typically 0.2 (20%)
final Double maxConcurrentFactor;
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/ConfiguredDirectSslProvider.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/ConfiguredDirectSslProvider.java
index 28dba3331d3..b47aa501ece 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/ConfiguredDirectSslProvider.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/ssl/ConfiguredDirectSslProvider.java
@@ -26,9 +26,10 @@ public class ConfiguredDirectSslProvider extends SimpleComponent implements Conn
private final String privateKey;
private final String certificate;
private final String caCertificatePath;
+ private final String caCertificate;
private final ConnectorConfig.Ssl.ClientAuth.Enum clientAuthentication;
- public ConfiguredDirectSslProvider(String servername, String privateKey, String certificate, String caCertificatePath, String clientAuthentication) {
+ public ConfiguredDirectSslProvider(String servername, String privateKey, String certificate, String caCertificatePath, String caCertificate, String clientAuthentication) {
super(new ComponentModel(
new BundleInstantiationSpecification(new ComponentId(COMPONENT_ID_PREFIX+servername),
fromString(COMPONENT_CLASS),
@@ -36,6 +37,7 @@ public class ConfiguredDirectSslProvider extends SimpleComponent implements Conn
this.privateKey = privateKey;
this.certificate = certificate;
this.caCertificatePath = caCertificatePath;
+ this.caCertificate = caCertificate;
this.clientAuthentication = mapToConfigEnum(clientAuthentication);
}
@@ -45,6 +47,7 @@ public class ConfiguredDirectSslProvider extends SimpleComponent implements Conn
builder.ssl.privateKey(privateKey);
builder.ssl.certificate(certificate);
builder.ssl.caCertificateFile(Optional.ofNullable(caCertificatePath).orElse(""));
+ builder.ssl.caCertificate(Optional.ofNullable(caCertificate).orElse(""));
builder.ssl.clientAuth(clientAuthentication);
}
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 2bfb1da9dcb..00aa5423087 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
@@ -192,9 +192,21 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
addClientProviders(deployState, spec, cluster);
addServerProviders(deployState, spec, cluster);
+ addTlsClientAuthority(deployState, spec, cluster);
+
addAthensCopperArgos(cluster, context); // Must be added after nodes.
}
+ private void addTlsClientAuthority(DeployState deployState, Element spec, ApplicationContainerCluster cluster) {
+ var clientAuthorized = XML.getChild(spec, "client-authorize");
+ if (clientAuthorized != null) {
+ if (deployState.tlsClientAuthority().isEmpty()) {
+ throw new RuntimeException("client-authorize set, but security/clients.pem is missing");
+ }
+ cluster.useTlsClientAuthority(true);
+ }
+ }
+
private void addSecretStore(ApplicationContainerCluster cluster, Element spec) {
Element secretStoreElement = XML.getChild(spec, "secret-store");
if (secretStoreElement != null) {
@@ -440,7 +452,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
}
private void addStandaloneNode(ApplicationContainerCluster cluster) {
- ApplicationContainer container = new ApplicationContainer(cluster, "standalone", cluster.getContainers().size(), cluster.isHostedVespa(), cluster.getTlsSecrets());
+ ApplicationContainer container = new ApplicationContainer(cluster, "standalone", cluster.getContainers().size(), cluster.isHostedVespa(), cluster.getTlsSecrets(), cluster.getTlsClientAuthority());
cluster.addContainers(Collections.singleton(container));
}
@@ -506,7 +518,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
Element nodesElement = XML.getChild(containerElement, "nodes");
Element rotationsElement = XML.getChild(containerElement, "rotations");
if (nodesElement == null) { // default single node on localhost
- ApplicationContainer node = new ApplicationContainer(cluster, "container.0", 0, cluster.isHostedVespa(), cluster.getTlsSecrets());
+ ApplicationContainer node = new ApplicationContainer(cluster, "container.0", 0, cluster.isHostedVespa(), cluster.getTlsSecrets(), cluster.getTlsClientAuthority());
HostResource host = allocateSingleNodeHost(cluster, log, containerElement, context);
node.setHostResource(host);
node.initService(context.getDeployLogger());
@@ -695,7 +707,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
List<ApplicationContainer> nodes = new ArrayList<>();
for (Map.Entry<HostResource, ClusterMembership> entry : hosts.entrySet()) {
String id = "container." + entry.getValue().index();
- ApplicationContainer container = new ApplicationContainer(cluster, id, entry.getValue().retired(), entry.getValue().index(), cluster.isHostedVespa(), cluster.getTlsSecrets());
+ ApplicationContainer container = new ApplicationContainer(cluster, id, entry.getValue().retired(), entry.getValue().index(), cluster.isHostedVespa(), cluster.getTlsSecrets(), cluster.getTlsClientAuthority());
container.setHostResource(entry.getKey());
container.initService(deployLogger);
nodes.add(container);
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerServiceBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerServiceBuilder.java
index 46271d3c0a2..c976a7fb153 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerServiceBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerServiceBuilder.java
@@ -22,7 +22,14 @@ public class ContainerServiceBuilder extends VespaDomBuilder.DomConfigProducerBu
@Override
protected ApplicationContainer doBuild(DeployState deployState, AbstractConfigProducer parent, Element nodeElem) {
- return new ApplicationContainer(parent, id, index, deployState.isHosted(), deployState.tlsSecrets());
+ return new ApplicationContainer(
+ parent,
+ id,
+ index,
+ deployState.isHosted(),
+ deployState.tlsSecrets(),
+ deployState.tlsClientAuthority()
+ );
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/Content.java b/config-model/src/main/java/com/yahoo/vespa/model/content/Content.java
index 8eda707be99..f028f0ac0cc 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/content/Content.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/content/Content.java
@@ -324,7 +324,7 @@ public class Content extends ConfigModel {
if (!processedHosts.contains(host)) {
String containerName = String.valueOf(searchNode.getDistributionKey());
ApplicationContainer docprocService = new ApplicationContainer(indexingCluster, containerName, index,
- modelContext.getDeployState().isHosted(), modelContext.getDeployState().tlsSecrets());
+ modelContext.getDeployState().isHosted(), modelContext.getDeployState().tlsSecrets(), Optional.empty());
index++;
docprocService.useDynamicPorts();
docprocService.setHostResource(host);
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java
index ac85a958ed5..89169c44079 100755
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java
@@ -252,7 +252,7 @@ public class ContainerClusterTest {
}
private static void addContainer(DeployLogger deployLogger, ApplicationContainerCluster cluster, String name, String hostName) {
- ApplicationContainer container = new ApplicationContainer(cluster, name, 0, cluster.isHostedVespa(), cluster.getTlsSecrets());
+ ApplicationContainer container = new ApplicationContainer(cluster, name, 0, cluster.isHostedVespa(), cluster.getTlsSecrets(), cluster.getTlsClientAuthority());
container.setHostResource(new HostResource(new Host(null, hostName)));
container.initService(deployLogger);
cluster.addContainer(container);
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 8b92e1091ca..e4fcf6305ed 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
@@ -25,6 +25,7 @@ import com.yahoo.container.servlet.ServletConfigConfig;
import com.yahoo.container.usability.BindingsOverviewHandler;
import com.yahoo.jdisc.http.ServletPathsConfig;
import com.yahoo.net.HostName;
+import com.yahoo.path.Path;
import com.yahoo.prelude.cluster.QrMonitorConfig;
import com.yahoo.search.config.QrStartConfig;
import com.yahoo.vespa.model.AbstractService;
@@ -35,13 +36,18 @@ import com.yahoo.vespa.model.container.SecretStore;
import com.yahoo.vespa.model.container.component.Component;
import com.yahoo.vespa.model.content.utils.ContentClusterUtils;
import com.yahoo.vespa.model.test.utils.VespaModelCreatorWithFilePkg;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
+import java.io.File;
import java.io.IOException;
+import java.io.StringReader;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
import java.util.stream.Collectors;
@@ -72,6 +78,8 @@ import static org.junit.Assert.fail;
* @author gjoranv
*/
public class ContainerModelBuilderTest extends ContainerModelBuilderTestBase {
+ @Rule
+ public TemporaryFolder applicationFolder = new TemporaryFolder();
@Test
public void deprecated_jdisc_tag_is_allowed() {
@@ -645,6 +653,41 @@ public class ContainerModelBuilderTest extends ContainerModelBuilderTestBase {
}
@Test
+ public void client_ca_carts_fail_with_missing_clients_pem() {
+ Element clusterElem = DomBuilderTest.parse(
+ "<container version='1.0'>",
+ " <client-authorize />",
+ "</container>");
+ try {
+ createModel(root, clusterElem);
+ } catch (RuntimeException e) {
+ assertEquals(e.getMessage(), "client-authorize set, but security/clients.pem is missing");
+ return;
+ }
+ fail();
+ }
+
+ @Test
+ public void client_ca_carts_succeeds_with_client_authorize_and_clients_pem() {
+ var applicationPackage = new MockApplicationPackage.Builder()
+ .withRoot(applicationFolder.getRoot())
+ .build();
+
+ applicationPackage.getFile(Path.fromString("security")).createDirectory();
+ applicationPackage.getFile(Path.fromString("security/clients.pem")).writeFile(new StringReader("I am a very nice certificate"));
+
+ var deployState = DeployState.createTestState(applicationPackage);
+
+ Element clusterElem = DomBuilderTest.parse(
+ "<container version='1.0'>",
+ " <client-authorize />",
+ "</container>");
+
+ createModel(root, deployState, null, clusterElem);
+ assertEquals(Optional.of("I am a very nice certificate"), getContainerCluster("container").getTlsClientAuthority());
+ }
+
+ @Test
public void environment_vars_are_honoured() {
Element clusterElem = DomBuilderTest.parse(
"<container version='1.0'>",
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClient.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClient.java
index 484124991d9..a99a2a2917d 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClient.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ZooKeeperClient.java
@@ -202,6 +202,9 @@ public class ZooKeeperClient {
writeDir(app.getFile(ApplicationPackage.MODELS_GENERATED_REPLICATED_DIR),
getZooKeeperAppPath(ConfigCurator.USERAPP_ZK_SUBPATH).append(ApplicationPackage.MODELS_GENERATED_REPLICATED_DIR),
true);
+ writeDir(app.getFile(ApplicationPackage.SECURITY_DIR),
+ getZooKeeperAppPath(ConfigCurator.USERAPP_ZK_SUBPATH).append(ApplicationPackage.SECURITY_DIR),
+ true);
}
private void writeDir(ApplicationFile file, Path zooKeeperAppPath, boolean recurse) throws IOException {
diff --git a/jdisc_http_service/abi-spec.json b/jdisc_http_service/abi-spec.json
index 6f41c4ced06..6e04ba741e6 100644
--- a/jdisc_http_service/abi-spec.json
+++ b/jdisc_http_service/abi-spec.json
@@ -84,6 +84,7 @@
"public com.yahoo.jdisc.http.ConnectorConfig$Ssl$Builder certificateFile(java.lang.String)",
"public com.yahoo.jdisc.http.ConnectorConfig$Ssl$Builder certificate(java.lang.String)",
"public com.yahoo.jdisc.http.ConnectorConfig$Ssl$Builder caCertificateFile(java.lang.String)",
+ "public com.yahoo.jdisc.http.ConnectorConfig$Ssl$Builder caCertificate(java.lang.String)",
"public com.yahoo.jdisc.http.ConnectorConfig$Ssl$Builder clientAuth(com.yahoo.jdisc.http.ConnectorConfig$Ssl$ClientAuth$Enum)",
"public com.yahoo.jdisc.http.ConnectorConfig$Ssl build()"
],
@@ -139,6 +140,7 @@
"public java.lang.String certificateFile()",
"public java.lang.String certificate()",
"public java.lang.String caCertificateFile()",
+ "public java.lang.String caCertificate()",
"public com.yahoo.jdisc.http.ConnectorConfig$Ssl$ClientAuth$Enum clientAuth()"
],
"fields": []
diff --git a/jdisc_http_service/src/main/resources/configdefinitions/jdisc.http.connector.def b/jdisc_http_service/src/main/resources/configdefinitions/jdisc.http.connector.def
index c6de875417c..f02a0d7b4a3 100644
--- a/jdisc_http_service/src/main/resources/configdefinitions/jdisc.http.connector.def
+++ b/jdisc_http_service/src/main/resources/configdefinitions/jdisc.http.connector.def
@@ -69,8 +69,15 @@ ssl.certificateFile string default=""
ssl.certificate string default=""
# with trusted CA certificates in PEM format. Used to verify clients
+# - this is the name of a file on the local container file system
+# - only one of caCertificateFile and caCertificate
ssl.caCertificateFile string default=""
+# with trusted CA certificates in PEM format. Used to verify clients
+# - this is the actual certificates instead of a pointer to the file
+# - only one of caCertificateFile and caCertificate
+ssl.caCertificate string default=""
+
# Client authentication mode. See SSLEngine.getNeedClientAuth()/getWantClientAuth() for details.
ssl.clientAuth enum { DISABLED, WANT_AUTH, NEED_AUTH } default=DISABLED