From ed414faf4315139d9fde8258c1522692e26d77e3 Mon Sep 17 00:00:00 2001 From: sagnghos Date: Thu, 23 Jan 2025 13:31:10 +0000 Subject: [PATCH] feat: mTLS support for external hosts --- .../pgadapter/metadata/OptionsMetadata.java | 24 ++++++++++++++++++- .../metadata/OptionsMetadataTest.java | 8 +++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/metadata/OptionsMetadata.java b/src/main/java/com/google/cloud/spanner/pgadapter/metadata/OptionsMetadata.java index 5f899034c5..9ae7e4c440 100644 --- a/src/main/java/com/google/cloud/spanner/pgadapter/metadata/OptionsMetadata.java +++ b/src/main/java/com/google/cloud/spanner/pgadapter/metadata/OptionsMetadata.java @@ -33,6 +33,7 @@ import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.spanner.v1.DatabaseName; +import io.grpc.ExperimentalApi; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -108,6 +109,8 @@ public static class Builder { private String endpoint; private boolean usePlainText; private Duration startupTimeout = DEFAULT_STARTUP_TIMEOUT; + private String clientCertificate; + private String clientKey; Builder() {} @@ -413,6 +416,20 @@ Builder setStartupTimeout(Duration timeout) { return this; } + /** + * Configures mTLS authentication using the provided client certificate and key files. mTLS is + * only supported for external spanner hosts. + * + * @param clientCertificate Path to the client certificate file. + * @param clientKey Path to the client private key file. + */ + @ExperimentalApi("https://github.com/googleapis/java-spanner/pull/3574") + Builder useClientCert(String clientCertificate, String clientKey) { + this.clientCertificate = clientCertificate; + this.clientKey = clientKey; + return this; + } + public OptionsMetadata build() { if (Strings.isNullOrEmpty(project) && !Strings.isNullOrEmpty(instance)) { throw SpannerExceptionFactory.newSpannerException( @@ -484,7 +501,8 @@ private String[] toCommandLineArguments() { || databaseRole != null || autoConfigEmulator || useVirtualGrpcTransportThreads - || enableEndToEndTracing) { + || enableEndToEndTracing + || (clientKey != null && clientCertificate != null)) { StringBuilder jdbcOptionBuilder = new StringBuilder(); if (usePlainText) { jdbcOptionBuilder.append("usePlainText=true;"); @@ -506,6 +524,10 @@ private String[] toCommandLineArguments() { if (enableEndToEndTracing) { jdbcOptionBuilder.append(ENABLE_END_TO_END_TRACING_PROPERTY_NAME).append("=true;"); } + if (clientKey != null && clientCertificate != null) { + jdbcOptionBuilder.append("clientCertificate=").append(clientCertificate).append(";"); + jdbcOptionBuilder.append("clientKey=").append(clientKey).append(";"); + } addOption(args, OPTION_JDBC_PROPERTIES, jdbcOptionBuilder.toString()); } if (logGrpcMessages) { diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/metadata/OptionsMetadataTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/metadata/OptionsMetadataTest.java index e55e157434..effb14c8a9 100644 --- a/src/test/java/com/google/cloud/spanner/pgadapter/metadata/OptionsMetadataTest.java +++ b/src/test/java/com/google/cloud/spanner/pgadapter/metadata/OptionsMetadataTest.java @@ -629,4 +629,12 @@ public void testBuildConnectionUrlWithEmulator() { .build() .buildConnectionURL("projects/my-project/instances/my-instance/databases/my-database")); } + + @Test + public void testUseClientCertParameters() { + OptionsMetadata options = + OptionsMetadata.newBuilder().useClientCert("client.crt", "client.key").build(); + assertEquals("client.crt", options.getPropertyMap().get("clientCertificate")); + assertEquals("client.key", options.getPropertyMap().get("clientKey")); + } }