Skip to content
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

Revert #3400: Reintroduce experimental S2A integration in client libraries grpc transport #3548

Open
wants to merge 18 commits into
base: main
Choose a base branch
from

Conversation

rmehta19
Copy link
Contributor

@rmehta19 rmehta19 commented Jan 7, 2025

Revert #3400.

This PR re-introduces the S2A integration the Java Cloud SDK (initially introduced in #3326, and temporarily reverted in #3400).

This PR does this by reverting #3400 with the following patches:

  • load the S2A APIs via reflection. This allows us to merge the code while the S2A API is still experimental in gRPC-Java without introducing a diamond dependency conflict. Once the S2A APIs are stable, the reflection logic can be removed and the S2A API can be used directly (via a dependency on S2A API)
  • fix NPE (s2a fix: fix NPE. #3401)
  • use a different env var name for enabling the feature

Below is the original description from #3326

Modify the Client Libraries gRPC Channel builder to use mTLS via S2A if the experimental environment variable is set, S2A is available (We check this by using SecureSessionAgent utility), and a few more conditions (see shouldUseS2A).

Following https://google.aip.dev/auth/4115, Only attempt to use S2A after DirectPath and DCA (https://google.aip.dev/auth/4114) are ruled out as options. If conditions to use S2A are not met (env variable not set, or S2A is not running in environment, etc (shouldUseS2A returns false)), fall back to default TLS connection.

When we are creating S2A-enabled Grpc Channel Credentials, we first try to secure the connection between the client and the S2A via MTLS, using MTLS-MDS credentials. If MTLS-MDS credentials can't be loaded, then we fallback to a plaintext connection between the client and S2A.

The parallel go implementation : googleapis/google-api-go-client#1874 (now lives here: https://github.com/googleapis/google-cloud-go/blob/main/auth/internal/transport/cba.go)

S2A Java client: https://github.com/grpc/grpc-java/tree/master/s2a

Resolving b/376258193 means that S2A.java is no longer experimental

@@ -1,5 +1,5 @@
/*
* Copyright 2024 Google LLC
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like running mvn fmt:format resulted in all these changes. Perhaps these changes could be made in another PR and then can be removed from this PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like these are missed in #3513.
We will do a separate PR for these and you can remove from this PR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! with the latest merge of main, these changes have been removed from this PR.

@rmehta19
Copy link
Contributor Author

rmehta19 commented Jan 7, 2025

@lqiu96 @blakeli0 @zhumin8 , please review, thanks!

@product-auto-label product-auto-label bot added size: l Pull request size is large. and removed size: m Pull request size is medium. labels Jan 9, 2025
Comment on lines 318 to 319
String s2AEnv;
s2AEnv = envProvider().getenv(S2A_ENV_ENABLE_USE_S2A);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this can be one line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -288,6 +306,37 @@ private String determineEndpoint() throws IOException {
return endpoint;
}

/** Determine if S2A can be used */
@VisibleForTesting
boolean shouldUseS2A() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a issue raised re: netty-tcnative dropping support for Windows and MacOS Intel platforms, do we want to add the runtime checks here an skip S2A if the code is running on an unsupported platforms?

We can also do that in a followup PR, but just to mention it here so we don't forget.

Copy link
Contributor Author

@rmehta19 rmehta19 Jan 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for flagging this Kui, I think this is fine to get to in a followup PR. Sent you a ping with some details.

(We can probably use System.getProperty("os.name") to get this info. Precedence for doing so is in existing DirectPath logic: https://github.com/googleapis/sdk-platform-java/blob/main/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java#L368)

}
if (channelCredentials != null) {
// Create the channel using S2A-secured channel credentials.
builder = Grpc.newChannelBuilder(mtlsEndpoint, channelCredentials);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this is what we discussed re: only pick the mtls endpoint when we know s2a will be used and directpath will not be used, but let know if otherwise. thanks

Copy link
Contributor Author

@rmehta19 rmehta19 Jan 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this is correct. We removed the logic in determineEndpoint in EndpointContext to set the mtls endpoint if shouldUseS2A returns true. We instead plumb down the mtls endpoint so that we use it only when we know DirectPath is not being used.

This is because the decision to use S2A and the decision to use DirectPath happen in different places (EndpointContext vs InstantiatingGrpcChannelProvider).

Comment on lines 93 to 108
/** True if the TransportProvider has no mtlsEndpoint set. */
boolean needsMtlsEndpoint();

/**
* Sets the endpoint to use when constructing a new {@link TransportChannel}.
*
* <p>This method should only be called if {@link #needsEndpoint()} returns true.
*/
TransportChannelProvider withEndpoint(String endpoint);

/**
* Sets the mtlsEndpoint to use when constructing a new {@link TransportChannel}.
*
* <p>This method should only be called if {@link #needsMtlsEndpoint()} returns true.
*/
TransportChannelProvider withMtlsEndpoint(String mtlsEndpoint);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me think about this a bit more. I'm not the biggest fan of adding these two public methods in needsMtlsEndpoint + withMtlsEndpoint and would prefer not to if possible.

I know this is a limitation regarding DirectPath and how that's determined. If we can't find a reasonable alternative, then I think I'm fine with this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took a look at this and I think there are possible a few alternatives to what is in this PR. Not sure entirely what all the pros and cons are as of now, but just going to pose them as possibilities.

  1. Remove the .mtls substring when using directpath flow. This is probably the simplest option, but is pretty much a workaround. Given that S2A may end up being used much more, I don't think I would like endpoint resolution to be based on string find and replace.
  2. Create a default method canUseDirectPath() in the TransportChannelProvider interface
  default boolean canUseDirectPath() {
    return false;
  }

I believe this allows us to use it via the ClientContext to resolve the endpoint before we create the TransportChannel:
i.e.

    if (transportChannelProvider.needsEndpoint()) {
      if (transportChannelProvider.canUseDirectPath()) {
        transportChannelProvider =
            transportChannelProvider.withEndpoint(endpointContext.mtlsEndpoint());
      } else {
        transportChannelProvider = transportChannelProvider.withEndpoint(endpoint);
      }
    }

It shouldn't affect users who manually create InstantiatingGrpcChannelProvider since the logic still resides in there and is used during channel creation.

Let me talk with the team and see if there are any other potential concerns that I'm missing with this. I think option 2 might be a possibility and if not, then I think we can proceed with this.

Copy link
Contributor Author

@rmehta19 rmehta19 Jan 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for looking into this Lawrence.

Remove the .mtls substring when using directpath flow. This is probably the simplest option, but is pretty much a workaround. Given that S2A may end up being used much more, I don't think I would like endpoint resolution to be based on string find and replace.

Agreed that this is probably the simplest option. However I also am hesitant about modifying the endpoint using string find and replace, as you pointed out.

Create a default method canUseDirectPath() in the TransportChannelProvider interface

I think I understand this, however I think it might not be possible without reworking a few things with canUseDirectPath:

Looking at canUseDirectPath, it calls:

The second one is easy to resolve, just be sure to call transportChannelProvider.needsCredentials() before transportChannelProvider.canUseDirectPath() in ClientContext. The first one will probably require moving that check out of canUseDirectPath and into ClientContext. I think this list is complete, but we may find more when we go to implement this.

Also, I think small typo in example you provided, should it be?:

if (transportChannelProvider.needsEndpoint()) {
      if (transportChannelProvider.canUseDirectPath()) {
        transportChannelProvider =
            transportChannelProvider.withEndpoint(endpoint);
      } else {
        transportChannelProvider = transportChannelProvider.withEndpoint(endpointContext.mtlsEndpoint());
      }
    }

Also, perhaps we could change it to set the mtls endpoint only if shouldUseS2A and !canUseDirectPath, and use endpoint derived via endpointResolution in all other cases?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed offline, we will not plumb the mtls endpoint for now, and just set the mtls endpoint if S2A can be used in EndpointContext in 25445d3

</difference>
<!-- Ignore this as this was part of s2a-grpc ExperimentalApi revert -->
<!-- Ignore method addition to an TransportChannelProvider interface -->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<!-- Ignore method addition to an TransportChannelProvider interface -->
<!-- Ignore method addition to TransportChannelProvider interface (InternalExtensionOnly) -->

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in e921696

@@ -106,16 +106,26 @@
<className>com/google/api/gax/batching/Batcher</className>
<method>*</method>
</difference>
<!-- Ignore this as this was part of s2a-grpc ExperimentalApi revert -->
<!-- Ignore abstract method addition to an EndpointContext -->
Copy link
Contributor

@lqiu96 lqiu96 Jan 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Adding the why (i.e. it's marked as internal)

Suggested change
<!-- Ignore abstract method addition to an EndpointContext -->
<!-- Ignore abstract method addition to an EndpointContext (InternalApi) -->

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in e921696

Comment on lines 100 to 103
/** Sets whether to use S2A when constructing a new {@link TransportChannel}. */
default TransportChannelProvider withUseS2A(boolean useS2A) {
throw new UnsupportedOperationException("S2A is not supported");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we probably should mark this with @BetaApi (

) until we gRPC-S2A is marked non-experimental. If possible, if you can link it with a GH issue

Anyone that extends from this interface and uses this flag may be susceptible to behavior changes depending on what comes out of testing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in fd6163a

Comment on lines 121 to 130
<difference>
<differenceType>7012</differenceType>
<className>com/google/api/gax/rpc/TransportChannelProvider</className>
<method>* needsMtlsEndpoint()</method>
</difference>
<difference>
<differenceType>7012</differenceType>
<className>com/google/api/gax/rpc/TransportChannelProvider</className>
<method>* withMtlsEndpoint(*)</method>
</difference>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these can potentially be added in a future date (if needed).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, thanks for catching. Done in a814a53

Copy link
Contributor

@lqiu96 lqiu96 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally LGTM. If @blakeli0 or @zhumin8 can also take a look as well

@lqiu96
Copy link
Contributor

lqiu96 commented Jan 16, 2025

/gcbrun

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
size: l Pull request size is large.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants