diff --git a/core/pva/src/main/java/org/epics/pva/PVASettings.java b/core/pva/src/main/java/org/epics/pva/PVASettings.java index 0c36568ede..6c9ffeecc2 100644 --- a/core/pva/src/main/java/org/epics/pva/PVASettings.java +++ b/core/pva/src/main/java/org/epics/pva/PVASettings.java @@ -153,6 +153,22 @@ public class PVASettings */ public static String EPICS_PVAS_TLS_KEYCHAIN = ""; + /** Path to a file containing the password for the PVA server keychain. + * + *
Alternative to embedding the password in {@link #EPICS_PVAS_TLS_KEYCHAIN} + * using the "/path/to/file;password" syntax. + * When set, the password is read from this file instead, with leading and trailing + * whitespace stripped. + * Takes precedence over an inline password in {@link #EPICS_PVAS_TLS_KEYCHAIN} + * when no ";" separator is present in that setting. + * + *
Intended for environments where secrets are mounted as files, + * for example Kubernetes pods using a {@code Secret} volume. + * + *
When empty, no password file is used. + */ + public static String EPICS_PVAS_TLS_KEYCHAIN_PWD_FILE = ""; + /** Secure server options * *
Alternative to embedding the password in {@link #EPICS_PVA_TLS_KEYCHAIN} + * using the "/path/to/file;password" syntax. + * When set, the password is read from this file instead, with leading and trailing + * whitespace stripped. + * Takes precedence over an inline password in {@link #EPICS_PVA_TLS_KEYCHAIN} + * when no ";" separator is present in that setting. + * + *
Intended for environments where secrets are mounted as files, + * for example Kubernetes pods using a {@code Secret} volume. + * + *
When empty, no password file is used. + */ + public static String EPICS_PVA_TLS_KEYCHAIN_PWD_FILE = ""; + /** TCP buffer size for sending data * *
Messages are constructed within this buffer,
@@ -281,9 +313,11 @@ public class PVASettings
EPICS_PVA_TCP_SOCKET_TMO = get("EPICS_PVA_TCP_SOCKET_TMO", EPICS_PVA_TCP_SOCKET_TMO);
EPICS_PVA_MAX_ARRAY_FORMATTING = get("EPICS_PVA_MAX_ARRAY_FORMATTING", EPICS_PVA_MAX_ARRAY_FORMATTING);
EPICS_PVAS_TLS_KEYCHAIN = get("EPICS_PVAS_TLS_KEYCHAIN", EPICS_PVAS_TLS_KEYCHAIN);
+ EPICS_PVAS_TLS_KEYCHAIN_PWD_FILE = get("EPICS_PVAS_TLS_KEYCHAIN_PWD_FILE", EPICS_PVAS_TLS_KEYCHAIN_PWD_FILE);
EPICS_PVAS_TLS_OPTIONS = get("EPICS_PVAS_TLS_OPTIONS", EPICS_PVAS_TLS_OPTIONS);
require_client_cert = EPICS_PVAS_TLS_OPTIONS.contains("client_cert=require");
EPICS_PVA_TLS_KEYCHAIN = get("EPICS_PVA_TLS_KEYCHAIN", EPICS_PVA_TLS_KEYCHAIN);
+ EPICS_PVA_TLS_KEYCHAIN_PWD_FILE = get("EPICS_PVA_TLS_KEYCHAIN_PWD_FILE", EPICS_PVA_TLS_KEYCHAIN_PWD_FILE);
if (EPICS_PVA_TLS_KEYCHAIN.isEmpty() && !EPICS_PVAS_TLS_KEYCHAIN.isEmpty())
{
EPICS_PVA_TLS_KEYCHAIN = EPICS_PVAS_TLS_KEYCHAIN;
diff --git a/core/pva/src/main/java/org/epics/pva/common/SecureSockets.java b/core/pva/src/main/java/org/epics/pva/common/SecureSockets.java
index d15d54957b..6f2ab6cd42 100644
--- a/core/pva/src/main/java/org/epics/pva/common/SecureSockets.java
+++ b/core/pva/src/main/java/org/epics/pva/common/SecureSockets.java
@@ -14,6 +14,8 @@
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.security.KeyStore;
import java.security.Principal;
import java.security.cert.Certificate;
@@ -63,16 +65,18 @@ public class SecureSockets
/** X509 certificates loaded from the keychain mapped by principal name of the certificate */
public static Map