Adding TLS for NettyMessaging and configurable on NettyMessagingManager through JAVA_OPTS
Change-Id: I5e77658cbae70d3facbe9e1f56c9fa9fcf0e00cc
diff --git a/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java b/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java
index 4777fdb..8b2cc8e 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/cluster/messaging/impl/NettyMessagingManager.java
@@ -1,5 +1,6 @@
package org.onosproject.store.cluster.messaging.impl;
+import com.google.common.base.Strings;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -22,12 +23,15 @@
private final Logger log = LoggerFactory.getLogger(getClass());
+ private static final short MIN_KS_LENGTH = 6;
+
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ClusterDefinitionService clusterDefinitionService;
@Activate
public void activate() throws Exception {
ControllerNode localNode = clusterDefinitionService.localNode();
+ getTLSParameters();
super.start(new Endpoint(localNode.ip(), localNode.tcpPort()));
log.info("Started");
}
@@ -37,4 +41,32 @@
super.stop();
log.info("Stopped");
}
-}
\ No newline at end of file
+
+ private void getTLSParameters() {
+ String tempString = System.getProperty("enableNettyTLS");
+ enableNettyTLS = Strings.isNullOrEmpty(tempString) ? TLS_DISABLED : Boolean.parseBoolean(tempString);
+ log.info("enableNettyTLS = {}", enableNettyTLS);
+ if (enableNettyTLS) {
+ ksLocation = System.getProperty("javax.net.ssl.keyStore");
+ if (Strings.isNullOrEmpty(ksLocation)) {
+ enableNettyTLS = TLS_DISABLED;
+ return;
+ }
+ tsLocation = System.getProperty("javax.net.ssl.trustStore");
+ if (Strings.isNullOrEmpty(tsLocation)) {
+ enableNettyTLS = TLS_DISABLED;
+ return;
+ }
+ ksPwd = System.getProperty("javax.net.ssl.keyStorePassword").toCharArray();
+ if (MIN_KS_LENGTH > ksPwd.length) {
+ enableNettyTLS = TLS_DISABLED;
+ return;
+ }
+ tsPwd = System.getProperty("javax.net.ssl.trustStorePassword").toCharArray();
+ if (MIN_KS_LENGTH > tsPwd.length) {
+ enableNettyTLS = TLS_DISABLED;
+ return;
+ }
+ }
+ }
+}
diff --git a/tools/package/bin/onos-service b/tools/package/bin/onos-service
index 3625c82..942caae 100755
--- a/tools/package/bin/onos-service
+++ b/tools/package/bin/onos-service
@@ -6,6 +6,10 @@
# uncomment the following line for performance testing
#export JAVA_OPTS="${JAVA_OPTS:--Xms8G -Xmx8G -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode -XX:+PrintGCDetails -XX:+PrintGCTimeStamps}"
+# uncomment the following line for Netty TLS encryption
+# Do modify the keystore location/password and truststore location/password accordingly
+#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}"
+
ONOS_HOME=/opt/onos
[ -d $ONOS_HOME ] && cd $ONOS_HOME || ONOS_HOME=$(dirname $0)/..
diff --git a/utils/netty/src/main/java/org/onlab/netty/NettyMessaging.java b/utils/netty/src/main/java/org/onlab/netty/NettyMessaging.java
index 4e6f4b7..8c759d1 100644
--- a/utils/netty/src/main/java/org/onlab/netty/NettyMessaging.java
+++ b/utils/netty/src/main/java/org/onlab/netty/NettyMessaging.java
@@ -35,7 +35,10 @@
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
+import java.io.FileInputStream;
import java.io.IOException;
+import java.security.KeyStore;
+
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
@@ -60,6 +63,11 @@
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.TrustManagerFactory;
+
/**
* Implementation of MessagingService based on <a href="http://netty.io/">Netty</a> framework.
*/
@@ -93,6 +101,14 @@
private Class<? extends ServerChannel> serverChannelClass;
private Class<? extends Channel> clientChannelClass;
+ protected static final boolean TLS_DISABLED = false;
+ protected boolean enableNettyTLS = TLS_DISABLED;
+
+ protected String ksLocation;
+ protected String tsLocation;
+ protected char[] ksPwd;
+ protected char[] tsPwd;
+
private void initEventLoopGroup() {
// try Epoll first and if that does work, use nio.
try {
@@ -216,9 +232,9 @@
handler.apply(message.payload()).whenComplete((result, error) -> {
if (error == null) {
InternalMessage response = new InternalMessage(message.id(),
- localEp,
- REPLY_MESSAGE_TYPE,
- result);
+ localEp,
+ REPLY_MESSAGE_TYPE,
+ result);
sendAsync(message.sender(), response).whenComplete((r, e) -> {
if (e != null) {
log.debug("Failed to respond", e);
@@ -241,11 +257,15 @@
b.option(ChannelOption.SO_RCVBUF, 1048576);
b.option(ChannelOption.TCP_NODELAY, true);
b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
- b.group(serverGroup, clientGroup)
- .channel(serverChannelClass)
- .childHandler(new OnosCommunicationChannelInitializer())
- .option(ChannelOption.SO_BACKLOG, 128)
- .childOption(ChannelOption.SO_KEEPALIVE, true);
+ b.group(serverGroup, clientGroup);
+ b.channel(serverChannelClass);
+ if (enableNettyTLS) {
+ b.childHandler(new SSLServerCommunicationChannelInitializer());
+ } else {
+ b.childHandler(new OnosCommunicationChannelInitializer());
+ }
+ b.option(ChannelOption.SO_BACKLOG, 128);
+ b.childOption(ChannelOption.SO_KEEPALIVE, true);
// Bind and start to accept incoming connections.
b.bind(localEp.port()).sync().addListener(future -> {
@@ -283,7 +303,11 @@
// http://normanmaurer.me/presentations/2014-facebook-eng-netty/slides.html#37.0
bootstrap.channel(clientChannelClass);
bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
- bootstrap.handler(new OnosCommunicationChannelInitializer());
+ if (enableNettyTLS) {
+ bootstrap.handler(new SSLClientCommunicationChannelInitializer());
+ } else {
+ bootstrap.handler(new OnosCommunicationChannelInitializer());
+ }
// Start the client.
ChannelFuture f = bootstrap.connect(ep.host().toString(), ep.port()).sync();
log.debug("Established a new connection to {}", ep);
@@ -301,6 +325,77 @@
}
}
+ private class SSLServerCommunicationChannelInitializer extends ChannelInitializer<SocketChannel> {
+
+ private final ChannelHandler dispatcher = new InboundMessageDispatcher();
+ private final ChannelHandler encoder = new MessageEncoder();
+
+ @Override
+ protected void initChannel(SocketChannel channel) throws Exception {
+ TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ KeyStore ts = KeyStore.getInstance("JKS");
+ ts.load(new FileInputStream(tsLocation), tsPwd);
+ tmFactory.init(ts);
+
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ KeyStore ks = KeyStore.getInstance("JKS");
+ ks.load(new FileInputStream(ksLocation), ksPwd);
+ kmf.init(ks, ksPwd);
+
+ SSLContext serverContext = SSLContext.getInstance("TLS");
+ serverContext.init(kmf.getKeyManagers(), tmFactory.getTrustManagers(), null);
+
+ SSLEngine serverSSLEngine = serverContext.createSSLEngine();
+
+ serverSSLEngine.setNeedClientAuth(true);
+ serverSSLEngine.setUseClientMode(false);
+ serverSSLEngine.setEnabledProtocols(serverSSLEngine.getSupportedProtocols());
+ serverSSLEngine.setEnabledCipherSuites(serverSSLEngine.getSupportedCipherSuites());
+ serverSSLEngine.setEnableSessionCreation(true);
+
+ channel.pipeline().addLast("ssl", new io.netty.handler.ssl.SslHandler(serverSSLEngine))
+ .addLast("encoder", encoder)
+ .addLast("decoder", new MessageDecoder())
+ .addLast("handler", dispatcher);
+ }
+
+ }
+
+ private class SSLClientCommunicationChannelInitializer extends ChannelInitializer<SocketChannel> {
+
+ private final ChannelHandler dispatcher = new InboundMessageDispatcher();
+ private final ChannelHandler encoder = new MessageEncoder();
+
+ @Override
+ protected void initChannel(SocketChannel channel) throws Exception {
+ TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ KeyStore ts = KeyStore.getInstance("JKS");
+ ts.load(new FileInputStream(tsLocation), tsPwd);
+ tmFactory.init(ts);
+
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ KeyStore ks = KeyStore.getInstance("JKS");
+ ks.load(new FileInputStream(ksLocation), ksPwd);
+ kmf.init(ks, ksPwd);
+
+ SSLContext clientContext = SSLContext.getInstance("TLS");
+ clientContext.init(kmf.getKeyManagers(), tmFactory.getTrustManagers(), null);
+
+ SSLEngine clientSSLEngine = clientContext.createSSLEngine();
+
+ clientSSLEngine.setUseClientMode(true);
+ clientSSLEngine.setEnabledProtocols(clientSSLEngine.getSupportedProtocols());
+ clientSSLEngine.setEnabledCipherSuites(clientSSLEngine.getSupportedCipherSuites());
+ clientSSLEngine.setEnableSessionCreation(true);
+
+ channel.pipeline().addLast("ssl", new io.netty.handler.ssl.SslHandler(clientSSLEngine))
+ .addLast("encoder", encoder)
+ .addLast("decoder", new MessageDecoder())
+ .addLast("handler", dispatcher);
+ }
+
+ }
+
private class OnosCommunicationChannelInitializer extends ChannelInitializer<SocketChannel> {
private final ChannelHandler dispatcher = new InboundMessageDispatcher();
@@ -308,10 +403,10 @@
@Override
protected void initChannel(SocketChannel channel) throws Exception {
- channel.pipeline()
- .addLast("encoder", encoder)
- .addLast("decoder", new MessageDecoder())
- .addLast("handler", dispatcher);
+ channel.pipeline()
+ .addLast("encoder", encoder)
+ .addLast("decoder", new MessageDecoder())
+ .addLast("handler", dispatcher);
}
}