-
Notifications
You must be signed in to change notification settings - Fork 68
fix: S2A- Check if a default endpoint has been set #3784
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: S2A- Check if a default endpoint has been set #3784
Conversation
@lqiu96 , would you be able to review this? Thanks! |
I see, I wasn't aware of this use case. However, if a user does create their own TransportChannelProvider with a custom endpoint, then it wouldn't skip S2A. Can you remind me again what the original rationale was for skipping a custom endpoint? |
When a user is setting a custom endpoint, we can't be sure this is a MTLS endpoint, therefore we can't use S2A. We only want to use S2A when we can use the MTLS endpoint.
This is true, if a hw client library does this (say they set it to something foo.xyz.com) then S2A wouldn't get skipped, and S2A would be used to connect to MTLS endpoint of api (foo.mtls.googleapis.com) which isn't our desired behavior (we want to respect custom set endpoint and skip S2A in this case). Perhaps we could add some extra field ( |
Friendly ping on this @lqiu96. Thank you! |
@@ -327,8 +327,7 @@ boolean shouldUseS2A() { | |||
} | |||
|
|||
// If a custom endpoint is being used, skip S2A. | |||
if (!Strings.isNullOrEmpty(clientSettingsEndpoint()) | |||
|| !Strings.isNullOrEmpty(transportChannelProviderEndpoint())) { | |||
if (!Strings.isNullOrEmpty(clientSettingsEndpoint())) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm worried that this may only end up potentially resolving the issue for the GrpcTransportOptions.setUpChannelProvider
case. IIRC, resolveEndpoint()
's logic still revolves around if either clientSettings' endpoint or transportChannelProvider's endpoint is set, and if so, then that's the resolved endpoint.
I'm worried that it would end up with s2a being enabled with the resolved endpoint still being the one configured in GrpcTransportOptions.setUpChannelProvider
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gax and the generator no longer provide a default non-mtls endpoint for the client libraries. The "default" endpoint that is intended to be used is constructed inside the EndpointContext. If you want to check, you can theoretically just check if clientSettingsEndpoint
or transportChannelEndpoint
== buildEndpointTemplate(serviceName(), resolvedUniverseDomain())
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm worried that it would end up with s2a being enabled with the resolved endpoint still being the one configured in GrpcTransportOptions.setUpChannelProvider
I believe our logic in InstantiatingGrpcChannelProvider prevents this from happening. If S2A is enabled, we use the mtlsEndpoint
(that is plumbed separately from the endpoint
; endpoint
== resolvedEndpoint()
):
Lines 686 to 699 in 49a7ae5
if (useS2A) { | |
channelCredentials = createS2ASecuredChannelCredentials(); | |
} | |
if (channelCredentials != null) { | |
// Create the channel using S2A-secured channel credentials. | |
if (mtlsS2ACallCredentials != null) { | |
// Set {@code mtlsS2ACallCredentials} to be per-RPC call credentials, | |
// which will be used to fetch MTLS_S2A hard bound tokens from the metdata server. | |
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); |
WDYT @lqiu96 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh right, there is the custom logic for S2A. What about the case if a user has a custom TransportChannelProvider with a non-mtls endpoint configured? IIUC above, the intention would be not use S2A, but our checks in EndpointContext would have shouldUseS2A as true.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh right, there is the custom logic for S2A. What about the case if a user has a custom TransportChannelProvider with a non-mtls endpoint configured? IIUC above, the intention would be not use S2A, but our checks in EndpointContext would have shouldUseS2A as true.
It is correct that if the user is intentionally setting a custom endpoint via their own TransportChannelProvider, that we want to skip S2A. With the latest changes, if they are setting the custom endpoint to be the same as the default non-mtls endpoint, we would end up using S2A. I believe this is ok, as my understanding is that if the user is setting an endpoint, it is usually something different than the default non-mtls endpoint.
Gax and the generator no longer provide a default non-mtls endpoint for the client libraries. The "default" endpoint that is intended to be used is constructed inside the EndpointContext. If you want to check, you can theoretically just check if clientSettingsEndpoint or transportChannelEndpoint == buildEndpointTemplate(serviceName(), resolvedUniverseDomain())
Apologies, I missed this comment of yours. Thanks for bringing this up! I tested this out internally and this works. The latest commit contains this logic, WDYT @lqiu96
981454b
to
6ad5b8e
Compare
|| !Strings.isNullOrEmpty(transportChannelProviderEndpoint())) { | ||
|| (!Strings.isNullOrEmpty(transportChannelProviderEndpoint()) | ||
&& !buildEndpointTemplate(serviceName(), resolvedUniverseDomain()) | ||
.contains(transportChannelProviderEndpoint()))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding this "contains" logic, since buildEndpointTemplate
adds 443
(https) as default port, and GrpcTransportOptions.setUpChannelProvider
, for example, just sets the host.
In this way, we are sure to respect a custom endpoint set via TransportChannelProvider
. For example, if client specified transportChannelProviderEndpoint
as the http endpoint (default endpoint + port 80), shouldUseS2A
would evaluate to false.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I think this does resolve the above concern. Could this check for both clientSettings and transportChannelProvider just to be safe? Or is there a specific reason for only doing this for the transportchannelprovider?
I think the contains logic is fine given the concerns with port. The string contains == resolved endpoint
may not be completely fool proof (I can't think of counter example off the top of my head), but I think it's safer than removing the check for the transportchannelprovider endpoint.
Hopefully this helps unblock the issue with GrpcTransportOptions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this check for both clientSettings and transportChannelProvider just to be safe? Or is there a specific reason for only doing this for the transportchannelprovider?
I don't see an issue for doing this check for both clientSettingsEndpoint
and transportChannelProviderEndpoint
, the reason I initially did it for the latter was because I ran into it in the GrpcTransportOptions case :). I tested this internally and verified that doing this check on both is ok. Added this in the latest commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI, Bigtable has custom code to setEndpoint via settings which I think would be an issue: https://github.com/googleapis/java-bigtable/blob/8d3dca43224179829829bcf91972610c666b130b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStubSettings.java#L807
May be an issue in the future as it auto sets a default. But you would prefer to handle those cases later on, then we can just proceed with this to unblock logging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code LGTM, added a small comment if you could take a look.
I think it should be fine, but we can try to address any additional things after more testing.
Thanks @lqiu96 ! Addressed your latest comment. PTAL when you get a chance. |
/gcbrun |
Re-running the failed showcase test. Not sure if it's flaky or not and we can see after this run. Also, can you update the title to follow conventioncommits with the update changes? i.e. |
Done, thanks @lqiu96 ! |
Seeing some odd showcase errors. Can you try merging the latest into the branch and we can see if that resolves the CI issues? |
Merged the latest changes from main @lqiu96 |
/gcbrun |
Thanks! Running the graalvm checks and should auto-merge after success |
Certain handwritten client libraries set this field to the (TLS) endpoint via [`GrpcTransportOptions.setUpChannelProvider`](https://github.com/googleapis/sdk-platform-java/blob/2a41393c0e148e96fd3a0a8e1505e0827aa4fd3a/java-core/google-cloud-core-grpc/src/main/java/com/google/cloud/grpc/GrpcTransportOptions.java#L165). This isn't really a custom endpoint, so we should be able to use S2A when this is set. Example with Cloud Logging: https://github.com/googleapis/java-logging/blob/644ebd756d44ffc02b58aa30d9a07c8afe700981/google-cloud-logging/src/main/java/com/google/cloud/logging/spi/v2/GrpcLoggingRpc.java#L137
🤖 I have created a release *beep* *boop* --- <details><summary>2.59.1</summary> ## [2.59.1](v2.59.0...v2.59.1) (2025-06-12) ### Bug Fixes * S2A- Check if a default endpoint has been set ([#3784](#3784)) ([5b2ab82](5b2ab82)) ### Dependencies * update google auth library dependencies to v1.37.0 ([#3830](#3830)) ([8bf9d3c](8bf9d3c)) </details> --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
Certain handwritten client libraries set this field to the (TLS) endpoint via
GrpcTransportOptions.setUpChannelProvider
.This isn't really a custom endpoint, so we should be able to use S2A when this is set.
Example with Cloud Logging: https://github.com/googleapis/java-logging/blob/644ebd756d44ffc02b58aa30d9a07c8afe700981/google-cloud-logging/src/main/java/com/google/cloud/logging/spi/v2/GrpcLoggingRpc.java#L137