diff options
author | Valerij Fredriksen <valerijf@oath.com> | 2018-01-23 09:45:22 +0100 |
---|---|---|
committer | Valerij Fredriksen <valerijf@oath.com> | 2018-01-23 09:51:34 +0100 |
commit | 522ed8a6a042e6ebae19af7047bce26739b03315 (patch) | |
tree | d3535534eadfe25d2737ee87818255401129f85c | |
parent | 193dcf4fdfdb0501cfe0e7d7198180185db1192f (diff) |
Add node-admin hostname verifier
5 files changed, 57 insertions, 11 deletions
diff --git a/node-admin/pom.xml b/node-admin/pom.xml index 7b3b787b503..a982a192b51 100644 --- a/node-admin/pom.xml +++ b/node-admin/pom.xml @@ -86,6 +86,12 @@ <version>${project.version}</version> <scope>compile</scope> </dependency> + <dependency> + <groupId>com.yahoo.vespa</groupId> + <artifactId>vespa-athenz</artifactId> + <version>${project.version}</version> + <scope>compile</scope> + </dependency> <dependency> <groupId>org.hamcrest</groupId> diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/DockerAdminComponent.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/DockerAdminComponent.java index db0313583db..0450229eae6 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/DockerAdminComponent.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/nodeadmin/DockerAdminComponent.java @@ -64,7 +64,11 @@ public class DockerAdminComponent implements AdminComponent { Environment environment = new Environment(configServerConfig); requestExecutor = ConfigServerHttpRequestExecutor.create( - environment.getConfigServerUris(), environment.getKeyStoreOptions(), environment.getTrustStoreOptions()); + environment.getConfigServerUris(), + environment.getKeyStoreOptions(), + environment.getTrustStoreOptions(), + environment.getAthenzIdentity()); + NodeRepository nodeRepository = new NodeRepositoryImpl(requestExecutor); Orchestrator orchestrator = new OrchestratorImpl(requestExecutor); diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/util/ConfigServerHttpRequestExecutor.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/util/ConfigServerHttpRequestExecutor.java index 954de4b271a..010fd99f124 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/util/ConfigServerHttpRequestExecutor.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/util/ConfigServerHttpRequestExecutor.java @@ -4,6 +4,8 @@ package com.yahoo.vespa.hosted.node.admin.util; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.yahoo.concurrent.ThreadFactoryFactory; +import com.yahoo.vespa.athenz.api.AthenzIdentity; +import com.yahoo.vespa.athenz.tls.AthenzIdentityVerifier; import org.apache.http.HttpHeaders; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpDelete; @@ -13,11 +15,11 @@ import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.entity.StringEntity; import org.apache.http.ssl.SSLContextBuilder; +import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -61,8 +63,11 @@ public class ConfigServerHttpRequestExecutor implements AutoCloseable { private volatile SelfCloseableHttpClient client; public static ConfigServerHttpRequestExecutor create( - Collection<URI> configServerUris, Optional<KeyStoreOptions> keyStoreOptions, Optional<KeyStoreOptions> trustStoreOptions) { - Supplier<SelfCloseableHttpClient> clientSupplier = () -> createHttpClient(keyStoreOptions, trustStoreOptions); + Collection<URI> configServerUris, + Optional<KeyStoreOptions> keyStoreOptions, + Optional<KeyStoreOptions> trustStoreOptions, + Optional<AthenzIdentity> athenzIdentity) { + Supplier<SelfCloseableHttpClient> clientSupplier = () -> createHttpClient(keyStoreOptions, trustStoreOptions, athenzIdentity); ConfigServerHttpRequestExecutor requestExecutor = new ConfigServerHttpRequestExecutor( randomizeConfigServerUris(configServerUris), clientSupplier.get()); @@ -178,11 +183,13 @@ public class ConfigServerHttpRequestExecutor implements AutoCloseable { } private static SelfCloseableHttpClient createHttpClient(Optional<KeyStoreOptions> keyStoreOptions, - Optional<KeyStoreOptions> trustStoreOptions) { + Optional<KeyStoreOptions> trustStoreOptions, + Optional<AthenzIdentity> athenzIdentity) { NODE_ADMIN_LOGGER.info("Creating new HTTP client"); try { - SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory( - makeSslContext(keyStoreOptions, trustStoreOptions), NoopHostnameVerifier.INSTANCE); + SSLContext sslContext = makeSslContext(keyStoreOptions, trustStoreOptions); + HostnameVerifier hostnameVerifier = makeHostnameVerifier(athenzIdentity); + SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier); return new SelfCloseableHttpClient(sslSocketFactory); } catch (Exception e) { NODE_ADMIN_LOGGER.error("Failed to create HTTP client with custom SSL Context, proceeding with default", e); @@ -212,6 +219,12 @@ public class ConfigServerHttpRequestExecutor implements AutoCloseable { return sslContextBuilder.build(); } + private static HostnameVerifier makeHostnameVerifier(Optional<AthenzIdentity> athenzIdentity) { + return athenzIdentity + .map(identity -> (HostnameVerifier) new AthenzIdentityVerifier(Collections.singleton(identity))) + .orElse(SSLConnectionSocketFactory.getDefaultHostnameVerifier()); + } + @Override public void close() { clientRefresherScheduler.shutdown(); diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/util/Environment.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/util/Environment.java index 72996e438b7..d4e790b941e 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/util/Environment.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/util/Environment.java @@ -2,6 +2,8 @@ package com.yahoo.vespa.hosted.node.admin.util; import com.google.common.base.Strings; +import com.yahoo.vespa.athenz.api.AthenzIdentity; +import com.yahoo.vespa.athenz.api.AthenzService; import com.yahoo.vespa.defaults.Defaults; import com.yahoo.vespa.hosted.dockerapi.ContainerName; import com.yahoo.vespa.hosted.node.admin.ConfigServerConfig; @@ -47,6 +49,7 @@ public class Environment { private final String feedEndpoint; private final Optional<KeyStoreOptions> keyStoreOptions; private final Optional<KeyStoreOptions> trustStoreOptions; + private final Optional<AthenzIdentity> athenzIdentity; static { filenameFormatter.setTimeZone(TimeZone.getTimeZone("UTC")); @@ -73,7 +76,10 @@ public class Environment { createKeyStoreOptions( configServerConfig.trustStoreConfig().path(), configServerConfig.trustStoreConfig().password().toCharArray(), - configServerConfig.trustStoreConfig().type().name()) + configServerConfig.trustStoreConfig().type().name()), + createAthenzIdentity( + configServerConfig.athenzDomain(), + configServerConfig.serviceName()) ); } @@ -86,7 +92,8 @@ public class Environment { List<String> logstashNodes, String feedEndpoint, Optional<KeyStoreOptions> keyStoreOptions, - Optional<KeyStoreOptions> trustStoreOptions) { + Optional<KeyStoreOptions> trustStoreOptions, + Optional<AthenzIdentity> athenzIdentity) { this.configServerHosts = configServerHosts; this.environment = environment; this.region = region; @@ -97,6 +104,7 @@ public class Environment { this.feedEndpoint = feedEndpoint; this.keyStoreOptions = keyStoreOptions; this.trustStoreOptions = trustStoreOptions; + this.athenzIdentity = athenzIdentity; } public List<URI> getConfigServerUris() { return configServerHosts; } @@ -145,6 +153,11 @@ public class Environment { .map(path -> new KeyStoreOptions(Paths.get(path), password, type)); } + private static Optional<AthenzIdentity> createAthenzIdentity(String athenzDomain, String serviceName) { + if (Strings.isNullOrEmpty(athenzDomain) || Strings.isNullOrEmpty(serviceName)) return Optional.empty(); + return Optional.of(new AthenzService(athenzDomain, serviceName)); + } + public InetAddress getInetAddressForHost(String hostname) throws UnknownHostException { return inetAddressResolver.getInetAddressForHost(hostname); } @@ -219,6 +232,10 @@ public class Environment { return trustStoreOptions; } + public Optional<AthenzIdentity> getAthenzIdentity() { + return athenzIdentity; + } + public static class Builder { private List<URI> configServerHosts = Collections.emptyList(); @@ -231,6 +248,7 @@ public class Environment { private String feedEndpoint; private KeyStoreOptions keyStoreOptions; private KeyStoreOptions trustStoreOptions; + private AthenzIdentity athenzIdentity; public Builder configServerUris(String... hosts) { configServerHosts = Arrays.stream(hosts) @@ -284,11 +302,16 @@ public class Environment { return this; } + public Builder athenzIdentity(AthenzIdentity athenzIdentity) { + this.athenzIdentity = athenzIdentity; + return this; + } public Environment build() { return new Environment(configServerHosts, environment, region, parentHostHostname, inetAddressResolver, pathResolver, logstashNodes, feedEndpoint, - Optional.ofNullable(keyStoreOptions), Optional.ofNullable(trustStoreOptions)); + Optional.ofNullable(keyStoreOptions), Optional.ofNullable(trustStoreOptions), + Optional.ofNullable(athenzIdentity)); } } } diff --git a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/noderepository/NodeRepositoryImplTest.java b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/noderepository/NodeRepositoryImplTest.java index c6e4447a606..85d92dbee25 100644 --- a/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/noderepository/NodeRepositoryImplTest.java +++ b/node-admin/src/test/java/com/yahoo/vespa/hosted/node/admin/noderepository/NodeRepositoryImplTest.java @@ -57,7 +57,7 @@ public class NodeRepositoryImplTest { public void startContainer() throws Exception { final int port = findRandomOpenPort(); requestExecutor = ConfigServerHttpRequestExecutor.create( - Collections.singleton(URI.create("http://127.0.0.1:" + port)), Optional.empty(), Optional.empty()); + Collections.singleton(URI.create("http://127.0.0.1:" + port)), Optional.empty(), Optional.empty(), Optional.empty()); container = JDisc.fromServicesXml(ContainerConfig.servicesXmlV2(port), Networking.enable); } |