summaryrefslogtreecommitdiffstats
path: root/container-core
diff options
context:
space:
mode:
authorMorten Tokle <mortent@yahooinc.com>2023-06-07 11:29:07 +0200
committerMorten Tokle <mortent@yahooinc.com>2023-06-07 11:29:07 +0200
commite8e31b8f7ff1a77a47a8e9cf1bb884123ca2469a (patch)
tree55ae69cceca99e955f455348dd18c46f97d8b4fb /container-core
parent17680e5bd51252b282e011e4f9929653f78be016 (diff)
Generate proxy certificate and inject in trust store
Diffstat (limited to 'container-core')
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/DataplaneProxyCredentials.java70
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/CloudSslContextProvider.java42
-rw-r--r--container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/ConfiguredSslContextFactoryProvider.java4
3 files changed, 114 insertions, 2 deletions
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/DataplaneProxyCredentials.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/DataplaneProxyCredentials.java
new file mode 100644
index 00000000000..46c840ad607
--- /dev/null
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/DataplaneProxyCredentials.java
@@ -0,0 +1,70 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.jdisc.http.server.jetty;
+
+import com.yahoo.component.AbstractComponent;
+import com.yahoo.security.KeyUtils;
+import com.yahoo.security.X509CertificateUtils;
+import com.yahoo.security.X509CertificateWithKey;
+import com.yahoo.vespa.defaults.Defaults;
+import com.yahoo.yolean.Exceptions;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+import java.time.Duration;
+
+/**
+ * Generates temporary credentials to be used by a proxy for accessing Jdisc.
+ * Credentials are written to vespa_home/tmp/.
+ *
+ * @author mortent
+ */
+public class DataplaneProxyCredentials extends AbstractComponent {
+
+ private final Path certificateFile;
+ private final Path keyFile;
+
+ public DataplaneProxyCredentials() {
+ certificateFile = Paths.get(Defaults.getDefaults().underVespaHome("tmp/proxy_cert.pem"));
+ keyFile = Paths.get(Defaults.getDefaults().underVespaHome("tmp/proxy_key.pem"));
+ if (regenerateCredentials(certificateFile, keyFile)) {
+ X509CertificateWithKey selfSigned = X509CertificateUtils.createSelfSigned("cn=vespa dataplane proxy", Duration.ofDays(30));
+ Exceptions.uncheck(() -> Files.writeString(certificateFile, X509CertificateUtils.toPem(selfSigned.certificate())));
+ Exceptions.uncheck(() -> Files.writeString(keyFile, KeyUtils.toPem(selfSigned.privateKey())));
+ }
+ }
+
+ /*
+ * Returns true if credentials should be regenerated.
+ */
+ private boolean regenerateCredentials(Path certificateFile, Path keyFile) {
+ if (!Files.exists(certificateFile) || !Files.exists(keyFile)) {
+ return true;
+ }
+ try {
+ X509Certificate x509Certificate = X509CertificateUtils.fromPem(Files.readString(certificateFile));
+ PrivateKey privateKey = KeyUtils.fromPemEncodedPrivateKey(Files.readString(keyFile));
+ return !X509CertificateUtils.privateKeyMatchesPublicKey(privateKey, x509Certificate.getPublicKey());
+ } catch (IOException e) {
+ // Some exception occured, assume credentials corrupted and requires a new pair.
+ return true;
+ }
+ }
+
+ public Path certificateFile() {
+ return certificateFile;
+ }
+
+ public Path keyFile() {
+ return keyFile;
+ }
+
+ @Override
+ public void deconstruct() {
+ super.deconstruct();
+ }
+
+}
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/CloudSslContextProvider.java
new file mode 100644
index 00000000000..cdfd4aa938e
--- /dev/null
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/CloudSslContextProvider.java
@@ -0,0 +1,42 @@
+// 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.jdisc.http.ConnectorConfig;
+import com.yahoo.jdisc.http.server.jetty.DataplaneProxyCredentials;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.util.Optional;
+
+/**
+ * Used to enable token based endpoints in Cloud. Amends trust store to allow proxy.
+ *
+ * @author mortent
+ */
+public class CloudSslContextProvider extends ConfiguredSslContextFactoryProvider {
+
+ private final DataplaneProxyCredentials dataplaneProxyCredentials;
+
+ public CloudSslContextProvider(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);
+ } 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);
+ }
+ }
+}
diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/ConfiguredSslContextFactoryProvider.java b/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/ConfiguredSslContextFactoryProvider.java
index 27c5aff22a9..b99bc007b32 100644
--- a/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/ConfiguredSslContextFactoryProvider.java
+++ b/container-core/src/main/java/com/yahoo/jdisc/http/ssl/impl/ConfiguredSslContextFactoryProvider.java
@@ -110,7 +110,7 @@ public class ConfiguredSslContextFactoryProvider implements SslProvider {
private static boolean hasBoth(String a, String b) { return !a.isBlank() && !b.isBlank(); }
private static boolean hasNeither(String a, String b) { return a.isBlank() && b.isBlank(); }
- private static Optional<String> getCaCertificates(ConnectorConfig.Ssl sslConfig) {
+ Optional<String> getCaCertificates(ConnectorConfig.Ssl sslConfig) {
if (!sslConfig.caCertificate().isBlank()) {
return Optional.of(sslConfig.caCertificate());
} else if (!sslConfig.caCertificateFile().isBlank()) {
@@ -130,7 +130,7 @@ public class ConfiguredSslContextFactoryProvider implements SslProvider {
return readToString(config.certificateFile());
}
- private static String readToString(String filename) {
+ static String readToString(String filename) {
try {
return Files.readString(Paths.get(filename), StandardCharsets.UTF_8);
} catch (IOException e) {