summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java2
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzIdentityVerifier.java36
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/zone/ZoneRegistry.java4
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java10
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/proxy/ConfigServerRestExecutorImpl.java36
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/VersionStatus.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ZoneRegistryMock.java5
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java6
-rw-r--r--filedistribution/src/main/java/com/yahoo/vespa/filedistribution/FileReferenceDownloader.java2
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java2
-rw-r--r--jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscSslContextFactory.java36
11 files changed, 119 insertions, 22 deletions
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java
index c19ae86157a..5005ddf309d 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/Deployment.java
@@ -126,7 +126,7 @@ public class Deployment implements com.yahoo.config.provision.Deployment {
log.log(LogLevel.DEBUG, "Trying to acquire lock " + activateLock + " for session " + sessionId);
boolean acquired = activateLock.acquire(timeoutBudget, ignoreLockFailure);
if ( ! acquired) {
- throw new InternalServerException("Did not get activate lock for session " + sessionId + " within " + timeout);
+ throw new ActivationConflictException("Did not get activate lock for session " + sessionId + " within " + timeout);
}
log.log(LogLevel.DEBUG, "Lock acquired " + activateLock + " for session " + sessionId);
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzIdentityVerifier.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzIdentityVerifier.java
index bfaa6c2acda..527efaab946 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzIdentityVerifier.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzIdentityVerifier.java
@@ -1,21 +1,26 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.api.integration.athenz;
+import org.apache.http.conn.ssl.X509HostnameVerifier;
+
import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLException;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
import java.security.cert.X509Certificate;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
- * A {@link HostnameVerifier} that validates Athenz x509 certificates using the identity in the Common Name attribute.
+ * A {@link HostnameVerifier} / {@link X509HostnameVerifier} that validates
+ * Athenz x509 certificates using the identity in the Common Name attribute.
*
* @author bjorncs
*/
// TODO Move to dedicated Athenz bundle
-public class AthenzIdentityVerifier implements HostnameVerifier {
+public class AthenzIdentityVerifier implements X509HostnameVerifier {
private static final Logger log = Logger.getLogger(AthenzIdentityVerifier.class.getName());
@@ -29,13 +34,36 @@ public class AthenzIdentityVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
try {
X509Certificate cert = (X509Certificate) session.getPeerCertificates()[0];
- AthenzIdentity certificateIdentity = AthenzUtils.createAthenzIdentity(cert);
- return allowedIdentities.contains(certificateIdentity);
+ return isTrusted(AthenzUtils.createAthenzIdentity(cert));
} catch (SSLPeerUnverifiedException e) {
log.log(Level.WARNING, "Unverified client: " + hostname);
return false;
}
}
+ @Override
+ public void verify(String host, SSLSocket ssl) {
+ // all sockets allowed
+ }
+
+ @Override
+ public void verify(String hostname, X509Certificate certificate) throws SSLException {
+ AthenzIdentity identity = AthenzUtils.createAthenzIdentity(certificate);
+ if (!isTrusted(identity)) {
+ throw new SSLException("Athenz identity is not trusted: " + identity.getFullName());
+ }
+ }
+
+ @Override
+ public void verify(String hostname, String[] cns, String[] subjectAlts) throws SSLException {
+ AthenzIdentity identity = AthenzUtils.createAthenzIdentity(cns[0]);
+ if (!isTrusted(identity)) {
+ throw new SSLException("Athenz identity is not trusted: " + identity.getFullName());
+ }
+ }
+
+ private boolean isTrusted(AthenzIdentity identity) {
+ return allowedIdentities.contains(identity);
+ }
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/zone/ZoneRegistry.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/zone/ZoneRegistry.java
index 03207d86983..e95c297b593 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/zone/ZoneRegistry.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/zone/ZoneRegistry.java
@@ -5,6 +5,7 @@ import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.SystemName;
import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
+import com.yahoo.vespa.hosted.controller.api.integration.athenz.AthenzService;
import java.net.URI;
import java.time.Duration;
@@ -52,4 +53,7 @@ public interface ZoneRegistry {
/** Returns the system of this registry. */
SystemName system();
+ /** Return the configserver's Athenz service identity */
+ AthenzService getConfigserverAthenzService(ZoneId zoneId);
+
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java
index e2fca415f4e..44e4cf0740f 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java
@@ -13,6 +13,7 @@ import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
import com.yahoo.vespa.hosted.controller.api.identifiers.Property;
import com.yahoo.vespa.hosted.controller.api.identifiers.PropertyId;
import com.yahoo.vespa.hosted.controller.api.integration.MetricsService;
+import com.yahoo.vespa.hosted.controller.api.integration.athenz.AthenzClientFactory;
import com.yahoo.vespa.hosted.controller.api.integration.chef.Chef;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServerClient;
import com.yahoo.vespa.hosted.controller.api.integration.dns.NameService;
@@ -23,7 +24,6 @@ import com.yahoo.vespa.hosted.controller.api.integration.routing.GlobalRoutingSe
import com.yahoo.vespa.hosted.controller.api.integration.routing.RotationStatus;
import com.yahoo.vespa.hosted.controller.api.integration.routing.RoutingGenerator;
import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneRegistry;
-import com.yahoo.vespa.hosted.controller.api.integration.athenz.AthenzClientFactory;
import com.yahoo.vespa.hosted.controller.persistence.ControllerDb;
import com.yahoo.vespa.hosted.controller.persistence.CuratorDb;
import com.yahoo.vespa.hosted.controller.versions.VersionStatus;
@@ -156,9 +156,17 @@ public class Controller extends AbstractComponent {
return zoneRegistry.getLogServerUri(deploymentId);
}
+ /**
+ * @deprecated Use {@link #getSecureConfigServerUris(ZoneId)} instead
+ */
+ @Deprecated
public List<URI> getConfigServerUris(ZoneId zoneId) {
return zoneRegistry.getConfigServerUris(zoneId);
}
+
+ public List<URI> getSecureConfigServerUris(ZoneId zoneId) {
+ return zoneRegistry.getConfigServerSecureUris(zoneId);
+ }
public ZoneRegistry zoneRegistry() { return zoneRegistry; }
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/proxy/ConfigServerRestExecutorImpl.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/proxy/ConfigServerRestExecutorImpl.java
index e8689a06162..7d06bbde081 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/proxy/ConfigServerRestExecutorImpl.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/proxy/ConfigServerRestExecutorImpl.java
@@ -3,10 +3,13 @@ package com.yahoo.vespa.hosted.controller.proxy;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.Inject;
import com.yahoo.config.provision.Environment;
-import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import com.yahoo.io.IOUtils;
import com.yahoo.jdisc.http.HttpRequest.Method;
+import com.yahoo.vespa.hosted.controller.api.integration.athenz.AthenzIdentityVerifier;
+import com.yahoo.vespa.hosted.controller.api.integration.athenz.AthenzSslContextProvider;
+import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneList;
import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneRegistry;
import org.apache.http.Header;
@@ -34,8 +37,11 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import static java.util.Collections.singleton;
+
/**
* @author Haakon Dybdahl
+ * @author bjorncs
*/
@SuppressWarnings("unused") // Injected
public class ConfigServerRestExecutorImpl implements ConfigServerRestExecutor {
@@ -43,9 +49,13 @@ public class ConfigServerRestExecutorImpl implements ConfigServerRestExecutor {
private static final Duration PROXY_REQUEST_TIMEOUT = Duration.ofSeconds(10);
private final ZoneRegistry zoneRegistry;
+ private final AthenzSslContextProvider sslContextProvider;
- public ConfigServerRestExecutorImpl(ZoneRegistry zoneRegistry) {
+ @Inject
+ public ConfigServerRestExecutorImpl(ZoneRegistry zoneRegistry,
+ AthenzSslContextProvider sslContextProvider) {
this.zoneRegistry = zoneRegistry;
+ this.sslContextProvider = sslContextProvider;
}
@Override
@@ -57,10 +67,10 @@ public class ConfigServerRestExecutorImpl implements ConfigServerRestExecutor {
ZoneId zoneId = ZoneId.from(proxyRequest.getEnvironment(), proxyRequest.getRegion());
// Make a local copy of the list as we want to manipulate it in case of ping problems.
- List<URI> allServers = new ArrayList<>(zoneRegistry.getConfigServerUris(zoneId));
+ List<URI> allServers = new ArrayList<>(zoneRegistry.getConfigServerSecureUris(zoneId));
StringBuilder errorBuilder = new StringBuilder();
- if (queueFirstServerIfDown(allServers)) {
+ if (queueFirstServerIfDown(allServers, proxyRequest)) {
errorBuilder.append("Change ordering due to failed ping.");
}
for (URI uri : allServers) {
@@ -115,7 +125,7 @@ public class ConfigServerRestExecutorImpl implements ConfigServerRestExecutor {
.setConnectionRequestTimeout((int) PROXY_REQUEST_TIMEOUT.toMillis())
.setSocketTimeout((int) PROXY_REQUEST_TIMEOUT.toMillis()).build();
try (
- CloseableHttpClient client = createHttpClient(config);
+ CloseableHttpClient client = createHttpClient(config, sslContextProvider, zoneRegistry, proxyRequest);
CloseableHttpResponse response = client.execute(requestBase);
) {
if (response.getStatusLine().getStatusCode() / 100 == 5) {
@@ -202,7 +212,7 @@ public class ConfigServerRestExecutorImpl implements ConfigServerRestExecutor {
* if it is not responding, we try the other servers first. False positive/negatives are not critical,
* but will increase latency to some extent.
*/
- private boolean queueFirstServerIfDown(List<URI> allServers) {
+ private boolean queueFirstServerIfDown(List<URI> allServers, ProxyRequest proxyRequest) {
if (allServers.size() < 2) {
return false;
}
@@ -215,7 +225,7 @@ public class ConfigServerRestExecutorImpl implements ConfigServerRestExecutor {
.setConnectionRequestTimeout(timeout)
.setSocketTimeout(timeout).build();
try (
- CloseableHttpClient client = createHttpClient(config);
+ CloseableHttpClient client = createHttpClient(config, sslContextProvider, zoneRegistry, proxyRequest);
CloseableHttpResponse response = client.execute(httpget);
) {
@@ -232,9 +242,19 @@ public class ConfigServerRestExecutorImpl implements ConfigServerRestExecutor {
return true;
}
- private static CloseableHttpClient createHttpClient(RequestConfig config) {
+ private static CloseableHttpClient createHttpClient(RequestConfig config,
+ AthenzSslContextProvider sslContextProvider,
+ ZoneRegistry zoneRegistry,
+ ProxyRequest proxyRequest) {
+ AthenzIdentityVerifier hostnameVerifier =
+ new AthenzIdentityVerifier(
+ singleton(
+ zoneRegistry.getConfigserverAthenzService(
+ ZoneId.from(proxyRequest.getEnvironment(), proxyRequest.getRegion()))));
return HttpClientBuilder.create()
.setUserAgent("config-server-client")
+ .setSslcontext(sslContextProvider.get())
+ .setHostnameVerifier(hostnameVerifier)
.setDefaultRequestConfig(config)
.build();
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/VersionStatus.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/VersionStatus.java
index 647000aebab..13eec52b97a 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/VersionStatus.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/VersionStatus.java
@@ -122,7 +122,7 @@ public class VersionStatus {
List<URI> configServers = controller.zoneRegistry().zones()
.controllerManaged()
.ids().stream()
- .flatMap(zoneId -> controller.getConfigServerUris(zoneId).stream())
+ .flatMap(zoneId -> controller.getSecureConfigServerUris(zoneId).stream())
.collect(Collectors.toList());
ListMap<Version, String> versions = new ListMap<>();
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ZoneRegistryMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ZoneRegistryMock.java
index 82434b6260c..21072f0b162 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ZoneRegistryMock.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/ZoneRegistryMock.java
@@ -8,6 +8,7 @@ import com.yahoo.config.provision.RegionName;
import com.yahoo.config.provision.SystemName;
import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneId;
import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
+import com.yahoo.vespa.hosted.controller.api.integration.athenz.AthenzService;
import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneRegistry;
import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneFilter;
import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneFilterMock;
@@ -68,6 +69,10 @@ public class ZoneRegistryMock extends AbstractComponent implements ZoneRegistry
return ZoneFilterMock.from(Collections.unmodifiableList(zones));
}
+ public AthenzService getConfigserverAthenzService(ZoneId zone) {
+ return new AthenzService("vespadomain", "provider-" + zone.environment().value() + "-" + zone.region().value());
+ }
+
@Override
public boolean hasZone(ZoneId zoneId) {
return zones.contains(zoneId);
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java
index 4f97c078c9b..1c1e2df2c94 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/versions/VersionStatusTest.java
@@ -11,8 +11,6 @@ import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.ControllerTester;
import com.yahoo.vespa.hosted.controller.api.identifiers.TenantId;
import com.yahoo.vespa.hosted.controller.application.ApplicationPackage;
-import com.yahoo.vespa.hosted.controller.application.DeploymentJobs;
-import com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobError;
import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder;
import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester;
import com.yahoo.vespa.hosted.controller.versions.VespaVersion.Confidence;
@@ -21,7 +19,6 @@ import org.junit.Test;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Duration;
-import java.util.Collections;
import java.util.List;
import static com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobType.component;
@@ -31,7 +28,6 @@ import static com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobTy
import static com.yahoo.vespa.hosted.controller.application.DeploymentJobs.JobType.systemTest;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/**
@@ -61,7 +57,7 @@ public class VersionStatusTest {
public void testSystemVersionIsVersionOfOldestConfigServer() throws URISyntaxException {
ControllerTester tester = new ControllerTester();
Version oldest = new Version(5);
- tester.configServer().versions().put(new URI("http://cfg.prod.corp-us-east-1.test"), oldest);
+ tester.configServer().versions().put(new URI("https://cfg.prod.corp-us-east-1.test:4443"), oldest);
VersionStatus versionStatus = VersionStatus.compute(tester.controller());
assertEquals(oldest, versionStatus.systemVersion().get().versionNumber());
}
diff --git a/filedistribution/src/main/java/com/yahoo/vespa/filedistribution/FileReferenceDownloader.java b/filedistribution/src/main/java/com/yahoo/vespa/filedistribution/FileReferenceDownloader.java
index 031506487a8..d3715a1ff89 100644
--- a/filedistribution/src/main/java/com/yahoo/vespa/filedistribution/FileReferenceDownloader.java
+++ b/filedistribution/src/main/java/com/yahoo/vespa/filedistribution/FileReferenceDownloader.java
@@ -93,7 +93,7 @@ public class FileReferenceDownloader {
downloads.remove(fileReference);
download.future().set(Optional.of(file));
} else {
- log.log(LogLevel.WARNING, "Received a file " + fileReference + " I did not ask for. Impossible");
+ log.log(LogLevel.INFO, "Received '" + fileReference + "', which was not requested. Can be ignored if happening during upgrades/restarts");
}
}
}
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java
index 981d4219158..1f2fb40f42f 100644
--- a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java
@@ -94,7 +94,7 @@ public class ConnectorFactory {
private SslConnectionFactory newSslConnectionFactory() {
Ssl sslConfig = connectorConfig.ssl();
- SslContextFactory factory = new SslContextFactory();
+ SslContextFactory factory = new JDiscSslContextFactory();
sslKeyStoreConfigurator.configure(new DefaultSslKeyStoreContext(factory));
sslTrustStoreConfigurator.configure(new DefaultSslTrustStoreContext(factory));
diff --git a/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscSslContextFactory.java b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscSslContextFactory.java
new file mode 100644
index 00000000000..81a6a0c8048
--- /dev/null
+++ b/jdisc_http_service/src/main/java/com/yahoo/jdisc/http/server/jetty/JDiscSslContextFactory.java
@@ -0,0 +1,36 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.jdisc.http.server.jetty;
+
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.util.security.CertificateUtils;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+
+import java.security.KeyStore;
+import java.util.Objects;
+
+/**
+ * A modified {@link SslContextFactory} that allows passwordless truststore in combination with password protected keystore.
+ *
+ * @author bjorncs
+ */
+class JDiscSslContextFactory extends SslContextFactory {
+
+ private String trustStorePassword;
+
+ @Override
+ public void setTrustStorePassword(String password) {
+ super.setTrustStorePassword(password);
+ this.trustStorePassword = password;
+ }
+
+
+ // Overriden to stop Jetty from using the keystore password if no truststore password is specified.
+ @Override
+ protected KeyStore loadTrustStore(Resource resource) throws Exception {
+ return CertificateUtils.getKeyStore(
+ resource != null ? resource : getKeyStoreResource(),
+ Objects.toString(getTrustStoreType(), getKeyStoreType()),
+ Objects.toString(getTrustStoreProvider(), getKeyStoreProvider()),
+ trustStorePassword);
+ }
+}