| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
There was a problem hiding this comment.
@HTHou , thanks for working on this!
I only have a comment on the conf so far. We should try to make it more general to support any ServerCredentials.
This part of the grpc code is new to me. Will need some time to review the other code.
Sorry, something went wrong.
| String TLS_HANDSHAKE_FAILURE_LISTENER_PARAMETER = PREFIX + ".tls.handshake.failure.listener"; | ||
| Class<TlsHandshakeFailureListener> TLS_HANDSHAKE_FAILURE_LISTENER_CLASS = | ||
| TlsHandshakeFailureListener.class; |
There was a problem hiding this comment.
NettyServerBuilder forAddress(SocketAddress address, ServerCredentials creds) Since the forAddress parameter is ServerCredentials, let's use ServerCredentials as the class. Then, it will also support other ServerCredentials.
String CREDENTIALS_PARAMETER = PREFIX + ".credentials";
Class<ServerCredentials> CREDENTIALS_CLASS = ServerCredentials.class;
static ServerCredentials credentials(Parameters parameters) {
return parameters == null ? null
: parameters.get(CREDENTIALS_PARAMETER, CREDENTIALS_CLASS);
}
static void setCredentials(Parameters parameters, ServerCredentials listener) {
parameters.put(CREDENTIALS_PARAMETER, listener, CREDENTIALS_CLASS);
}
Sorry, something went wrong.
There was a problem hiding this comment.
Thanks for the suggestion. Updated in 058baf3: the parameter now stores a generic ServerCredentials via GrpcConfigKeys.Server.setCredentials(...), and GrpcServicesImpl passes it directly to NettyServerBuilder.forAddress(...). The TLS listener is exposed through TlsHandshakeFailureServerCredentials.create(...), and the test registers that implementation through the generic credentials configuration, so other ServerCredentials implementations are supported as well.
Sorry, something went wrong.
There was a problem hiding this comment.
@HTHou , thanks for the update! Please see the comments inlined and also https://issues.apache.org/jira/secure/attachment/13084161/1561_review.patch
Sorry, something went wrong.
| if (serverCredentials != null) { | ||
| LOG.info("Setting server credentials for {}", address); | ||
| } else if (sslContext != null) { | ||
| LOG.info("Setting TLS for {}", address); | ||
| nettyServerBuilder.sslContext(sslContext); | ||
| } |
There was a problem hiding this comment.
Move the LOG to above if-statement.
if (serverCredentials != null) {
LOG.info("Setting server credentials for {}", address);
nettyServerBuilder = NettyServerBuilder.forAddress(address, serverCredentials);
} else {
nettyServerBuilder = NettyServerBuilder.forAddress(address);
if (sslContext != null) {
LOG.info("Setting sslContext for {}", address);
nettyServerBuilder.sslContext(sslContext);
}
}
Sorry, something went wrong.
There was a problem hiding this comment.
Updated in 64ca1d7. The log statements are now inside the corresponding serverCredentials and sslContext branches.
Sorry, something went wrong.
| import java.util.Objects; | ||
|
|
||
| /** Information about a failed TLS handshake. */ | ||
| public final class TlsHandshakeFailureEvent { |
There was a problem hiding this comment.
Let's move it as an inner class TlsHandshakeFailureServerCredentials.Event.
Sorry, something went wrong.
There was a problem hiding this comment.
Updated in 64ca1d7. The event is now the nested TlsHandshakeFailureServerCredentials.Event, and the standalone event class has been removed.
Sorry, something went wrong.
| public interface TlsHandshakeFailureListener { | ||
| /** | ||
| * Invoked on a transport event-loop thread. Implementations must not block and should hand off | ||
| * expensive work to another thread. | ||
| */ | ||
| void onFailure(TlsHandshakeFailureEvent event); | ||
| } |
There was a problem hiding this comment.
Let's use Consumer<TlsHandshakeFailureEvent> instead of adding a new interface.
Sorry, something went wrong.
There was a problem hiding this comment.
Updated in 64ca1d7. create(...) now accepts Consumer<TlsHandshakeFailureServerCredentials.Event>, and the standalone listener interface has been removed. I kept the non-blocking transport event-loop requirement in the API documentation.
Sorry, something went wrong.
| final ChannelHandler grpcNegotiationHandler = | ||
| InternalProtocolNegotiators.grpcNegotiationHandler(grpcHandler); | ||
| final ChannelHandler tlsHandler = new ServerTlsHandler(grpcNegotiationHandler, grpcHandler, | ||
| sslContext, listener, offloadExecutorPool); |
There was a problem hiding this comment.
It seems better to pass the executor, instead of the offloadExecutorPool.
Sorry, something went wrong.
There was a problem hiding this comment.
Updated in 64ca1d7. Negotiator now passes its acquired executor to ServerTlsHandler, avoiding a second getObject() call while retaining the existing returnObject() lifecycle.
Sorry, something went wrong.
| .contains(sslHandler.applicationProtocol())) { | ||
| final RuntimeException cause = Status.UNAVAILABLE | ||
| .withDescription("Failed protocol negotiation: Unable to find compatible protocol") | ||
| .asRuntimeException(); |
There was a problem hiding this comment.
How about using asException()?
Sorry, something went wrong.
There was a problem hiding this comment.
Updated in 64ca1d7. The ALPN negotiation failure now uses Status.asException().
Sorry, something went wrong.
| if (failureReported) { | ||
| return; | ||
| } | ||
| failureReported = true; |
There was a problem hiding this comment.
It is better to use AtomicBoolean and compareAndSet:
if (failureReported.compareAndSet(false, true)) {
return;
}
Sorry, something went wrong.
There was a problem hiding this comment.
Updated in 64ca1d7. failureReported is now an AtomicBoolean. I used if (!failureReported.compareAndSet(false, true)) { return; } so that the first failure reaches the listener and subsequent reports are skipped.
Sorry, something went wrong.
| if (!sslContext.applicationProtocolNegotiator().protocols() | ||
| .contains(sslHandler.applicationProtocol())) { | ||
| final RuntimeException cause = Status.UNAVAILABLE | ||
| .withDescription("Failed protocol negotiation: Unable to find compatible protocol") |
There was a problem hiding this comment.
Include the protocol string in the exception:
final String protocol = sslHandler.applicationProtocol();
if (!sslContext.applicationProtocolNegotiator().protocols().contains(protocol)) {
final Exception cause = Status.UNAVAILABLE
.withDescription("Failed protocol negotiation: Unable to find compatible protocol for " + protocol)
Sorry, something went wrong.
There was a problem hiding this comment.
Updated in 64ca1d7. The negotiated protocol is captured and included in the ALPN failure description.
Sorry, something went wrong.
There was a problem hiding this comment.
+1 the change looks good.
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
What changes were proposed in this pull request?
Add an optional generic ServerCredentials configuration to ratis-grpc. Applications can register credentials through GrpcConfigKeys.Server.setCredentials(...), and Ratis passes them directly to NettyServerBuilder.forAddress(...). This supports custom credential implementations without specializing the configuration API for one use case.
This pull request also adds TlsHandshakeFailureServerCredentials.create(GrpcTlsConfig, Consumer<TlsHandshakeFailureServerCredentials.Event>) for applications that need to observe inbound gRPC TLS handshake failures. Ratis reports the original cause and the physical local and remote socket addresses. The callback runs on a transport event-loop thread and must not block. Listener failures are isolated from the TLS failure and channel-closing behavior. Ratis does not perform audit logging or require callers to persist the exception; applications may use only the endpoint information when that is sufficient for their audit policy.
The TLS handshake failure credentials wrap the shaded gRPC protocol negotiator inside Ratis. They report TLS and ALPN negotiation failures at most once per physical connection and ignore channel closure without an SSLException. Configured server credentials apply to SERVER, CLIENT, and ADMIN server endpoints, including shared ports. When no credentials are configured, the existing server creation and SslContext paths remain unchanged.
What is the link to the Apache JIRA
https://issues.apache.org/jira/browse/RATIS-2638
How was this patch tested?
Added TestRaftServerWithGrpc#testTlsHandshakeFailureListener, which verifies that a valid TLS request does not trigger the listener and that a plaintext connection to the TLS port reports one inbound failure with the expected local and remote addresses.
Also ran: