Skip to content

Commit a961459

Browse files
authored
fix: plumb mtls endpoint to TransportChannelProvider (#3673)
This PR plumbs the MTLS endpoint (separately from the resolved endpoint) from the `EndpointContext` to the `InstantiatingGrpcChannelProvider`. Why not just set the MTLS endpoint in `EndpointContext` if S2A can be used? - Although we can decide whether or not to try to use S2A in `EndpointContext`, we could fail to use S2A in `InstantiatingGrpcChannelProvider` (if autoconfig doesn't return an address), in which case we fall back to using a TLS connection - DirectPath supersedes S2A in `InstantiatingGrpcChannelProvider`, and the decision to use DirectPath is made in `InstantiatingGrpcChannelProvider`, not `EndpointContext`. We may decide to use S2A in `EndpointContext`, but when we go to create the channel in `InstantiatingGrpcChannelProvider`, we may find that we should be using DirectPath, in which case we need to use the non-MTLS endpoint
1 parent cd89916 commit a961459

File tree

6 files changed

+66
-10
lines changed

6 files changed

+66
-10
lines changed

gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java

+36-1
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ public final class InstantiatingGrpcChannelProvider implements TransportChannelP
129129
private final HeaderProvider headerProvider;
130130
private final boolean useS2A;
131131
private final String endpoint;
132+
private final String mtlsEndpoint;
132133
// TODO: remove. envProvider currently provides DirectPath environment variable, and is only used
133134
// during initial rollout for DirectPath. This provider will be removed once the DirectPath
134135
// environment is not used.
@@ -179,6 +180,7 @@ private InstantiatingGrpcChannelProvider(Builder builder) {
179180
this.headerProvider = builder.headerProvider;
180181
this.useS2A = builder.useS2A;
181182
this.endpoint = builder.endpoint;
183+
this.mtlsEndpoint = builder.mtlsEndpoint;
182184
this.allowedHardBoundTokenTypes = builder.allowedHardBoundTokenTypes;
183185
this.mtlsProvider = builder.mtlsProvider;
184186
this.s2aConfigProvider = builder.s2aConfigProvider;
@@ -258,6 +260,12 @@ public boolean needsEndpoint() {
258260
return endpoint == null;
259261
}
260262

263+
@InternalApi("This public method is used by Gax to help configure the MTLS endpoint for S2A")
264+
@Override
265+
public boolean needsMtlsEndpoint() {
266+
return mtlsEndpoint == null;
267+
}
268+
261269
/**
262270
* Specify the endpoint the channel should connect to.
263271
*
@@ -272,6 +280,22 @@ public TransportChannelProvider withEndpoint(String endpoint) {
272280
return toBuilder().setEndpoint(endpoint).build();
273281
}
274282

283+
/**
284+
* Specify the mTLS endpoint the channel should connect to when using S2A.
285+
*
286+
* <p>The value of {@code mtlsEndpoint} must be of the form {@code host:port}.
287+
*
288+
* @param mtlsEndpoint The mtTLS endpoint to connect to
289+
* @return A new {@link InstantiatingGrpcChannelProvider} with the specified mTLS endpoint
290+
* configured
291+
*/
292+
@InternalApi("This public method is used by Gax to help configure the MTLS endpoint for S2A")
293+
@Override
294+
public TransportChannelProvider withMtlsEndpoint(String mtlsEndpoint) {
295+
validateEndpoint(mtlsEndpoint);
296+
return toBuilder().setMtlsEndpoint(mtlsEndpoint).build();
297+
}
298+
275299
/**
276300
* Specify whether or not to use S2A.
277301
*
@@ -666,7 +690,9 @@ private ManagedChannel createSingleChannel() throws IOException {
666690
channelCredentials =
667691
CompositeChannelCredentials.create(channelCredentials, mtlsS2ACallCredentials);
668692
}
669-
builder = Grpc.newChannelBuilder(endpoint, channelCredentials);
693+
// Connect to the MTLS endpoint when using S2A because S2A is used to perform an MTLS
694+
// handshake.
695+
builder = Grpc.newChannelBuilder(mtlsEndpoint, channelCredentials);
670696
} else {
671697
// Use default if we cannot initialize channel credentials via DCA or S2A.
672698
builder = ManagedChannelBuilder.forAddress(serviceAddress, port);
@@ -819,6 +845,7 @@ public static final class Builder {
819845
private Executor executor;
820846
private HeaderProvider headerProvider;
821847
private String endpoint;
848+
private String mtlsEndpoint;
822849
private boolean useS2A;
823850
private EnvironmentProvider envProvider;
824851
private SecureSessionAgent s2aConfigProvider = SecureSessionAgent.create();
@@ -926,6 +953,14 @@ public Builder setEndpoint(String endpoint) {
926953
return this;
927954
}
928955

956+
/** Sets the mTLS Endpoint used to reach the service, eg "localhost:8080". */
957+
@InternalApi("This public method is used by Gax to help configure the MTLS endpoint for S2A")
958+
public Builder setMtlsEndpoint(String mtlsEndpoint) {
959+
validateEndpoint(mtlsEndpoint);
960+
this.mtlsEndpoint = mtlsEndpoint;
961+
return this;
962+
}
963+
929964
Builder setUseS2A(boolean useS2A) {
930965
this.useS2A = useS2A;
931966
return this;

gax-java/gax/clirr-ignored-differences.xml

+10
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,14 @@
118118
<className>com/google/api/gax/rpc/TransportChannelProvider</className>
119119
<method>* withUseS2A(*)</method>
120120
</difference>
121+
<difference>
122+
<differenceType>7012</differenceType>
123+
<className>com/google/api/gax/rpc/TransportChannelProvider</className>
124+
<method>* withMtlsEndpoint(*)</method>
125+
</difference>
126+
<difference>
127+
<differenceType>7012</differenceType>
128+
<className>com/google/api/gax/rpc/TransportChannelProvider</className>
129+
<method>* needsMtlsEndpoint()</method>
130+
</difference>
121131
</differences>

gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java

+4
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,10 @@ public static ClientContext create(StubSettings settings) throws IOException {
223223
transportChannelProvider = transportChannelProvider.withEndpoint(endpoint);
224224
}
225225
transportChannelProvider = transportChannelProvider.withUseS2A(endpointContext.useS2A());
226+
if (transportChannelProvider.needsMtlsEndpoint()) {
227+
transportChannelProvider =
228+
transportChannelProvider.withMtlsEndpoint(endpointContext.mtlsEndpoint());
229+
}
226230
TransportChannel transportChannel = transportChannelProvider.getTransportChannel();
227231

228232
ApiCallContext defaultCallContext =

gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java

-7
Original file line numberDiff line numberDiff line change
@@ -303,13 +303,6 @@ private String determineEndpoint() throws IOException {
303303
"mTLS is not supported in any universe other than googleapis.com");
304304
}
305305

306-
// Check if Experimental S2A feature enabled. When feature is non-experimental, remove this
307-
// check from this function, and plumb MTLS endpoint to channel creation logic separately.
308-
// Note that mTLS via S2A is an independent feature from mTLS via DCA (for which endpoint
309-
// determined by {@code mtlsEndpointResolver} above).
310-
if (shouldUseS2A()) {
311-
return mtlsEndpoint();
312-
}
313306
return endpoint;
314307
}
315308

gax-java/gax/src/main/java/com/google/api/gax/rpc/TransportChannelProvider.java

+14
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,20 @@ public interface TransportChannelProvider {
9797
*/
9898
TransportChannelProvider withEndpoint(String endpoint);
9999

100+
/** True for gRPC transport provider which has no mtlsEndpoint set. */
101+
default boolean needsMtlsEndpoint() {
102+
return false;
103+
}
104+
105+
/**
106+
* Sets the mTLS endpoint to use when constructing a new {@link TransportChannel} using S2A.
107+
*
108+
* <p>This method should only be called if {@link #needsMtlsEndpoint()} returns true.
109+
*/
110+
default TransportChannelProvider withMtlsEndpoint(String mtlsEndpoint) {
111+
return this;
112+
}
113+
100114
/** Sets whether to use S2A when constructing a new {@link TransportChannel}. */
101115
@BetaApi(
102116
"The S2A feature is not stable yet and may change in the future. https://github.com/grpc/grpc-java/issues/11533.")

gax-java/gax/src/test/java/com/google/api/gax/rpc/EndpointContextTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ void endpointContextBuild_multipleUniverseDomainConfigurations_clientSettingsHas
374374
}
375375

376376
@Test
377-
void endpointContextBuild_shouldUseS2A_mtlsEndpoint() throws IOException {
377+
void endpointContextBuild_shouldUseS2A_tlsEndpoint() throws IOException {
378378
EnvironmentProvider envProvider = Mockito.mock(EnvironmentProvider.class);
379379
Mockito.when(envProvider.getenv(EndpointContext.S2A_ENV_ENABLE_USE_S2A)).thenReturn("true");
380380
defaultEndpointContextBuilder =
@@ -385,7 +385,7 @@ void endpointContextBuild_shouldUseS2A_mtlsEndpoint() throws IOException {
385385
.setUsingGDCH(false);
386386
EndpointContext endpointContext = defaultEndpointContextBuilder.build();
387387
Truth.assertThat(defaultEndpointContextBuilder.shouldUseS2A()).isTrue();
388-
Truth.assertThat(endpointContext.resolvedEndpoint()).isEqualTo(DEFAULT_MTLS_ENDPOINT);
388+
Truth.assertThat(endpointContext.resolvedEndpoint()).isEqualTo(DEFAULT_ENDPOINT);
389389
}
390390

391391
@Test

0 commit comments

Comments
 (0)