-
Notifications
You must be signed in to change notification settings - Fork 3.3k
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
HBASE-28317: Expose client TLS certificate on RpcCallContext #5644
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,8 @@ | |
import java.io.InterruptedIOException; | ||
import java.net.InetSocketAddress; | ||
import java.net.SocketAddress; | ||
import java.security.cert.Certificate; | ||
import java.security.cert.X509Certificate; | ||
import java.util.List; | ||
import java.util.concurrent.CountDownLatch; | ||
import java.util.concurrent.atomic.AtomicReference; | ||
|
@@ -166,10 +168,10 @@ protected void initChannel(Channel ch) throws Exception { | |
ChannelPipeline pipeline = ch.pipeline(); | ||
FixedLengthFrameDecoder preambleDecoder = new FixedLengthFrameDecoder(6); | ||
preambleDecoder.setSingleDecode(true); | ||
NettyServerRpcConnection conn = createNettyServerRpcConnection(ch); | ||
if (conf.getBoolean(HBASE_SERVER_NETTY_TLS_ENABLED, false)) { | ||
initSSL(pipeline, conf.getBoolean(HBASE_SERVER_NETTY_TLS_SUPPORTPLAINTEXT, true)); | ||
initSSL(pipeline, conn, conf.getBoolean(HBASE_SERVER_NETTY_TLS_SUPPORTPLAINTEXT, true)); | ||
} | ||
NettyServerRpcConnection conn = createNettyServerRpcConnection(ch); | ||
pipeline.addLast(NettyRpcServerPreambleHandler.DECODER_NAME, preambleDecoder) | ||
.addLast(new NettyRpcServerPreambleHandler(NettyRpcServer.this, conn)) | ||
// We need NettyRpcServerResponseEncoder here because NettyRpcServerPreambleHandler may | ||
|
@@ -378,7 +380,7 @@ public int getNumOpenConnections() { | |
return allChannels.size(); | ||
} | ||
|
||
private void initSSL(ChannelPipeline p, boolean supportPlaintext) | ||
private void initSSL(ChannelPipeline p, NettyServerRpcConnection conn, boolean supportPlaintext) | ||
throws X509Exception, IOException { | ||
SslContext nettySslContext = getSslContext(); | ||
|
||
|
@@ -413,6 +415,19 @@ private void initSSL(ChannelPipeline p, boolean supportPlaintext) | |
sslHandler.setWrapDataSize( | ||
conf.getInt(HBASE_SERVER_NETTY_TLS_WRAP_SIZE, DEFAULT_HBASE_SERVER_NETTY_TLS_WRAP_SIZE)); | ||
|
||
sslHandler.handshakeFuture().addListener(future -> { | ||
try { | ||
Certificate[] certificates = sslHandler.engine().getSession().getPeerCertificates(); | ||
if (certificates.length > 0) { | ||
conn.clientCertificate = (X509Certificate) certificates[0]; | ||
} else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should inspect the Another thing I notice in zookeeper is that they set the entire Certificate[] onto the connection, so that someone can inspect the whole certificate chain if they want. I think we should probably do that in order to avoid having to break this interface in the future if someone wants more than the head of the chain. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've changed the interface to use the certificate chain. I'm also logging when |
||
LOG.debug("No client certificate found for peer {}", remoteAddress); | ||
} | ||
} catch (Exception e) { | ||
LOG.debug("Failure getting peer certificate for {}", remoteAddress, e); | ||
} | ||
}); | ||
|
||
p.addLast("ssl", sslHandler); | ||
LOG.debug("SSL handler added for channel: {}", p.channel()); | ||
} | ||
|
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.
@Apache9 do you think a listener is the right approach here? I'm wondering if we should instead pass the SSLHandler into NettyServerRpcConnection, and directly call
handler.handshakeFuture().get()
insetupHandlers()
. That way it's more explicit that we have the certificate on the connection prior to handling any requests. With the listener approach, I'm not 100% sure we can guarantee that the listener is executed in the eventLoop prior to the channelRead0 in NettyRpcServerPreambleHandler.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 never do future.get in event loop thread, as it has serious performance impact, or even dead lock...
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.
That makes sense. Do you think we should leave it as is?
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.
https://stackoverflow.com/questions/70654915/order-of-invocation-of-listeners
Norman Maurer answered that the invocation order of listeners is the same with adding order. And I checked the code, if there are multiple listeners netty will call them sequentially, with the adding order. So here, since we are the first listener(at least first in the listeners added by our code), so I think we can guarantee that NettyRpcServerPreambleHandler.channelRead can see the certificates.