JunHuy Lam
Committed by Gerrit Code Review

Adding TLS for NettyMessaging and configurable on NettyMessagingManager through JAVA_OPTS

Change-Id: I5e77658cbae70d3facbe9e1f56c9fa9fcf0e00cc
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 }
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 + }
40 } 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 {
...@@ -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);
306 + if (enableNettyTLS) {
307 + bootstrap.handler(new SSLClientCommunicationChannelInitializer());
308 + } else {
286 bootstrap.handler(new OnosCommunicationChannelInitializer()); 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();
......