diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3cfdcd86f6bf0..0b5a7cc705a79 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -119,6 +119,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- [Tiered caching] Add serializer integration to allow ehcache disk cache to use non-primitive values ([#12709](https://github.com/opensearch-project/OpenSearch/pull/12709))
- [Admission Control] Integrated IO Based AdmissionController to AdmissionControl Framework ([#12583](https://github.com/opensearch-project/OpenSearch/pull/12583))
- Introduce a new setting `index.check_pending_flush.enabled` to expose the ability to disable the check for pending flushes by write threads ([#12710](https://github.com/opensearch-project/OpenSearch/pull/12710))
+- Built-in secure transports support ([#12435](https://github.com/opensearch-project/OpenSearch/pull/12435))
### Dependencies
- Bump `peter-evans/find-comment` from 2 to 3 ([#12288](https://github.com/opensearch-project/OpenSearch/pull/12288))
diff --git a/modules/transport-netty4/src/main/java/org/opensearch/http/netty4/ssl/SecureNetty4HttpServerTransport.java b/modules/transport-netty4/src/main/java/org/opensearch/http/netty4/ssl/SecureNetty4HttpServerTransport.java
new file mode 100644
index 0000000000000..51a76903e284d
--- /dev/null
+++ b/modules/transport-netty4/src/main/java/org/opensearch/http/netty4/ssl/SecureNetty4HttpServerTransport.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2015-2017 floragunn GmbH
+ *
+ * Licensed 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.
+ *
+ */
+
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ *
+ * Modifications Copyright OpenSearch Contributors. See
+ * GitHub history for details.
+ */
+
+package org.opensearch.http.netty4.ssl;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.opensearch.common.network.NetworkService;
+import org.opensearch.common.settings.ClusterSettings;
+import org.opensearch.common.settings.Settings;
+import org.opensearch.common.util.BigArrays;
+import org.opensearch.core.xcontent.NamedXContentRegistry;
+import org.opensearch.http.HttpChannel;
+import org.opensearch.http.HttpHandlingSettings;
+import org.opensearch.http.netty4.Netty4HttpChannel;
+import org.opensearch.http.netty4.Netty4HttpServerTransport;
+import org.opensearch.plugins.SecureTransportSettingsProvider;
+import org.opensearch.telemetry.tracing.Tracer;
+import org.opensearch.threadpool.ThreadPool;
+import org.opensearch.transport.SharedGroupFactory;
+import org.opensearch.transport.netty4.ssl.SslUtils;
+
+import javax.net.ssl.SSLEngine;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.DecoderException;
+import io.netty.handler.ssl.ApplicationProtocolNames;
+import io.netty.handler.ssl.ApplicationProtocolNegotiationHandler;
+import io.netty.handler.ssl.SslHandler;
+
+/**
+ * @see SecuritySSLNettyHttpServerTransport
+ */
+public class SecureNetty4HttpServerTransport extends Netty4HttpServerTransport {
+ private static final Logger logger = LogManager.getLogger(SecureNetty4HttpServerTransport.class);
+ private final SecureTransportSettingsProvider secureTransportSettingsProvider;
+ private final SecureTransportSettingsProvider.ServerExceptionHandler exceptionHandler;
+
+ public SecureNetty4HttpServerTransport(
+ final Settings settings,
+ final NetworkService networkService,
+ final BigArrays bigArrays,
+ final ThreadPool threadPool,
+ final NamedXContentRegistry namedXContentRegistry,
+ final Dispatcher dispatcher,
+ final ClusterSettings clusterSettings,
+ final SharedGroupFactory sharedGroupFactory,
+ final SecureTransportSettingsProvider secureTransportSettingsProvider,
+ final Tracer tracer
+ ) {
+ super(
+ settings,
+ networkService,
+ bigArrays,
+ threadPool,
+ namedXContentRegistry,
+ dispatcher,
+ clusterSettings,
+ sharedGroupFactory,
+ tracer
+ );
+ this.secureTransportSettingsProvider = secureTransportSettingsProvider;
+ this.exceptionHandler = secureTransportSettingsProvider.buildHttpServerExceptionHandler(settings, this)
+ .orElse(SecureTransportSettingsProvider.ServerExceptionHandler.NOOP);
+ }
+
+ @Override
+ public ChannelHandler configureServerChannelHandler() {
+ return new SslHttpChannelHandler(this, handlingSettings);
+ }
+
+ @Override
+ public void onException(HttpChannel channel, Exception cause0) {
+ Throwable cause = cause0;
+
+ if (cause0 instanceof DecoderException && cause0 != null) {
+ cause = cause0.getCause();
+ }
+
+ exceptionHandler.onError(cause);
+ logger.error("Exception during establishing a SSL connection: " + cause, cause);
+ super.onException(channel, cause0);
+ }
+
+ protected class SslHttpChannelHandler extends Netty4HttpServerTransport.HttpChannelHandler {
+ /**
+ * Application negotiation handler to select either HTTP 1.1 or HTTP 2 protocol, based
+ * on client/server ALPN negotiations.
+ */
+ private class Http2OrHttpHandler extends ApplicationProtocolNegotiationHandler {
+ protected Http2OrHttpHandler() {
+ super(ApplicationProtocolNames.HTTP_1_1);
+ }
+
+ @Override
+ protected void configurePipeline(ChannelHandlerContext ctx, String protocol) throws Exception {
+ if (ApplicationProtocolNames.HTTP_2.equals(protocol)) {
+ configureDefaultHttp2Pipeline(ctx.pipeline());
+ } else if (ApplicationProtocolNames.HTTP_1_1.equals(protocol)) {
+ configureDefaultHttpPipeline(ctx.pipeline());
+ } else {
+ throw new IllegalStateException("Unknown application protocol: " + protocol);
+ }
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+ super.exceptionCaught(ctx, cause);
+ Netty4HttpChannel channel = ctx.channel().attr(HTTP_CHANNEL_KEY).get();
+ if (channel != null) {
+ if (cause instanceof Error) {
+ onException(channel, new Exception(cause));
+ } else {
+ onException(channel, (Exception) cause);
+ }
+ }
+ }
+ }
+
+ protected SslHttpChannelHandler(final Netty4HttpServerTransport transport, final HttpHandlingSettings handlingSettings) {
+ super(transport, handlingSettings);
+ }
+
+ @Override
+ protected void initChannel(Channel ch) throws Exception {
+ super.initChannel(ch);
+
+ final SSLEngine sslEngine = secureTransportSettingsProvider.buildSecureHttpServerEngine(
+ settings,
+ SecureNetty4HttpServerTransport.this
+ ).orElseGet(SslUtils::createDefaultServerSSLEngine);
+
+ final SslHandler sslHandler = new SslHandler(sslEngine);
+ ch.pipeline().addFirst("ssl_http", sslHandler);
+ }
+
+ @Override
+ protected void configurePipeline(Channel ch) {
+ ch.pipeline().addLast(new Http2OrHttpHandler());
+ }
+ }
+}
diff --git a/modules/transport-netty4/src/main/java/org/opensearch/transport/Netty4ModulePlugin.java b/modules/transport-netty4/src/main/java/org/opensearch/transport/Netty4ModulePlugin.java
index 2bc795d11ed5d..56163c18949a4 100644
--- a/modules/transport-netty4/src/main/java/org/opensearch/transport/Netty4ModulePlugin.java
+++ b/modules/transport-netty4/src/main/java/org/opensearch/transport/Netty4ModulePlugin.java
@@ -46,11 +46,14 @@
import org.opensearch.core.xcontent.NamedXContentRegistry;
import org.opensearch.http.HttpServerTransport;
import org.opensearch.http.netty4.Netty4HttpServerTransport;
+import org.opensearch.http.netty4.ssl.SecureNetty4HttpServerTransport;
import org.opensearch.plugins.NetworkPlugin;
import org.opensearch.plugins.Plugin;
+import org.opensearch.plugins.SecureTransportSettingsProvider;
import org.opensearch.telemetry.tracing.Tracer;
import org.opensearch.threadpool.ThreadPool;
import org.opensearch.transport.netty4.Netty4Transport;
+import org.opensearch.transport.netty4.ssl.SecureNetty4Transport;
import java.util.Arrays;
import java.util.Collections;
@@ -61,7 +64,9 @@
public class Netty4ModulePlugin extends Plugin implements NetworkPlugin {
public static final String NETTY_TRANSPORT_NAME = "netty4";
+ public static final String NETTY_SECURE_TRANSPORT_NAME = "netty4-secure";
public static final String NETTY_HTTP_TRANSPORT_NAME = "netty4";
+ public static final String NETTY_SECURE_HTTP_TRANSPORT_NAME = "netty4-secure";
private final SetOnce groupFactory = new SetOnce<>();
@@ -144,6 +149,65 @@ public Map> getHttpTransports(
);
}
+ @Override
+ public Map> getSecureHttpTransports(
+ Settings settings,
+ ThreadPool threadPool,
+ BigArrays bigArrays,
+ PageCacheRecycler pageCacheRecycler,
+ CircuitBreakerService circuitBreakerService,
+ NamedXContentRegistry xContentRegistry,
+ NetworkService networkService,
+ HttpServerTransport.Dispatcher dispatcher,
+ ClusterSettings clusterSettings,
+ SecureTransportSettingsProvider secureTransportSettingsProvider,
+ Tracer tracer
+ ) {
+ return Collections.singletonMap(
+ NETTY_SECURE_HTTP_TRANSPORT_NAME,
+ () -> new SecureNetty4HttpServerTransport(
+ settings,
+ networkService,
+ bigArrays,
+ threadPool,
+ xContentRegistry,
+ dispatcher,
+ clusterSettings,
+ getSharedGroupFactory(settings),
+ secureTransportSettingsProvider,
+ tracer
+ )
+ );
+ }
+
+ @Override
+ public Map> getSecureTransports(
+ Settings settings,
+ ThreadPool threadPool,
+ PageCacheRecycler pageCacheRecycler,
+ CircuitBreakerService circuitBreakerService,
+ NamedWriteableRegistry namedWriteableRegistry,
+ NetworkService networkService,
+ SecureTransportSettingsProvider secureTransportSettingsProvider,
+ Tracer tracer
+ ) {
+ return Collections.singletonMap(
+ NETTY_SECURE_TRANSPORT_NAME,
+ () -> new SecureNetty4Transport(
+ settings,
+ Version.CURRENT,
+ threadPool,
+ networkService,
+ pageCacheRecycler,
+ namedWriteableRegistry,
+ circuitBreakerService,
+ getSharedGroupFactory(settings),
+ secureTransportSettingsProvider,
+ tracer
+ )
+ );
+ }
+
SharedGroupFactory getSharedGroupFactory(Settings settings) {
SharedGroupFactory groupFactory = this.groupFactory.get();
if (groupFactory != null) {
diff --git a/modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/DualModeSslHandler.java b/modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/DualModeSslHandler.java
new file mode 100644
index 0000000000000..1bf4cdb0eb438
--- /dev/null
+++ b/modules/transport-netty4/src/main/java/org/opensearch/transport/netty4/ssl/DualModeSslHandler.java
@@ -0,0 +1,106 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ *
+ * Modifications Copyright OpenSearch Contributors. See
+ * GitHub history for details.
+ */
+package org.opensearch.transport.netty4.ssl;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.opensearch.common.settings.Settings;
+import org.opensearch.plugins.SecureTransportSettingsProvider;
+import org.opensearch.transport.TcpTransport;
+
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLException;
+
+import java.nio.charset.StandardCharsets;
+import java.security.NoSuchAlgorithmException;
+import java.util.List;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelFutureListener;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelPipeline;
+import io.netty.handler.codec.ByteToMessageDecoder;
+import io.netty.handler.ssl.SslHandler;
+
+/**
+ * Modifies the current pipeline dynamically to enable TLS
+ *
+ * @see DualModeSSLHandler
+ */
+public class DualModeSslHandler extends ByteToMessageDecoder {
+
+ private static final Logger logger = LogManager.getLogger(DualModeSslHandler.class);
+ private final Settings settings;
+ private final SecureTransportSettingsProvider secureTransportSettingsProvider;
+ private final TcpTransport transport;
+ private final SslHandler providedSSLHandler;
+
+ public DualModeSslHandler(
+ final Settings settings,
+ final SecureTransportSettingsProvider secureTransportSettingsProvider,
+ final TcpTransport transport
+ ) {
+ this(settings, secureTransportSettingsProvider, transport, null);
+ }
+
+ protected DualModeSslHandler(
+ final Settings settings,
+ final SecureTransportSettingsProvider secureTransportSettingsProvider,
+ final TcpTransport transport,
+ SslHandler providedSSLHandler
+ ) {
+ this.settings = settings;
+ this.secureTransportSettingsProvider = secureTransportSettingsProvider;
+ this.transport = transport;
+ this.providedSSLHandler = providedSSLHandler;
+ }
+
+ @Override
+ protected void decode(ChannelHandlerContext ctx, ByteBuf in, List