-
Notifications
You must be signed in to change notification settings - Fork 123
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
feat(spanner): mTLS setup for spanner external host clients #3574
base: main
Are you sure you want to change the base?
Conversation
Warning: This pull request is touching the following templated files:
|
b85de2b
to
1f1ef13
Compare
@@ -393,6 +393,10 @@ Spanner createSpanner(SpannerPoolKey key, ConnectionOptions options) { | |||
// Set a custom channel configurator to allow http instead of https. | |||
builder.setChannelConfigurator(ManagedChannelBuilder::usePlaintext); | |||
} | |||
if (options.getClientCertificate() != null && options.getClientCertificateKey() != null) { |
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.
You should also add these properties to SpannerPoolKey
. That will ensure that if you use two different client certificates, that you also get two different Spanner
instances.
@@ -1485,6 +1496,34 @@ public Builder setEmulatorHost(String emulatorHost) { | |||
return this; | |||
} | |||
|
|||
public Builder useClientCert(String host, String clientCertificate, String clientKey) { |
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 don't think we should add this method here. Instead, this logic should probably be moved to ConnectionOptions
, and then that class can just call SpannerOptions$Builder#setChannelProvider(..)
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.
If you do decide to keep it here, then:
- Add Javadoc. It is a public method.
- Consider adding
@ExperimentalApi
to indicate that it might change in the future.
try { | ||
URI uri = new URI(host); | ||
managedChannel = | ||
NettyChannelBuilder.forAddress(uri.getHost(), uri.getPort()) |
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 think that this will create a single gRPC channel, and not a channel pool. That means that the potential concurrency of any client that uses this option will be lower than the default for the Java client (the default is to use a channel pool with 4 channels).
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.
Also, I'm not really a fan of a set method on a builder like this doing this much logic. Normally, I would expect this logic to be executed when the object is actually built, and not in the set method. (See also my first comment on this method)
.build()) | ||
.build(); | ||
|
||
setChannelProvider( |
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.
This will override all the additional settings etc. that are set on the channel provider that is used by default by the Java client. That means that you will potentially be missing out on a lot of default settings and features, such as compression, keep-alive settings, interceptors, end-to-end tracing, direct-path etc. Are you sure you want that?
throw new IllegalArgumentException( | ||
"Invalid host format. Expected format: 'protocol://host[:port]'.", e); | ||
} catch (Exception e) { | ||
throw new RuntimeException("Unexpected error during mTLS setup.", e); |
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.
Throw a SpannerException
in a case like this. They can be created with SpannerExceptionFactory
.
return this; | ||
} | ||
|
||
public Builder usePlainText() { |
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 not sure we need a separate method for this. This is not something a normal user would normally need to call separately.
@@ -1593,6 +1632,24 @@ public SpannerOptions build() { | |||
this.setChannelConfigurator(ManagedChannelBuilder::usePlaintext); | |||
// As we are using plain text, we should never send any credentials. | |||
this.setCredentials(NoCredentials.getInstance()); | |||
} else if (managedChannel != null) { | |||
// Add shutdown hook for the ManagedChannel if created to prevent resource leak |
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.
We should not add a shutdown hook for this. GapicSpannerRpc
instances can also be closed without shutting down the application, and this would then not be invoked. Instead, I think it would be better if GapicSpannerRpc
kept track of the fact that it uses a custom channel provider that has a shutdown
method, and call that shutdown
method when a GapicSpannerRpc
instance is closed.
Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly:
Fixes #<issue_number_goes_here> ☕️
If you write sample code, please follow the samples format.