From f0c638d4d23620991be80735613da54867e493e9 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Mon, 3 Mar 2025 15:58:07 -0800 Subject: [PATCH 1/7] plumb mtls endpoint separately. --- .../InstantiatingGrpcChannelProvider.java | 34 ++++++++++++++++++- .../com/google/api/gax/rpc/ClientContext.java | 4 +++ .../google/api/gax/rpc/EndpointContext.java | 7 ---- .../api/gax/rpc/TransportChannelProvider.java | 14 ++++++++ .../api/gax/rpc/EndpointContextTest.java | 4 +-- 5 files changed, 53 insertions(+), 10 deletions(-) diff --git a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java index 88bfd91601..6d5e889201 100644 --- a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java +++ b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java @@ -129,6 +129,7 @@ public final class InstantiatingGrpcChannelProvider implements TransportChannelP private final HeaderProvider headerProvider; private final boolean useS2A; private final String endpoint; + private final String mtlsEndpoint; // TODO: remove. envProvider currently provides DirectPath environment variable, and is only used // during initial rollout for DirectPath. This provider will be removed once the DirectPath // environment is not used. @@ -179,6 +180,7 @@ private InstantiatingGrpcChannelProvider(Builder builder) { this.headerProvider = builder.headerProvider; this.useS2A = builder.useS2A; this.endpoint = builder.endpoint; + this.mtlsEndpoint = builder.mtlsEndpoint; this.allowedHardBoundTokenTypes = builder.allowedHardBoundTokenTypes; this.mtlsProvider = builder.mtlsProvider; this.s2aConfigProvider = builder.s2aConfigProvider; @@ -258,6 +260,11 @@ public boolean needsEndpoint() { return endpoint == null; } + @Override + public boolean needsMtlsEndpoint() { + return mtlsEndpoint == null; + } + /** * Specify the endpoint the channel should connect to. * @@ -272,6 +279,21 @@ public TransportChannelProvider withEndpoint(String endpoint) { return toBuilder().setEndpoint(endpoint).build(); } + /** + * Specify the mTLS endpoint the channel should connect to when using S2A. + * + *

The value of {@code mtlsEndpoint} must be of the form {@code host:port}. + * + * @param mtlsEndpoint The mtTLS endpoint to connect to + * @return A new {@link InstantiatingGrpcChannelProvider} with the specified mTLS endpoint + * configured + */ + @Override + public TransportChannelProvider withMtlsEndpoint(String mtlsEndpoint) { + validateEndpoint(mtlsEndpoint); + return toBuilder().setMtlsEndpoint(mtlsEndpoint).build(); + } + /** * Specify whether or not to use S2A. * @@ -666,7 +688,9 @@ private ManagedChannel createSingleChannel() throws IOException { channelCredentials = CompositeChannelCredentials.create(channelCredentials, mtlsS2ACallCredentials); } - builder = Grpc.newChannelBuilder(endpoint, channelCredentials); + // mtlsEndpoint is non-null + non-empty here, since it must be non-null and non-empty + // in order for useS2A to be true. + builder = Grpc.newChannelBuilder(mtlsEndpoint, channelCredentials); } else { // Use default if we cannot initialize channel credentials via DCA or S2A. builder = ManagedChannelBuilder.forAddress(serviceAddress, port); @@ -819,6 +843,7 @@ public static final class Builder { private Executor executor; private HeaderProvider headerProvider; private String endpoint; + private String mtlsEndpoint; private boolean useS2A; private EnvironmentProvider envProvider; private SecureSessionAgent s2aConfigProvider = SecureSessionAgent.create(); @@ -926,6 +951,13 @@ public Builder setEndpoint(String endpoint) { return this; } + /** Sets the mTLS Endpoint used to reach the service, eg "localhost:8080". */ + public Builder setMtlsEndpoint(String mtlsEndpoint) { + validateEndpoint(mtlsEndpoint); + this.mtlsEndpoint = mtlsEndpoint; + return this; + } + Builder setUseS2A(boolean useS2A) { this.useS2A = useS2A; return this; diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java index 8e7c9a3090..2b10c0ae45 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java @@ -222,6 +222,10 @@ public static ClientContext create(StubSettings settings) throws IOException { if (transportChannelProvider.needsEndpoint()) { transportChannelProvider = transportChannelProvider.withEndpoint(endpoint); } + if (transportChannelProvider.needsMtlsEndpoint()) { + transportChannelProvider = + transportChannelProvider.withMtlsEndpoint(endpointContext.mtlsEndpoint()); + } transportChannelProvider = transportChannelProvider.withUseS2A(endpointContext.useS2A()); TransportChannel transportChannel = transportChannelProvider.getTransportChannel(); diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java index 2c11f6e058..ce5cf8c786 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java @@ -303,13 +303,6 @@ private String determineEndpoint() throws IOException { "mTLS is not supported in any universe other than googleapis.com"); } - // Check if Experimental S2A feature enabled. When feature is non-experimental, remove this - // check from this function, and plumb MTLS endpoint to channel creation logic separately. - // Note that mTLS via S2A is an independent feature from mTLS via DCA (for which endpoint - // determined by {@code mtlsEndpointResolver} above). - if (shouldUseS2A()) { - return mtlsEndpoint(); - } return endpoint; } diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/TransportChannelProvider.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/TransportChannelProvider.java index 7ab19c9c16..9965babcdb 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/TransportChannelProvider.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/TransportChannelProvider.java @@ -97,6 +97,20 @@ public interface TransportChannelProvider { */ TransportChannelProvider withEndpoint(String endpoint); + /** True for gRPC transport provider which has no mtlsEndpoint set. */ + default boolean needsMtlsEndpoint() { + return false; + } + + /** + * Sets the mTLS endpoint to use when constructing a new {@link TransportChannel} using S2A. + * + *

This method should only be called if {@link #needsMtlsEndpoint()} returns true. + */ + default TransportChannelProvider withMtlsEndpoint(String mtlsEndpoint) { + return this; + } + /** Sets whether to use S2A when constructing a new {@link TransportChannel}. */ @BetaApi( "The S2A feature is not stable yet and may change in the future. https://github.com/grpc/grpc-java/issues/11533.") diff --git a/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java b/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java index 94f013f9ba..dd1d383801 100644 --- a/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java +++ b/gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java @@ -374,7 +374,7 @@ void endpointContextBuild_multipleUniverseDomainConfigurations_clientSettingsHas } @Test - void endpointContextBuild_shouldUseS2A_mtlsEndpoint() throws IOException { + void endpointContextBuild_shouldUseS2A_tlsEndpoint() throws IOException { EnvironmentProvider envProvider = Mockito.mock(EnvironmentProvider.class); Mockito.when(envProvider.getenv(EndpointContext.S2A_ENV_ENABLE_USE_S2A)).thenReturn("true"); defaultEndpointContextBuilder = @@ -385,7 +385,7 @@ void endpointContextBuild_shouldUseS2A_mtlsEndpoint() throws IOException { .setUsingGDCH(false); EndpointContext endpointContext = defaultEndpointContextBuilder.build(); Truth.assertThat(defaultEndpointContextBuilder.shouldUseS2A()).isTrue(); - Truth.assertThat(endpointContext.resolvedEndpoint()).isEqualTo(DEFAULT_MTLS_ENDPOINT); + Truth.assertThat(endpointContext.resolvedEndpoint()).isEqualTo(DEFAULT_ENDPOINT); } @Test From 70153f761039fbb289821246f28e0de1a9c4120f Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Mon, 3 Mar 2025 16:01:23 -0800 Subject: [PATCH 2/7] remove comment. --- .../google/api/gax/grpc/InstantiatingGrpcChannelProvider.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java index 6d5e889201..d12366801a 100644 --- a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java +++ b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java @@ -688,8 +688,6 @@ private ManagedChannel createSingleChannel() throws IOException { channelCredentials = CompositeChannelCredentials.create(channelCredentials, mtlsS2ACallCredentials); } - // mtlsEndpoint is non-null + non-empty here, since it must be non-null and non-empty - // in order for useS2A to be true. builder = Grpc.newChannelBuilder(mtlsEndpoint, channelCredentials); } else { // Use default if we cannot initialize channel credentials via DCA or S2A. From 59f3bf7e2bbfbc08a6fe61d76463c1cd06b14c04 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Mon, 3 Mar 2025 16:05:06 -0800 Subject: [PATCH 3/7] move withUseS2A above needsMtlsEndpoint check. --- .../gax/src/main/java/com/google/api/gax/rpc/ClientContext.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java index 2b10c0ae45..247e2f10f9 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java @@ -222,11 +222,11 @@ public static ClientContext create(StubSettings settings) throws IOException { if (transportChannelProvider.needsEndpoint()) { transportChannelProvider = transportChannelProvider.withEndpoint(endpoint); } + transportChannelProvider = transportChannelProvider.withUseS2A(endpointContext.useS2A()); if (transportChannelProvider.needsMtlsEndpoint()) { transportChannelProvider = transportChannelProvider.withMtlsEndpoint(endpointContext.mtlsEndpoint()); } - transportChannelProvider = transportChannelProvider.withUseS2A(endpointContext.useS2A()); TransportChannel transportChannel = transportChannelProvider.getTransportChannel(); ApiCallContext defaultCallContext = From 716c9ee76af3da5ef0452361874bfe65c601fabd Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Tue, 4 Mar 2025 10:06:25 -0800 Subject: [PATCH 4/7] add interface additions to clirr-ignored-diffeences. --- gax-java/gax/clirr-ignored-differences.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gax-java/gax/clirr-ignored-differences.xml b/gax-java/gax/clirr-ignored-differences.xml index ee2e254c96..4e0a8816c1 100644 --- a/gax-java/gax/clirr-ignored-differences.xml +++ b/gax-java/gax/clirr-ignored-differences.xml @@ -118,4 +118,14 @@ com/google/api/gax/rpc/TransportChannelProvider * withUseS2A(*) + + 7012 + com/google/api/gax/rpc/TransportChannelProvider + * withMtlsEndpoint(*) + + + 7012 + com/google/api/gax/rpc/TransportChannelProvider + * needsMtlsEndpoint() + From 7e36d1ac8667c5ccbe44659faf23bec94f27a027 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Tue, 11 Mar 2025 11:23:06 -0700 Subject: [PATCH 5/7] mark new public APIs as internal-only. --- .../google/api/gax/grpc/InstantiatingGrpcChannelProvider.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java index d12366801a..a4459264d6 100644 --- a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java +++ b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java @@ -260,6 +260,7 @@ public boolean needsEndpoint() { return endpoint == null; } + @InternalApi("This public method is used by Gax to help configure the MTLS endpoint for S2A") @Override public boolean needsMtlsEndpoint() { return mtlsEndpoint == null; @@ -288,6 +289,7 @@ public TransportChannelProvider withEndpoint(String endpoint) { * @return A new {@link InstantiatingGrpcChannelProvider} with the specified mTLS endpoint * configured */ + @InternalApi("This public method is used by Gax to help configure the MTLS endpoint for S2A") @Override public TransportChannelProvider withMtlsEndpoint(String mtlsEndpoint) { validateEndpoint(mtlsEndpoint); @@ -950,6 +952,7 @@ public Builder setEndpoint(String endpoint) { } /** Sets the mTLS Endpoint used to reach the service, eg "localhost:8080". */ + @InternalApi("This public method is used by Gax to help configure the MTLS endpoint for S2A") public Builder setMtlsEndpoint(String mtlsEndpoint) { validateEndpoint(mtlsEndpoint); this.mtlsEndpoint = mtlsEndpoint; From 2afdbbc1abb17f1ef676bffd241c740695c37b53 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Tue, 11 Mar 2025 11:28:23 -0700 Subject: [PATCH 6/7] comment on why we use MTLS endpoint with S2A. --- .../google/api/gax/grpc/InstantiatingGrpcChannelProvider.java | 1 + 1 file changed, 1 insertion(+) diff --git a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java index a4459264d6..7e5c3faffe 100644 --- a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java +++ b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java @@ -690,6 +690,7 @@ private ManagedChannel createSingleChannel() throws IOException { channelCredentials = CompositeChannelCredentials.create(channelCredentials, mtlsS2ACallCredentials); } + // Connect to the MTLS endpoint when using S2A because S2A is used to perform an MTLS handshake. builder = Grpc.newChannelBuilder(mtlsEndpoint, channelCredentials); } else { // Use default if we cannot initialize channel credentials via DCA or S2A. From 92e07fe28aeaa120ec5ab14b3f68181f994f2c1a Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Wed, 12 Mar 2025 09:27:26 -0700 Subject: [PATCH 7/7] format. --- .../google/api/gax/grpc/InstantiatingGrpcChannelProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java index 7e5c3faffe..e22ffa098a 100644 --- a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java +++ b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java @@ -690,7 +690,8 @@ private ManagedChannel createSingleChannel() throws IOException { channelCredentials = CompositeChannelCredentials.create(channelCredentials, mtlsS2ACallCredentials); } - // Connect to the MTLS endpoint when using S2A because S2A is used to perform an MTLS handshake. + // Connect to the MTLS endpoint when using S2A because S2A is used to perform an MTLS + // handshake. builder = Grpc.newChannelBuilder(mtlsEndpoint, channelCredentials); } else { // Use default if we cannot initialize channel credentials via DCA or S2A.