Committed by
Gerrit Code Review
Adding TLS for NettyMessaging and configurable on NettyMessagingManager through JAVA_OPTS
Change-Id: I5e77658cbae70d3facbe9e1f56c9fa9fcf0e00cc
Showing
3 changed files
with
145 additions
and
14 deletions
1 | package org.onosproject.store.cluster.messaging.impl; | 1 | package org.onosproject.store.cluster.messaging.impl; |
2 | 2 | ||
3 | +import com.google.common.base.Strings; | ||
3 | import org.apache.felix.scr.annotations.Activate; | 4 | import org.apache.felix.scr.annotations.Activate; |
4 | import org.apache.felix.scr.annotations.Component; | 5 | import org.apache.felix.scr.annotations.Component; |
5 | import org.apache.felix.scr.annotations.Deactivate; | 6 | import org.apache.felix.scr.annotations.Deactivate; |
... | @@ -22,12 +23,15 @@ public class NettyMessagingManager extends NettyMessaging { | ... | @@ -22,12 +23,15 @@ public class NettyMessagingManager extends NettyMessaging { |
22 | 23 | ||
23 | private final Logger log = LoggerFactory.getLogger(getClass()); | 24 | private final Logger log = LoggerFactory.getLogger(getClass()); |
24 | 25 | ||
26 | + private static final short MIN_KS_LENGTH = 6; | ||
27 | + | ||
25 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 28 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
26 | protected ClusterDefinitionService clusterDefinitionService; | 29 | protected ClusterDefinitionService clusterDefinitionService; |
27 | 30 | ||
28 | @Activate | 31 | @Activate |
29 | public void activate() throws Exception { | 32 | public void activate() throws Exception { |
30 | ControllerNode localNode = clusterDefinitionService.localNode(); | 33 | ControllerNode localNode = clusterDefinitionService.localNode(); |
34 | + getTLSParameters(); | ||
31 | super.start(new Endpoint(localNode.ip(), localNode.tcpPort())); | 35 | super.start(new Endpoint(localNode.ip(), localNode.tcpPort())); |
32 | log.info("Started"); | 36 | log.info("Started"); |
33 | } | 37 | } |
... | @@ -37,4 +41,32 @@ public class NettyMessagingManager extends NettyMessaging { | ... | @@ -37,4 +41,32 @@ public class NettyMessagingManager extends NettyMessaging { |
37 | super.stop(); | 41 | super.stop(); |
38 | log.info("Stopped"); | 42 | log.info("Stopped"); |
39 | } | 43 | } |
40 | -} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
44 | + | ||
45 | + private void getTLSParameters() { | ||
46 | + String tempString = System.getProperty("enableNettyTLS"); | ||
47 | + enableNettyTLS = Strings.isNullOrEmpty(tempString) ? TLS_DISABLED : Boolean.parseBoolean(tempString); | ||
48 | + log.info("enableNettyTLS = {}", enableNettyTLS); | ||
49 | + if (enableNettyTLS) { | ||
50 | + ksLocation = System.getProperty("javax.net.ssl.keyStore"); | ||
51 | + if (Strings.isNullOrEmpty(ksLocation)) { | ||
52 | + enableNettyTLS = TLS_DISABLED; | ||
53 | + return; | ||
54 | + } | ||
55 | + tsLocation = System.getProperty("javax.net.ssl.trustStore"); | ||
56 | + if (Strings.isNullOrEmpty(tsLocation)) { | ||
57 | + enableNettyTLS = TLS_DISABLED; | ||
58 | + return; | ||
59 | + } | ||
60 | + ksPwd = System.getProperty("javax.net.ssl.keyStorePassword").toCharArray(); | ||
61 | + if (MIN_KS_LENGTH > ksPwd.length) { | ||
62 | + enableNettyTLS = TLS_DISABLED; | ||
63 | + return; | ||
64 | + } | ||
65 | + tsPwd = System.getProperty("javax.net.ssl.trustStorePassword").toCharArray(); | ||
66 | + if (MIN_KS_LENGTH > tsPwd.length) { | ||
67 | + enableNettyTLS = TLS_DISABLED; | ||
68 | + return; | ||
69 | + } | ||
70 | + } | ||
71 | + } | ||
72 | +} | ... | ... |
... | @@ -6,6 +6,10 @@ | ... | @@ -6,6 +6,10 @@ |
6 | # uncomment the following line for performance testing | 6 | # uncomment the following line for performance testing |
7 | #export JAVA_OPTS="${JAVA_OPTS:--Xms8G -Xmx8G -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:+PrintGCDetails -XX:+PrintGCTimeStamps}" | 7 | #export JAVA_OPTS="${JAVA_OPTS:--Xms8G -Xmx8G -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:+PrintGCDetails -XX:+PrintGCTimeStamps}" |
8 | 8 | ||
9 | +# uncomment the following line for Netty TLS encryption | ||
10 | +# Do modify the keystore location/password and truststore location/password accordingly | ||
11 | +#export JAVA_OPTS="${JAVA_OPTS:--DenableNettyTLS=true -Djavax.net.ssl.keyStore=/home/ubuntu/onos.jks -Djavax.net.ssl.keyStorePassword=222222 -Djavax.net.ssl.trustStore=/home/ubuntu/onos.jks -Djavax.net.ssl.trustStorePassword=222222}" | ||
12 | + | ||
9 | ONOS_HOME=/opt/onos | 13 | ONOS_HOME=/opt/onos |
10 | 14 | ||
11 | [ -d $ONOS_HOME ] && cd $ONOS_HOME || ONOS_HOME=$(dirname $0)/.. | 15 | [ -d $ONOS_HOME ] && cd $ONOS_HOME || ONOS_HOME=$(dirname $0)/.. | ... | ... |
... | @@ -35,7 +35,10 @@ import io.netty.channel.socket.SocketChannel; | ... | @@ -35,7 +35,10 @@ import io.netty.channel.socket.SocketChannel; |
35 | import io.netty.channel.socket.nio.NioServerSocketChannel; | 35 | import io.netty.channel.socket.nio.NioServerSocketChannel; |
36 | import io.netty.channel.socket.nio.NioSocketChannel; | 36 | import io.netty.channel.socket.nio.NioSocketChannel; |
37 | 37 | ||
38 | +import java.io.FileInputStream; | ||
38 | import java.io.IOException; | 39 | import java.io.IOException; |
40 | +import java.security.KeyStore; | ||
41 | + | ||
39 | import java.util.Map; | 42 | import java.util.Map; |
40 | import java.util.concurrent.CompletableFuture; | 43 | import java.util.concurrent.CompletableFuture; |
41 | import java.util.concurrent.ConcurrentHashMap; | 44 | import java.util.concurrent.ConcurrentHashMap; |
... | @@ -60,6 +63,11 @@ import com.google.common.cache.CacheBuilder; | ... | @@ -60,6 +63,11 @@ import com.google.common.cache.CacheBuilder; |
60 | import com.google.common.cache.RemovalListener; | 63 | import com.google.common.cache.RemovalListener; |
61 | import com.google.common.cache.RemovalNotification; | 64 | import com.google.common.cache.RemovalNotification; |
62 | 65 | ||
66 | +import javax.net.ssl.KeyManagerFactory; | ||
67 | +import javax.net.ssl.SSLContext; | ||
68 | +import javax.net.ssl.SSLEngine; | ||
69 | +import javax.net.ssl.TrustManagerFactory; | ||
70 | + | ||
63 | /** | 71 | /** |
64 | * Implementation of MessagingService based on <a href="http://netty.io/">Netty</a> framework. | 72 | * Implementation of MessagingService based on <a href="http://netty.io/">Netty</a> framework. |
65 | */ | 73 | */ |
... | @@ -93,6 +101,14 @@ public class NettyMessaging implements MessagingService { | ... | @@ -93,6 +101,14 @@ public class NettyMessaging implements MessagingService { |
93 | private Class<? extends ServerChannel> serverChannelClass; | 101 | private Class<? extends ServerChannel> serverChannelClass; |
94 | private Class<? extends Channel> clientChannelClass; | 102 | private Class<? extends Channel> clientChannelClass; |
95 | 103 | ||
104 | + protected static final boolean TLS_DISABLED = false; | ||
105 | + protected boolean enableNettyTLS = TLS_DISABLED; | ||
106 | + | ||
107 | + protected String ksLocation; | ||
108 | + protected String tsLocation; | ||
109 | + protected char[] ksPwd; | ||
110 | + protected char[] tsPwd; | ||
111 | + | ||
96 | private void initEventLoopGroup() { | 112 | private void initEventLoopGroup() { |
97 | // try Epoll first and if that does work, use nio. | 113 | // try Epoll first and if that does work, use nio. |
98 | try { | 114 | try { |
... | @@ -216,9 +232,9 @@ public class NettyMessaging implements MessagingService { | ... | @@ -216,9 +232,9 @@ public class NettyMessaging implements MessagingService { |
216 | handler.apply(message.payload()).whenComplete((result, error) -> { | 232 | handler.apply(message.payload()).whenComplete((result, error) -> { |
217 | if (error == null) { | 233 | if (error == null) { |
218 | InternalMessage response = new InternalMessage(message.id(), | 234 | InternalMessage response = new InternalMessage(message.id(), |
219 | - localEp, | 235 | + localEp, |
220 | - REPLY_MESSAGE_TYPE, | 236 | + REPLY_MESSAGE_TYPE, |
221 | - result); | 237 | + result); |
222 | sendAsync(message.sender(), response).whenComplete((r, e) -> { | 238 | sendAsync(message.sender(), response).whenComplete((r, e) -> { |
223 | if (e != null) { | 239 | if (e != null) { |
224 | log.debug("Failed to respond", e); | 240 | log.debug("Failed to respond", e); |
... | @@ -241,11 +257,15 @@ public class NettyMessaging implements MessagingService { | ... | @@ -241,11 +257,15 @@ public class NettyMessaging implements MessagingService { |
241 | b.option(ChannelOption.SO_RCVBUF, 1048576); | 257 | b.option(ChannelOption.SO_RCVBUF, 1048576); |
242 | b.option(ChannelOption.TCP_NODELAY, true); | 258 | b.option(ChannelOption.TCP_NODELAY, true); |
243 | b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); | 259 | b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); |
244 | - b.group(serverGroup, clientGroup) | 260 | + b.group(serverGroup, clientGroup); |
245 | - .channel(serverChannelClass) | 261 | + b.channel(serverChannelClass); |
246 | - .childHandler(new OnosCommunicationChannelInitializer()) | 262 | + if (enableNettyTLS) { |
247 | - .option(ChannelOption.SO_BACKLOG, 128) | 263 | + b.childHandler(new SSLServerCommunicationChannelInitializer()); |
248 | - .childOption(ChannelOption.SO_KEEPALIVE, true); | 264 | + } else { |
265 | + b.childHandler(new OnosCommunicationChannelInitializer()); | ||
266 | + } | ||
267 | + b.option(ChannelOption.SO_BACKLOG, 128); | ||
268 | + b.childOption(ChannelOption.SO_KEEPALIVE, true); | ||
249 | 269 | ||
250 | // Bind and start to accept incoming connections. | 270 | // Bind and start to accept incoming connections. |
251 | b.bind(localEp.port()).sync().addListener(future -> { | 271 | b.bind(localEp.port()).sync().addListener(future -> { |
... | @@ -283,7 +303,11 @@ public class NettyMessaging implements MessagingService { | ... | @@ -283,7 +303,11 @@ public class NettyMessaging implements MessagingService { |
283 | // http://normanmaurer.me/presentations/2014-facebook-eng-netty/slides.html#37.0 | 303 | // http://normanmaurer.me/presentations/2014-facebook-eng-netty/slides.html#37.0 |
284 | bootstrap.channel(clientChannelClass); | 304 | bootstrap.channel(clientChannelClass); |
285 | bootstrap.option(ChannelOption.SO_KEEPALIVE, true); | 305 | bootstrap.option(ChannelOption.SO_KEEPALIVE, true); |
286 | - bootstrap.handler(new OnosCommunicationChannelInitializer()); | 306 | + if (enableNettyTLS) { |
307 | + bootstrap.handler(new SSLClientCommunicationChannelInitializer()); | ||
308 | + } else { | ||
309 | + bootstrap.handler(new OnosCommunicationChannelInitializer()); | ||
310 | + } | ||
287 | // Start the client. | 311 | // Start the client. |
288 | ChannelFuture f = bootstrap.connect(ep.host().toString(), ep.port()).sync(); | 312 | ChannelFuture f = bootstrap.connect(ep.host().toString(), ep.port()).sync(); |
289 | log.debug("Established a new connection to {}", ep); | 313 | log.debug("Established a new connection to {}", ep); |
... | @@ -301,6 +325,77 @@ public class NettyMessaging implements MessagingService { | ... | @@ -301,6 +325,77 @@ public class NettyMessaging implements MessagingService { |
301 | } | 325 | } |
302 | } | 326 | } |
303 | 327 | ||
328 | + private class SSLServerCommunicationChannelInitializer extends ChannelInitializer<SocketChannel> { | ||
329 | + | ||
330 | + private final ChannelHandler dispatcher = new InboundMessageDispatcher(); | ||
331 | + private final ChannelHandler encoder = new MessageEncoder(); | ||
332 | + | ||
333 | + @Override | ||
334 | + protected void initChannel(SocketChannel channel) throws Exception { | ||
335 | + TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); | ||
336 | + KeyStore ts = KeyStore.getInstance("JKS"); | ||
337 | + ts.load(new FileInputStream(tsLocation), tsPwd); | ||
338 | + tmFactory.init(ts); | ||
339 | + | ||
340 | + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); | ||
341 | + KeyStore ks = KeyStore.getInstance("JKS"); | ||
342 | + ks.load(new FileInputStream(ksLocation), ksPwd); | ||
343 | + kmf.init(ks, ksPwd); | ||
344 | + | ||
345 | + SSLContext serverContext = SSLContext.getInstance("TLS"); | ||
346 | + serverContext.init(kmf.getKeyManagers(), tmFactory.getTrustManagers(), null); | ||
347 | + | ||
348 | + SSLEngine serverSSLEngine = serverContext.createSSLEngine(); | ||
349 | + | ||
350 | + serverSSLEngine.setNeedClientAuth(true); | ||
351 | + serverSSLEngine.setUseClientMode(false); | ||
352 | + serverSSLEngine.setEnabledProtocols(serverSSLEngine.getSupportedProtocols()); | ||
353 | + serverSSLEngine.setEnabledCipherSuites(serverSSLEngine.getSupportedCipherSuites()); | ||
354 | + serverSSLEngine.setEnableSessionCreation(true); | ||
355 | + | ||
356 | + channel.pipeline().addLast("ssl", new io.netty.handler.ssl.SslHandler(serverSSLEngine)) | ||
357 | + .addLast("encoder", encoder) | ||
358 | + .addLast("decoder", new MessageDecoder()) | ||
359 | + .addLast("handler", dispatcher); | ||
360 | + } | ||
361 | + | ||
362 | + } | ||
363 | + | ||
364 | + private class SSLClientCommunicationChannelInitializer extends ChannelInitializer<SocketChannel> { | ||
365 | + | ||
366 | + private final ChannelHandler dispatcher = new InboundMessageDispatcher(); | ||
367 | + private final ChannelHandler encoder = new MessageEncoder(); | ||
368 | + | ||
369 | + @Override | ||
370 | + protected void initChannel(SocketChannel channel) throws Exception { | ||
371 | + TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); | ||
372 | + KeyStore ts = KeyStore.getInstance("JKS"); | ||
373 | + ts.load(new FileInputStream(tsLocation), tsPwd); | ||
374 | + tmFactory.init(ts); | ||
375 | + | ||
376 | + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); | ||
377 | + KeyStore ks = KeyStore.getInstance("JKS"); | ||
378 | + ks.load(new FileInputStream(ksLocation), ksPwd); | ||
379 | + kmf.init(ks, ksPwd); | ||
380 | + | ||
381 | + SSLContext clientContext = SSLContext.getInstance("TLS"); | ||
382 | + clientContext.init(kmf.getKeyManagers(), tmFactory.getTrustManagers(), null); | ||
383 | + | ||
384 | + SSLEngine clientSSLEngine = clientContext.createSSLEngine(); | ||
385 | + | ||
386 | + clientSSLEngine.setUseClientMode(true); | ||
387 | + clientSSLEngine.setEnabledProtocols(clientSSLEngine.getSupportedProtocols()); | ||
388 | + clientSSLEngine.setEnabledCipherSuites(clientSSLEngine.getSupportedCipherSuites()); | ||
389 | + clientSSLEngine.setEnableSessionCreation(true); | ||
390 | + | ||
391 | + channel.pipeline().addLast("ssl", new io.netty.handler.ssl.SslHandler(clientSSLEngine)) | ||
392 | + .addLast("encoder", encoder) | ||
393 | + .addLast("decoder", new MessageDecoder()) | ||
394 | + .addLast("handler", dispatcher); | ||
395 | + } | ||
396 | + | ||
397 | + } | ||
398 | + | ||
304 | private class OnosCommunicationChannelInitializer extends ChannelInitializer<SocketChannel> { | 399 | private class OnosCommunicationChannelInitializer extends ChannelInitializer<SocketChannel> { |
305 | 400 | ||
306 | private final ChannelHandler dispatcher = new InboundMessageDispatcher(); | 401 | private final ChannelHandler dispatcher = new InboundMessageDispatcher(); |
... | @@ -308,10 +403,10 @@ public class NettyMessaging implements MessagingService { | ... | @@ -308,10 +403,10 @@ public class NettyMessaging implements MessagingService { |
308 | 403 | ||
309 | @Override | 404 | @Override |
310 | protected void initChannel(SocketChannel channel) throws Exception { | 405 | protected void initChannel(SocketChannel channel) throws Exception { |
311 | - channel.pipeline() | 406 | + channel.pipeline() |
312 | - .addLast("encoder", encoder) | 407 | + .addLast("encoder", encoder) |
313 | - .addLast("decoder", new MessageDecoder()) | 408 | + .addLast("decoder", new MessageDecoder()) |
314 | - .addLast("handler", dispatcher); | 409 | + .addLast("handler", dispatcher); |
315 | } | 410 | } |
316 | } | 411 | } |
317 | 412 | ... | ... |
-
Please register or login to post a comment