This is an automated email from the ASF dual-hosted git repository.

ptupitsyn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new 5dd1f38c72 IGNITE-18579 Add SSL support to ScaleCube (#1659)
5dd1f38c72 is described below

commit 5dd1f38c72aecf836ce692ff2d74d283505b4a00
Author: Aleksandr <[email protected]>
AuthorDate: Fri Feb 10 18:55:25 2023 +0400

    IGNITE-18579 Add SSL support to ScaleCube (#1659)
---
 .../java/org/apache/ignite/lang/ErrorGroups.java   |   3 +
 .../AbstractSslConfigurationSchema.java            |  54 ++++++
 .../configuration/KeyStoreConfigurationSchema.java |   6 +-
 .../configuration/NetworkConfigurationSchema.java  |   4 +
 ...tionSchema.java => SslConfigurationSchema.java} |  14 +-
 .../internal/network/netty/ConnectionManager.java  |   7 +-
 .../ignite/internal/network/netty/NettyClient.java |  36 ++--
 .../ignite/internal/network/netty/NettyServer.java |   9 +-
 .../internal/network/netty/PipelineUtils.java      |  19 +-
 .../internal/network/ssl/KeystoreLoader.java       |  47 +++++
 .../internal/network/ssl/SslContextProvider.java   |  92 ++++++++++
 .../internal/network/netty/NettyClientTest.java    |  17 +-
 .../network/ssl/SslContextProviderTest.java        | 202 +++++++++++++++++++++
 .../network/DefaultMessagingServiceTest.java       |  51 +-----
 .../ignite/internal/rest/ItPortRangeTest.java      |   2 +-
 .../ignite/internal/rest/ssl/ItRestSslTest.java    |   2 +-
 .../apache/ignite/internal/rest/ssl/RestNode.java  |   2 +-
 .../org/apache/ignite/internal/ssl/ItSslTest.java  | 193 ++++++++++++++++++++
 .../src/integrationTest/resources/ssl/keystore.p12 | Bin 4286 -> 4533 bytes
 .../integrationTest/resources/ssl/truststore.jks   | Bin 1558 -> 1738 bytes
 20 files changed, 681 insertions(+), 79 deletions(-)

diff --git a/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java 
b/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java
index f9a7a38024..5ee9ea6f12 100755
--- a/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java
+++ b/modules/core/src/main/java/org/apache/ignite/lang/ErrorGroups.java
@@ -39,6 +39,9 @@ public class ErrorGroups {
         /** Illegal argument or argument in a wrong format has been passed. */
         public static final int ILLEGAL_ARGUMENT_ERR = 
COMMON_ERR_GROUP.registerErrorCode(4);
 
+        /** SSL can not be configured error. */
+        public static final int SSL_CONFIGURATION_ERR = 
COMMON_ERR_GROUP.registerErrorCode(5);
+
         /** Unknown error. */
         @Deprecated
         public static final int UNKNOWN_ERR = 
COMMON_ERR_GROUP.registerErrorCode(0xFFFF);
diff --git 
a/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/AbstractSslConfigurationSchema.java
 
b/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/AbstractSslConfigurationSchema.java
new file mode 100644
index 0000000000..2baf3a7fdf
--- /dev/null
+++ 
b/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/AbstractSslConfigurationSchema.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.network.configuration;
+
+import org.apache.ignite.configuration.annotation.AbstractConfiguration;
+import org.apache.ignite.configuration.annotation.ConfigValue;
+import org.apache.ignite.configuration.annotation.Value;
+import org.apache.ignite.configuration.validation.OneOf;
+
+/** SSL configuration schema. */
+@AbstractConfiguration
+public class AbstractSslConfigurationSchema {
+    /** Enable/disable SSL. */
+    @Value(hasDefault = true)
+    public final boolean enabled = false;
+
+    /**
+     * Client authentication. Set to "none" by default.
+     *
+     * <p>If set to "optional", the server will request a certificate from the 
client,
+     * but will not fail if the client does not provide one.
+     *
+     * <p>If set to "require", the server will request a certificate from the 
client,
+     * and will fail if the client does not provide one.
+     */
+    @OneOf({"none", "optional", "require"})
+    @Value(hasDefault = true)
+    public final String clientAuth = "none";
+
+    /** SSL keystore configuration. */
+    @ConfigValue
+    @KeyStoreConfigurationValidator
+    public KeyStoreConfigurationSchema keyStore;
+
+    /** SSL truststore configuration. */
+    @ConfigValue
+    @KeyStoreConfigurationValidator
+    public KeyStoreConfigurationSchema trustStore;
+}
diff --git 
a/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/KeyStoreConfigurationSchema.java
 
b/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/KeyStoreConfigurationSchema.java
index 895fa204d9..bfb3fb1664 100644
--- 
a/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/KeyStoreConfigurationSchema.java
+++ 
b/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/KeyStoreConfigurationSchema.java
@@ -20,16 +20,18 @@ package org.apache.ignite.internal.network.configuration;
 import org.apache.ignite.configuration.annotation.Config;
 import org.apache.ignite.configuration.annotation.Value;
 
-/** Key store configuration. */
+/** Keystore configuration schema. */
 @Config
 public class KeyStoreConfigurationSchema {
-
+    /** Keystore type. */
     @Value(hasDefault = true)
     public String type = "PKCS12";
 
+    /** Keystore path. */
     @Value(hasDefault = true)
     public String path = "";
 
+    /** Keystore password. */
     @Value(hasDefault = true)
     public String password = "";
 }
diff --git 
a/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/NetworkConfigurationSchema.java
 
b/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/NetworkConfigurationSchema.java
index dbe18bee72..3ab3a6041e 100644
--- 
a/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/NetworkConfigurationSchema.java
+++ 
b/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/NetworkConfigurationSchema.java
@@ -70,4 +70,8 @@ public class NetworkConfigurationSchema {
     /** NodeFinder configuration. */
     @ConfigValue
     public NodeFinderConfigurationSchema nodeFinder;
+
+    /** SSL configuration.*/
+    @ConfigValue
+    public SslConfigurationSchema ssl;
 }
diff --git 
a/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/KeyStoreConfigurationSchema.java
 
b/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/SslConfigurationSchema.java
similarity index 74%
copy from 
modules/network/src/main/java/org/apache/ignite/internal/network/configuration/KeyStoreConfigurationSchema.java
copy to 
modules/network/src/main/java/org/apache/ignite/internal/network/configuration/SslConfigurationSchema.java
index 895fa204d9..0c1ca9094e 100644
--- 
a/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/KeyStoreConfigurationSchema.java
+++ 
b/modules/network/src/main/java/org/apache/ignite/internal/network/configuration/SslConfigurationSchema.java
@@ -18,18 +18,8 @@
 package org.apache.ignite.internal.network.configuration;
 
 import org.apache.ignite.configuration.annotation.Config;
-import org.apache.ignite.configuration.annotation.Value;
 
-/** Key store configuration. */
+/** SSL configuration schema. */
 @Config
-public class KeyStoreConfigurationSchema {
-
-    @Value(hasDefault = true)
-    public String type = "PKCS12";
-
-    @Value(hasDefault = true)
-    public String path = "";
-
-    @Value(hasDefault = true)
-    public String password = "";
+public class SslConfigurationSchema extends AbstractSslConfigurationSchema {
 }
diff --git 
a/modules/network/src/main/java/org/apache/ignite/internal/network/netty/ConnectionManager.java
 
b/modules/network/src/main/java/org/apache/ignite/internal/network/netty/ConnectionManager.java
index a9bd44c520..18ef33dbfd 100644
--- 
a/modules/network/src/main/java/org/apache/ignite/internal/network/netty/ConnectionManager.java
+++ 
b/modules/network/src/main/java/org/apache/ignite/internal/network/netty/ConnectionManager.java
@@ -97,6 +97,9 @@ public class ConnectionManager {
     /** Recovery descriptor provider. */
     private final RecoveryDescriptorProvider descriptorProvider = new 
DefaultRecoveryDescriptorProvider();
 
+    /** Network Configuration. */
+    private final NetworkView networkConfiguration;
+
     /**
      * Constructor.
      *
@@ -145,6 +148,7 @@ public class ConnectionManager {
         this.launchId = launchId;
         this.consistentId = consistentId;
         this.clientHandhakeManagerFactory = clientHandhakeManagerFactory;
+        this.networkConfiguration = networkConfiguration;
 
         this.server = new NettyServer(
                 networkConfiguration,
@@ -267,7 +271,8 @@ public class ConnectionManager {
                 address,
                 serializationService,
                 createClientHandshakeManager(connectionId),
-                this::onMessage
+                this::onMessage,
+                this.networkConfiguration.ssl()
         );
 
         client.start(clientBootstrap).whenComplete((sender, throwable) -> {
diff --git 
a/modules/network/src/main/java/org/apache/ignite/internal/network/netty/NettyClient.java
 
b/modules/network/src/main/java/org/apache/ignite/internal/network/netty/NettyClient.java
index c3a40c6194..f4df8d905b 100644
--- 
a/modules/network/src/main/java/org/apache/ignite/internal/network/netty/NettyClient.java
+++ 
b/modules/network/src/main/java/org/apache/ignite/internal/network/netty/NettyClient.java
@@ -21,6 +21,7 @@ import io.netty.bootstrap.Bootstrap;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelInitializer;
 import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.ssl.SslContext;
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
 import java.util.Objects;
@@ -29,9 +30,11 @@ import java.util.concurrent.CompletableFuture;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import org.apache.ignite.internal.future.OrderingFuture;
+import org.apache.ignite.internal.network.configuration.SslView;
 import org.apache.ignite.internal.network.handshake.HandshakeManager;
 import 
org.apache.ignite.internal.network.serialization.PerSessionSerializationService;
 import org.apache.ignite.internal.network.serialization.SerializationService;
+import org.apache.ignite.internal.network.ssl.SslContextProvider;
 import org.apache.ignite.lang.IgniteInternalException;
 import org.jetbrains.annotations.Nullable;
 
@@ -48,44 +51,50 @@ public class NettyClient {
     /** Destination address. */
     private final SocketAddress address;
 
-    /** Future that resolves when the client finished the handshake. */
-    @Nullable
-    private volatile OrderingFuture<NettySender> senderFuture = null;
-
     /** Future that resolves when the client channel is opened. */
     private final CompletableFuture<Void> channelFuture = new 
CompletableFuture<>();
 
-    /** Client channel. */
-    @Nullable
-    private volatile Channel channel = null;
-
     /** Message listener. */
     private final Consumer<InNetworkObject> messageListener;
 
     /** Handshake manager. */
     private final HandshakeManager handshakeManager;
 
+    /** SSL configuration. */
+    private final SslView sslConfiguration;
+
+    /** Future that resolves when the client finished the handshake. */
+    @Nullable
+    private volatile OrderingFuture<NettySender> senderFuture = null;
+
+    /** Client channel. */
+    @Nullable
+    private volatile Channel channel = null;
+
     /** Flag indicating if {@link #stop()} has been called. */
     private boolean stopped = false;
 
     /**
-     * Constructor.
+     * Constructor with SSL configuration.
      *
      * @param address               Destination address.
      * @param serializationService  Serialization service.
      * @param manager               Client handshake manager.
      * @param messageListener       Message listener.
+     * @param sslConfiguration         SSL configuration.
      */
     public NettyClient(
             InetSocketAddress address,
             SerializationService serializationService,
             HandshakeManager manager,
-            Consumer<InNetworkObject> messageListener
+            Consumer<InNetworkObject> messageListener,
+            SslView sslConfiguration
     ) {
         this.address = address;
         this.serializationService = serializationService;
         this.handshakeManager = manager;
         this.messageListener = messageListener;
+        this.sslConfiguration = sslConfiguration;
     }
 
     /**
@@ -112,7 +121,12 @@ public class NettyClient {
                 public void initChannel(SocketChannel ch) {
                     var sessionSerializationService = new 
PerSessionSerializationService(serializationService);
 
-                    PipelineUtils.setup(ch.pipeline(), 
sessionSerializationService, handshakeManager, messageListener);
+                    if (sslConfiguration.enabled()) {
+                        SslContext sslContext = 
SslContextProvider.createClientSslContext(sslConfiguration);
+                        PipelineUtils.setup(ch.pipeline(), 
sessionSerializationService, handshakeManager, messageListener, sslContext);
+                    } else {
+                        PipelineUtils.setup(ch.pipeline(), 
sessionSerializationService, handshakeManager, messageListener);
+                    }
                 }
             });
 
diff --git 
a/modules/network/src/main/java/org/apache/ignite/internal/network/netty/NettyServer.java
 
b/modules/network/src/main/java/org/apache/ignite/internal/network/netty/NettyServer.java
index 52d0e93910..7242c25725 100644
--- 
a/modules/network/src/main/java/org/apache/ignite/internal/network/netty/NettyServer.java
+++ 
b/modules/network/src/main/java/org/apache/ignite/internal/network/netty/NettyServer.java
@@ -23,6 +23,7 @@ import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelInitializer;
 import io.netty.channel.ServerChannel;
 import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.ssl.SslContext;
 import java.net.SocketAddress;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.CompletableFuture;
@@ -33,6 +34,7 @@ import 
org.apache.ignite.internal.network.configuration.NetworkView;
 import org.apache.ignite.internal.network.handshake.HandshakeManager;
 import 
org.apache.ignite.internal.network.serialization.PerSessionSerializationService;
 import org.apache.ignite.internal.network.serialization.SerializationService;
+import org.apache.ignite.internal.network.ssl.SslContextProvider;
 import org.apache.ignite.lang.IgniteInternalException;
 import org.apache.ignite.network.NettyBootstrapFactory;
 import org.jetbrains.annotations.Nullable;
@@ -129,7 +131,12 @@ public class NettyServer {
                             // Get handshake manager for the new channel.
                             HandshakeManager manager = handshakeManager.get();
 
-                            PipelineUtils.setup(ch.pipeline(), 
sessionSerializationService, manager, messageListener);
+                            if (configuration.ssl().enabled()) {
+                                SslContext sslContext = 
SslContextProvider.createServerSslContext(configuration.ssl());
+                                PipelineUtils.setup(ch.pipeline(), 
sessionSerializationService, manager, messageListener, sslContext);
+                            } else {
+                                PipelineUtils.setup(ch.pipeline(), 
sessionSerializationService, manager, messageListener);
+                            }
 
                             
manager.handshakeFuture().thenAccept(newConnectionListener);
                         }
diff --git 
a/modules/network/src/main/java/org/apache/ignite/internal/network/netty/PipelineUtils.java
 
b/modules/network/src/main/java/org/apache/ignite/internal/network/netty/PipelineUtils.java
index 036e81d5da..ec545bd894 100644
--- 
a/modules/network/src/main/java/org/apache/ignite/internal/network/netty/PipelineUtils.java
+++ 
b/modules/network/src/main/java/org/apache/ignite/internal/network/netty/PipelineUtils.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.network.netty;
 
 import io.netty.channel.ChannelPipeline;
+import io.netty.handler.ssl.SslContext;
 import io.netty.handler.stream.ChunkedWriteHandler;
 import java.util.function.Consumer;
 import org.apache.ignite.internal.network.NetworkMessagesFactory;
@@ -30,6 +31,22 @@ public class PipelineUtils {
     /** {@link ChunkedWriteHandler}'s name. */
     private static final String CHUNKED_WRITE_HANDLER_NAME = 
"chunked-write-handler";
 
+    /**
+     * Sets up initial pipeline with ssl.
+     *
+     * @param pipeline Channel pipeline.
+     * @param serializationService Serialization service.
+     * @param handshakeManager Handshake manager.
+     * @param messageListener Message listener.
+     * @param sslContext Netty SSL context.
+     */
+    public static void setup(ChannelPipeline pipeline, 
PerSessionSerializationService serializationService,
+            HandshakeManager handshakeManager, Consumer<InNetworkObject> 
messageListener, SslContext sslContext) {
+        pipeline.addFirst("ssl", 
sslContext.newHandler(pipeline.channel().alloc()));
+
+        setup(pipeline, serializationService, handshakeManager, 
messageListener);
+    }
+
     /**
      * Sets up initial pipeline.
      *
@@ -39,7 +56,7 @@ public class PipelineUtils {
      * @param messageListener Message listener.
      */
     public static void setup(ChannelPipeline pipeline, 
PerSessionSerializationService serializationService,
-                HandshakeManager handshakeManager, Consumer<InNetworkObject> 
messageListener) {
+            HandshakeManager handshakeManager, Consumer<InNetworkObject> 
messageListener) {
         pipeline.addLast(InboundDecoder.NAME, new 
InboundDecoder(serializationService));
         pipeline.addLast(HandshakeHandler.NAME, new 
HandshakeHandler(handshakeManager, messageListener, serializationService));
         pipeline.addLast(CHUNKED_WRITE_HANDLER_NAME, new 
ChunkedWriteHandler());
diff --git 
a/modules/network/src/main/java/org/apache/ignite/internal/network/ssl/KeystoreLoader.java
 
b/modules/network/src/main/java/org/apache/ignite/internal/network/ssl/KeystoreLoader.java
new file mode 100644
index 0000000000..f60d087730
--- /dev/null
+++ 
b/modules/network/src/main/java/org/apache/ignite/internal/network/ssl/KeystoreLoader.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.network.ssl;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import org.apache.ignite.internal.network.configuration.KeyStoreView;
+
+/** Java keystore loader. */
+public final class KeystoreLoader {
+
+    private KeystoreLoader() {
+    }
+
+    /** Initialize and load keystore with provided configuration. */
+    public static KeyStore load(KeyStoreView keyStoreConfiguration)
+            throws KeyStoreException, IOException, CertificateException, 
NoSuchAlgorithmException {
+        char[] password = keyStoreConfiguration.password() == null ? null : 
keyStoreConfiguration.password().toCharArray();
+
+        KeyStore ks = KeyStore.getInstance(keyStoreConfiguration.type());
+        try (var is = 
Files.newInputStream(Path.of(keyStoreConfiguration.path()))) {
+            ks.load(is, password);
+        }
+
+        return ks;
+    }
+}
diff --git 
a/modules/network/src/main/java/org/apache/ignite/internal/network/ssl/SslContextProvider.java
 
b/modules/network/src/main/java/org/apache/ignite/internal/network/ssl/SslContextProvider.java
new file mode 100644
index 0000000000..d50b1acc3f
--- /dev/null
+++ 
b/modules/network/src/main/java/org/apache/ignite/internal/network/ssl/SslContextProvider.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.network.ssl;
+
+import io.netty.handler.ssl.ClientAuth;
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslContextBuilder;
+import java.io.IOException;
+import java.nio.file.NoSuchFileException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.TrustManagerFactory;
+import org.apache.ignite.internal.network.configuration.SslView;
+import org.apache.ignite.lang.ErrorGroups.Common;
+import org.apache.ignite.lang.IgniteException;
+
+/** SSL context provider. */
+public final class SslContextProvider {
+
+    private SslContextProvider() {
+    }
+
+    /** Create client SSL context. */
+    public static SslContext createClientSslContext(SslView ssl) {
+        try {
+            TrustManagerFactory trustManagerFactory = 
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+            trustManagerFactory.init(KeystoreLoader.load(ssl.trustStore()));
+
+            var builder = 
SslContextBuilder.forClient().trustManager(trustManagerFactory);
+
+            ClientAuth clientAuth = 
ClientAuth.valueOf(ssl.clientAuth().toUpperCase());
+            if (ClientAuth.NONE == clientAuth) {
+                return builder.build();
+            }
+
+            KeyManagerFactory keyManagerFactory = 
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+            keyManagerFactory.init(KeystoreLoader.load(ssl.keyStore()), 
ssl.keyStore().password().toCharArray());
+
+            builder.keyManager(keyManagerFactory);
+
+            return builder.build();
+        } catch (NoSuchFileException e) {
+            throw new IgniteException(Common.SSL_CONFIGURATION_ERR, 
String.format("File %s not found", e.getMessage()), e);
+        } catch (IOException | CertificateException | KeyStoreException | 
NoSuchAlgorithmException | UnrecoverableKeyException e) {
+            throw new IgniteException(Common.SSL_CONFIGURATION_ERR, e);
+        }
+    }
+
+    /** Create server SSL context. */
+    public static SslContext createServerSslContext(SslView ssl) {
+        try {
+            KeyManagerFactory keyManagerFactory = 
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+            keyManagerFactory.init(KeystoreLoader.load(ssl.keyStore()), 
ssl.keyStore().password().toCharArray());
+
+            var builder = SslContextBuilder.forServer(keyManagerFactory);
+
+            ClientAuth clientAuth = 
ClientAuth.valueOf(ssl.clientAuth().toUpperCase());
+            if (ClientAuth.NONE == clientAuth) {
+                return builder.build();
+            }
+
+            TrustManagerFactory trustManagerFactory = 
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+            trustManagerFactory.init(KeystoreLoader.load(ssl.trustStore()));
+
+            builder.clientAuth(clientAuth).trustManager(trustManagerFactory);
+
+            return builder.build();
+        } catch (NoSuchFileException e) {
+            throw new IgniteException(Common.SSL_CONFIGURATION_ERR, 
String.format("File %s not found", e.getMessage()), e);
+        } catch (KeyStoreException | NoSuchAlgorithmException | 
CertificateException | UnrecoverableKeyException | IOException e) {
+            throw new IgniteException(Common.SSL_CONFIGURATION_ERR, e);
+        }
+    }
+}
diff --git 
a/modules/network/src/test/java/org/apache/ignite/internal/network/netty/NettyClientTest.java
 
b/modules/network/src/test/java/org/apache/ignite/internal/network/netty/NettyClientTest.java
index 8aef53ff77..466278e413 100644
--- 
a/modules/network/src/test/java/org/apache/ignite/internal/network/netty/NettyClientTest.java
+++ 
b/modules/network/src/test/java/org/apache/ignite/internal/network/netty/NettyClientTest.java
@@ -32,23 +32,32 @@ import java.nio.channels.ClosedChannelException;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
+import 
org.apache.ignite.internal.configuration.testframework.ConfigurationExtension;
+import 
org.apache.ignite.internal.configuration.testframework.InjectConfiguration;
 import org.apache.ignite.internal.future.OrderingFuture;
+import org.apache.ignite.internal.network.configuration.NetworkConfiguration;
 import org.apache.ignite.internal.network.handshake.HandshakeManager;
 import org.apache.ignite.lang.IgniteInternalException;
 import org.apache.ignite.network.NetworkMessage;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.Mockito;
 
 /**
  * Tests for {@link NettyClient}.
  */
+@ExtendWith(ConfigurationExtension.class)
 public class NettyClientTest {
     /** Client. */
     private NettyClient client;
 
     private final InetSocketAddress address = 
InetSocketAddress.createUnresolved("", 0);
 
+    /** Network configuration. */
+    @InjectConfiguration
+    private NetworkConfiguration networkConfiguration;
+
     /**
      * After each.
      */
@@ -169,8 +178,8 @@ public class NettyClientTest {
                 address,
                 null,
                 new MockClientHandshakeManager(channel),
-                (message) -> {
-                }
+                (message) -> {},
+                networkConfiguration.ssl().value()
         );
 
         client.start(bootstrap);
@@ -193,8 +202,8 @@ public class NettyClientTest {
                 address,
                 null,
                 new MockClientHandshakeManager(future.channel()),
-                (message) -> {
-                }
+                (message) -> {},
+                networkConfiguration.ssl().value()
         );
 
         Bootstrap bootstrap = mockBootstrap();
diff --git 
a/modules/network/src/test/java/org/apache/ignite/internal/network/ssl/SslContextProviderTest.java
 
b/modules/network/src/test/java/org/apache/ignite/internal/network/ssl/SslContextProviderTest.java
new file mode 100644
index 0000000000..1f045f7a0c
--- /dev/null
+++ 
b/modules/network/src/test/java/org/apache/ignite/internal/network/ssl/SslContextProviderTest.java
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.network.ssl;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.either;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.junit.Assert.assertThrows;
+
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.util.SelfSignedCertificate;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import 
org.apache.ignite.internal.configuration.testframework.ConfigurationExtension;
+import 
org.apache.ignite.internal.configuration.testframework.InjectConfiguration;
+import org.apache.ignite.internal.network.configuration.SslConfiguration;
+import org.apache.ignite.lang.ErrorGroups.Common;
+import org.apache.ignite.lang.IgniteException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.io.TempDir;
+
+@ExtendWith(ConfigurationExtension.class)
+class SslContextProviderTest {
+
+    @InjectConfiguration
+    private SslConfiguration configuration;
+
+    private String password;
+
+    private String keyStorePkcs12Path;
+
+    private String trustStoreJks12Path;
+
+    @BeforeEach
+    void setUp(@TempDir Path tmpDir) throws KeyStoreException, 
CertificateException, IOException, NoSuchAlgorithmException {
+        password = "changeit";
+        keyStorePkcs12Path = 
tmpDir.resolve("keystore.p12").toAbsolutePath().toString();
+        trustStoreJks12Path = 
tmpDir.resolve("truststore.jks").toAbsolutePath().toString();
+
+        SelfSignedCertificate cert = new SelfSignedCertificate("localhost");
+        generateKeystore(cert);
+        generateTruststore(cert);
+    }
+
+    private void generateTruststore(SelfSignedCertificate cert)
+            throws KeyStoreException, IOException, NoSuchAlgorithmException, 
CertificateException {
+        KeyStore ts = KeyStore.getInstance("JKS");
+        ts.load(null, null);
+        ts.setCertificateEntry("cert", cert.cert());
+        try (FileOutputStream fos = new FileOutputStream(trustStoreJks12Path)) 
{
+            ts.store(fos, password.toCharArray());
+        }
+    }
+
+    private void generateKeystore(SelfSignedCertificate cert)
+            throws KeyStoreException, IOException, NoSuchAlgorithmException, 
CertificateException {
+        KeyStore ks = KeyStore.getInstance("PKCS12");
+        ks.load(null, null);
+        ks.setKeyEntry("key", cert.key(), password.toCharArray(), new 
Certificate[]{cert.cert()});
+        try (FileOutputStream fos = new FileOutputStream(keyStorePkcs12Path)) {
+            ks.store(fos, password.toCharArray());
+        }
+    }
+
+    @Test
+    void createsSslContextForClient() throws Exception {
+        // Given valid self-signed certificate
+        configuration.trustStore().type().update("PKCS12").get();
+        configuration.trustStore().path().update(keyStorePkcs12Path).get();
+        configuration.trustStore().password().update(password).get();
+
+        // When
+        SslContext clientSslContext = 
SslContextProvider.createClientSslContext(configuration.value());
+
+        // Then
+        assertThat(clientSslContext, notNullValue());
+    }
+
+    @Test
+    void createsSslContextForServer() throws Exception {
+        // Given valid self-signed certificate
+        configuration.keyStore().password().update(password).get();
+        configuration.keyStore().path().update(keyStorePkcs12Path).get();
+
+        // When
+        SslContext sslContext = 
SslContextProvider.createServerSslContext(configuration.value());
+
+        // Then
+        assertThat(sslContext, notNullValue());
+    }
+
+    @Test
+    void createsSslContextForServerJks() throws Exception {
+        // Given valid self-signed certificate
+        configuration.keyStore().type().update("JKS").get();
+        configuration.keyStore().password().update(password).get();
+        configuration.keyStore().path().update(trustStoreJks12Path).get();
+
+        // When
+        SslContext sslContext = 
SslContextProvider.createServerSslContext(configuration.value());
+
+        // Then
+        assertThat(sslContext, notNullValue());
+    }
+
+    @Test
+    void throwsIgniteExceptionWhenWrongKeystorePathConfigured() throws 
Exception {
+        // Given wrong path configured for keystore
+        configuration.keyStore().path().update("/no/such/file.pfx").get();
+
+        // When
+        var thrown = assertThrows(
+                IgniteException.class,
+                () -> 
SslContextProvider.createServerSslContext(configuration.value())
+        );
+
+        // Then
+        assertThat(thrown.groupName(), 
equalTo(Common.COMMON_ERR_GROUP.name()));
+        assertThat(thrown.code(), equalTo(Common.SSL_CONFIGURATION_ERR));
+        assertThat(thrown.getMessage(), containsString("File /no/such/file.pfx 
not found"));
+    }
+
+    @Test
+    void throwsIgniteExceptionWhenWrongTruststorePathConfigured() throws 
Exception {
+        // Given wrong path configured for truststore
+        configuration.trustStore().path().update("/no/such/file.pfx").get();
+
+        // When
+        var thrown = assertThrows(
+                IgniteException.class,
+                () -> 
SslContextProvider.createClientSslContext(configuration.value())
+        );
+
+        // Then
+        assertThat(thrown.groupName(), 
equalTo(Common.COMMON_ERR_GROUP.name()));
+        assertThat(thrown.code(), equalTo(Common.SSL_CONFIGURATION_ERR));
+        assertThat(thrown.getMessage(), containsString("File /no/such/file.pfx 
not found"));
+    }
+
+    @Test
+    void throwsIgniteExceptionWhenWrongKeystorePassword() throws Exception {
+        // Given wrong password for keystore
+        configuration.keyStore().path().update(keyStorePkcs12Path).get();
+        configuration.keyStore().password().update("wrong").get();
+
+        // When
+        var thrown = assertThrows(
+                IgniteException.class,
+                () -> 
SslContextProvider.createServerSslContext(configuration.value())
+        );
+
+        // Then
+        assertThat(thrown.groupName(), 
equalTo(Common.COMMON_ERR_GROUP.name()));
+        assertThat(thrown.code(), equalTo(Common.SSL_CONFIGURATION_ERR));
+        assertThat(thrown.getMessage(), containsString("keystore password was 
incorrect"));
+    }
+
+    @Test
+    void throwsIgniteExceptionWhenWrongTruststorePassword() throws Exception {
+        // Given wrong password for truststore
+        configuration.trustStore().path().update(trustStoreJks12Path).get();
+        configuration.trustStore().password().update("wrong").get();
+
+        // When
+        var thrown = assertThrows(
+                IgniteException.class,
+                () -> 
SslContextProvider.createClientSslContext(configuration.value())
+        );
+
+        // Then
+        assertThat(thrown.groupName(), 
equalTo(Common.COMMON_ERR_GROUP.name()));
+        assertThat(thrown.code(), equalTo(Common.SSL_CONFIGURATION_ERR));
+        assertThat(thrown.getMessage(),
+                either(containsString("keystore password was incorrect"))
+                        .or(containsString("password was incorrect")));
+    }
+}
diff --git 
a/modules/network/src/test/java/org/apache/ignite/network/DefaultMessagingServiceTest.java
 
b/modules/network/src/test/java/org/apache/ignite/network/DefaultMessagingServiceTest.java
index aab1680c55..5b1754b349 100644
--- 
a/modules/network/src/test/java/org/apache/ignite/network/DefaultMessagingServiceTest.java
+++ 
b/modules/network/src/test/java/org/apache/ignite/network/DefaultMessagingServiceTest.java
@@ -25,19 +25,18 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.lenient;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
 import java.util.List;
 import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
+import 
org.apache.ignite.internal.configuration.testframework.ConfigurationExtension;
+import 
org.apache.ignite.internal.configuration.testframework.InjectConfiguration;
 import org.apache.ignite.internal.network.NetworkMessagesFactory;
-import org.apache.ignite.internal.network.configuration.InboundView;
 import org.apache.ignite.internal.network.configuration.NetworkConfiguration;
-import org.apache.ignite.internal.network.configuration.NetworkView;
-import org.apache.ignite.internal.network.configuration.OutboundView;
 import org.apache.ignite.internal.network.messages.TestMessage;
 import org.apache.ignite.internal.network.messages.TestMessageTypes;
 import org.apache.ignite.internal.network.messages.TestMessagesFactory;
@@ -60,6 +59,7 @@ import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
 
 @ExtendWith(MockitoExtension.class)
+@ExtendWith(ConfigurationExtension.class)
 class DefaultMessagingServiceTest {
     private static final int SENDER_PORT = 2001;
     private static final int RECEIVER_PORT = 2002;
@@ -67,23 +67,11 @@ class DefaultMessagingServiceTest {
     @Mock
     private TopologyService topologyService;
 
-    @Mock
+    @InjectConfiguration("mock.port=" + SENDER_PORT)
     private NetworkConfiguration senderNetworkConfig;
-    @Mock
-    private NetworkView senderNetworkConfigView;
-    @Mock
-    private OutboundView senderOutboundConfig;
-    @Mock
-    private InboundView senderInboundConfig;
 
-    @Mock
+    @InjectConfiguration("mock.port=" + RECEIVER_PORT)
     private NetworkConfiguration receiverNetworkConfig;
-    @Mock
-    private NetworkView receiverNetworkConfigView;
-    @Mock
-    private OutboundView receiverOutboundConfig;
-    @Mock
-    private InboundView receiverInboundConfig;
 
     private final NetworkMessagesFactory networkMessagesFactory = new 
NetworkMessagesFactory();
     private final TestMessagesFactory testMessagesFactory = new 
TestMessagesFactory();
@@ -102,10 +90,7 @@ class DefaultMessagingServiceTest {
     );
 
     @BeforeEach
-    void setUp() {
-        configureSender();
-        configureReceiver();
-
+    void setUp() throws InterruptedException, ExecutionException {
         
lenient().when(topologyService.getByConsistentId(eq(senderNode.name()))).thenReturn(senderNode);
     }
 
@@ -148,28 +133,6 @@ class DefaultMessagingServiceTest {
         }
     }
 
-    private void configureSender() {
-        when(senderNetworkConfigView.port()).thenReturn(SENDER_PORT);
-        configureNetworkDefaults(senderNetworkConfig, senderNetworkConfigView, 
senderOutboundConfig, senderInboundConfig);
-    }
-
-    private void configureReceiver() {
-        
lenient().when(receiverNetworkConfigView.port()).thenReturn(RECEIVER_PORT);
-        configureNetworkDefaults(receiverNetworkConfig, 
receiverNetworkConfigView, receiverOutboundConfig, receiverInboundConfig);
-    }
-
-    private static void configureNetworkDefaults(
-            NetworkConfiguration networkConfig,
-            NetworkView networkConfigView,
-            OutboundView outboundConfig,
-            InboundView inboundConfig
-    ) {
-        lenient().when(networkConfig.value()).thenReturn(networkConfigView);
-        lenient().when(networkConfigView.portRange()).thenReturn(0);
-        
lenient().when(networkConfigView.outbound()).thenReturn(outboundConfig);
-        lenient().when(networkConfigView.inbound()).thenReturn(inboundConfig);
-    }
-
     private static void awaitQuietly(CountDownLatch latch) {
         try {
             latch.await();
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ItPortRangeTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ItPortRangeTest.java
index 3098c447a4..fb5f7078ad 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ItPortRangeTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ItPortRangeTest.java
@@ -60,7 +60,7 @@ public class ItPortRangeTest {
     private static final String trustStorePath = "ssl/truststore.jks";
 
     /** Trust store password. */
-    private static final String trustStorePassword = "changeIt";
+    private static final String trustStorePassword = "changeit";
 
     /** Path to the working directory. */
     @WorkDirectory
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ssl/ItRestSslTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ssl/ItRestSslTest.java
index 70b5f14722..e2e608cf31 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ssl/ItRestSslTest.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ssl/ItRestSslTest.java
@@ -60,7 +60,7 @@ public class ItRestSslTest {
     private static final String trustStorePath = "ssl/truststore.jks";
 
     /** Trust store password. */
-    private static final String trustStorePassword = "changeIt";
+    private static final String trustStorePassword = "changeit";
 
     /** Path to the working directory. */
     @WorkDirectory
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ssl/RestNode.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ssl/RestNode.java
index f554526994..ca19ddb61f 100644
--- 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ssl/RestNode.java
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/rest/ssl/RestNode.java
@@ -27,7 +27,7 @@ public class RestNode {
     private static final String keyStorePath = "ssl/keystore.p12";
 
     /** Key store password. */
-    private static final String keyStorePassword = "changeIt";
+    private static final String keyStorePassword = "changeit";
 
     private final Path workDir;
     private final String name;
diff --git 
a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/ssl/ItSslTest.java
 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/ssl/ItSslTest.java
new file mode 100644
index 0000000000..f24e9deb29
--- /dev/null
+++ 
b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/ssl/ItSslTest.java
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.ssl;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+import java.nio.file.Path;
+import org.apache.ignite.internal.Cluster;
+import org.apache.ignite.internal.testframework.WorkDirectory;
+import org.apache.ignite.internal.testframework.WorkDirectoryExtension;
+import org.intellij.lang.annotations.Language;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestInstance.Lifecycle;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+/** SSL support integration test. */
+@ExtendWith(WorkDirectoryExtension.class)
+public class ItSslTest {
+
+    private static String password;
+
+    private static String trustStorePath;
+
+    private static String keyStorePath;
+
+    @BeforeAll
+    static void beforeAll() {
+        password = "changeit";
+        trustStorePath = 
ItSslTest.class.getClassLoader().getResource("ssl/truststore.jks").getPath();
+        keyStorePath = 
ItSslTest.class.getClassLoader().getResource("ssl/keystore.p12").getPath();
+    }
+
+    @Nested
+    @TestInstance(Lifecycle.PER_CLASS)
+    class ClusterWithoutSsl {
+
+        @WorkDirectory
+        private Path workDir;
+
+        private Cluster cluster;
+
+        @Language("JSON")
+        String sslDisabledBoostrapConfig = "{\n"
+                + "  network: {\n"
+                + "    ssl.enabled: false,\n"
+                + "    port: 3355,\n"
+                + "    portRange: 2,\n"
+                + "    nodeFinder:{\n"
+                + "      netClusterNodes: [ \"localhost:3355\", 
\"localhost:3356\" ]\n"
+                + "    }\n"
+                + "  }\n"
+                + "}";
+
+        @BeforeEach
+        void setUp(TestInfo testInfo) {
+            cluster = new Cluster(testInfo, workDir, 
sslDisabledBoostrapConfig);
+            cluster.startAndInit(2);
+        }
+
+        @AfterEach
+        void tearDown() {
+            cluster.shutdown();
+        }
+
+        @Test
+        @DisplayName("SSL disabled and cluster starts")
+        void clusterStartsWithDisabledSsl(TestInfo testInfo) {
+            assertThat(cluster.runningNodes().count(), is(2L));
+        }
+    }
+
+    @Nested
+    @TestInstance(Lifecycle.PER_CLASS)
+    class ClusterWithSsl {
+
+        @WorkDirectory
+        private Path workDir;
+
+        private Cluster cluster;
+
+        @Language("JSON")
+        String sslEnabledBoostrapConfig = "{\n"
+                + "  network: {\n"
+                + "    ssl : {"
+                + "      enabled: true,\n"
+                + "      trustStore: {\n"
+                + "        password: \"" + password + "\","
+                + "        path: \"" + trustStorePath + "\""
+                + "      },\n"
+                + "      keyStore: {\n"
+                + "        password: \"" + password + "\","
+                + "        path: \"" + keyStorePath + "\""
+                + "      }\n"
+                + "    },\n"
+                + "    port: 3345,\n"
+                + "    portRange: 2,\n"
+                + "    nodeFinder:{\n"
+                + "      netClusterNodes: [ \"localhost:3345\", 
\"localhost:3346\" ]\n"
+                + "    }\n"
+                + "  }\n"
+                + "}";
+
+        @BeforeEach
+        void setUp(TestInfo testInfo) {
+            cluster = new Cluster(testInfo, workDir, sslEnabledBoostrapConfig);
+            cluster.startAndInit(2);
+        }
+
+        @AfterEach
+        void tearDown() {
+            cluster.shutdown();
+        }
+
+        @Test
+        @DisplayName("SSL enabled and setup correctly then cluster starts")
+        void clusterStartsWithEnabledSsl(TestInfo testInfo) {
+            assertThat(cluster.runningNodes().count(), is(2L));
+        }
+    }
+
+    @Nested
+    @TestInstance(Lifecycle.PER_CLASS)
+    class ClusterWithSslAndClientAuth {
+
+        @WorkDirectory
+        private Path workDir;
+
+        private Cluster cluster;
+
+        @Language("JSON")
+        String sslEnabledBoostrapConfig = "{\n"
+                + "  network: {\n"
+                + "    ssl : {"
+                + "      enabled: true,\n"
+                + "      clientAuth: \"require\",\n"
+                + "      trustStore: {\n"
+                + "        password: \"" + password + "\","
+                + "        path: \"" + trustStorePath + "\""
+                + "      },\n"
+                + "      keyStore: {\n"
+                + "        password: \"" + password + "\","
+                + "        path: \"" + keyStorePath + "\""
+                + "      }\n"
+                + "    },\n"
+                + "    port: 3365,\n"
+                + "    portRange: 2,\n"
+                + "    nodeFinder:{\n"
+                + "      netClusterNodes: [ \"localhost:3365\", 
\"localhost:3366\" ]\n"
+                + "    }\n"
+                + "  }\n"
+                + "}";
+
+        @BeforeEach
+        void setUp(TestInfo testInfo) {
+            cluster = new Cluster(testInfo, workDir, sslEnabledBoostrapConfig);
+            cluster.startAndInit(2);
+        }
+
+        @AfterEach
+        void tearDown() {
+            cluster.shutdown();
+        }
+
+        @Test
+        @DisplayName("SSL enabled and setup correctly then cluster starts")
+        void clusterStartsWithEnabledSsl(TestInfo testInfo) {
+            assertThat(cluster.runningNodes().count(), is(2L));
+        }
+    }
+}
diff --git a/modules/runner/src/integrationTest/resources/ssl/keystore.p12 
b/modules/runner/src/integrationTest/resources/ssl/keystore.p12
index 1677d2a561..d929618bd6 100644
Binary files a/modules/runner/src/integrationTest/resources/ssl/keystore.p12 
and b/modules/runner/src/integrationTest/resources/ssl/keystore.p12 differ
diff --git a/modules/runner/src/integrationTest/resources/ssl/truststore.jks 
b/modules/runner/src/integrationTest/resources/ssl/truststore.jks
index a20d9db42d..45052de67f 100644
Binary files a/modules/runner/src/integrationTest/resources/ssl/truststore.jks 
and b/modules/runner/src/integrationTest/resources/ssl/truststore.jks differ

Reply via email to