Skip to content

Commit 93a1491

Browse files
committed
Ensure support of the transport-nio by security plugin
Signed-off-by: Andriy Redko <[email protected]>
1 parent 08dc3bb commit 93a1491

File tree

19 files changed

+933
-42
lines changed

19 files changed

+933
-42
lines changed

CHANGELOG.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
77
### Added
88
- Latency and Memory allocation improvements to Multi Term Aggregation queries ([#14993](https://github.com/opensearch-project/OpenSearch/pull/14993))
99
- Add support for restoring from snapshot with search replicas ([#16111](https://github.com/opensearch-project/OpenSearch/pull/16111))
10-
- Add logic in master service to optimize performance and retain detailed logging for critical cluster operations. ([#14795](https://github.com/opensearch-project/OpenSearch/pull/14795))
11-
- Add Setting to adjust the primary constraint weights ([#16471](https://github.com/opensearch-project/OpenSearch/pull/16471))
12-
- Switch from `buildSrc/version.properties` to Gradle version catalog (`gradle/libs.versions.toml`) to enable dependabot to perform automated upgrades on common libs ([#16284](https://github.com/opensearch-project/OpenSearch/pull/16284))
10+
- Ensure support of the transport-nio by security plugin ([#16474](https://github.com/opensearch-project/OpenSearch/pull/16474))
1311

1412
### Dependencies
1513

modules/transport-netty4/src/test/java/org/opensearch/http/netty4/Netty4HttpClient.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,13 +315,11 @@ private static class CountDownLatchHandlerHttp2 extends AwaitableChannelInitiali
315315

316316
private final CountDownLatch latch;
317317
private final Collection<FullHttpResponse> content;
318-
private final boolean secure;
319318
private Http2SettingsHandler settingsHandler;
320319

321320
CountDownLatchHandlerHttp2(final CountDownLatch latch, final Collection<FullHttpResponse> content, final boolean secure) {
322321
this.latch = latch;
323322
this.content = content;
324-
this.secure = secure;
325323
}
326324

327325
@Override

plugins/transport-nio/build.gradle

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ dependencies {
5050
api "io.netty:netty-handler:${versions.netty}"
5151
api "io.netty:netty-resolver:${versions.netty}"
5252
api "io.netty:netty-transport:${versions.netty}"
53+
api "io.netty:netty-transport-native-unix-common:${versions.netty}"
5354
}
5455

5556
tasks.named("dependencyLicenses").configure {
@@ -151,10 +152,6 @@ thirdPartyAudit {
151152
'io.netty.internal.tcnative.SessionTicketKey',
152153
'io.netty.internal.tcnative.SniHostNameMatcher',
153154

154-
// from io.netty.channel.unix (netty)
155-
'io.netty.channel.unix.FileDescriptor',
156-
'io.netty.channel.unix.UnixChannel',
157-
158155
'reactor.blockhound.BlockHound$Builder',
159156
'reactor.blockhound.integration.BlockHoundIntegration'
160157
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
d1171bb99411f282068f49d780cedf8c9adeabfd

plugins/transport-nio/src/internalClusterTest/java/org/opensearch/http/nio/NioPipeliningIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public void testThatNioHttpServerSupportsPipelining() throws Exception {
6161
TransportAddress[] boundAddresses = httpServerTransport.boundAddress().boundAddresses();
6262
TransportAddress transportAddress = randomFrom(boundAddresses);
6363

64-
try (NioHttpClient nettyHttpClient = new NioHttpClient()) {
64+
try (NioHttpClient nettyHttpClient = NioHttpClient.http()) {
6565
Collection<FullHttpResponse> responses = nettyHttpClient.get(transportAddress.address(), requests);
6666
assertThat(responses, hasSize(5));
6767

plugins/transport-nio/src/main/java/org/opensearch/http/nio/HttpReadWriteHandler.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
package org.opensearch.http.nio;
3434

35+
import org.opensearch.common.Nullable;
3536
import org.opensearch.common.unit.TimeValue;
3637
import org.opensearch.http.HttpHandlingSettings;
3738
import org.opensearch.http.HttpPipelinedRequest;
@@ -44,6 +45,8 @@
4445
import org.opensearch.nio.TaskScheduler;
4546
import org.opensearch.nio.WriteOperation;
4647

48+
import javax.net.ssl.SSLEngine;
49+
4750
import java.io.IOException;
4851
import java.util.ArrayList;
4952
import java.util.List;
@@ -58,6 +61,9 @@
5861
import io.netty.handler.codec.http.HttpObjectAggregator;
5962
import io.netty.handler.codec.http.HttpRequestDecoder;
6063
import io.netty.handler.codec.http.HttpResponseEncoder;
64+
import io.netty.handler.logging.LogLevel;
65+
import io.netty.handler.logging.LoggingHandler;
66+
import io.netty.handler.ssl.SslHandler;
6167

6268
public class HttpReadWriteHandler implements NioChannelHandler {
6369

@@ -77,6 +83,17 @@ public HttpReadWriteHandler(
7783
HttpHandlingSettings settings,
7884
TaskScheduler taskScheduler,
7985
LongSupplier nanoClock
86+
) {
87+
this(nioHttpChannel, transport, settings, taskScheduler, nanoClock, null /* no SSL/TLS */);
88+
}
89+
90+
HttpReadWriteHandler(
91+
NioHttpChannel nioHttpChannel,
92+
NioHttpServerTransport transport,
93+
HttpHandlingSettings settings,
94+
TaskScheduler taskScheduler,
95+
LongSupplier nanoClock,
96+
@Nullable SSLEngine sslEngine
8097
) {
8198
this.nioHttpChannel = nioHttpChannel;
8299
this.transport = transport;
@@ -85,6 +102,12 @@ public HttpReadWriteHandler(
85102
this.readTimeoutNanos = TimeUnit.MILLISECONDS.toNanos(settings.getReadTimeoutMillis());
86103

87104
List<ChannelHandler> handlers = new ArrayList<>(8);
105+
106+
SslHandler sslHandler = null;
107+
if (sslEngine != null) {
108+
sslHandler = new SslHandler(sslEngine);
109+
}
110+
88111
HttpRequestDecoder decoder = new HttpRequestDecoder(
89112
settings.getMaxInitialLineLength(),
90113
settings.getMaxHeaderSize(),
@@ -101,8 +124,9 @@ public HttpReadWriteHandler(
101124
handlers.add(new NioHttpRequestCreator());
102125
handlers.add(new NioHttpResponseCreator());
103126
handlers.add(new NioHttpPipeliningHandler(transport.getLogger(), settings.getPipeliningMaxEvents()));
127+
handlers.add(new LoggingHandler(LogLevel.DEBUG));
104128

105-
adaptor = new NettyAdaptor(handlers.toArray(new ChannelHandler[0]));
129+
adaptor = new NettyAdaptor(sslHandler, handlers.toArray(new ChannelHandler[0]));
106130
adaptor.addCloseListener((v, e) -> nioHttpChannel.close());
107131
}
108132

plugins/transport-nio/src/main/java/org/opensearch/http/nio/NettyAdaptor.java

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,21 @@
4949
import io.netty.channel.ChannelOutboundHandlerAdapter;
5050
import io.netty.channel.ChannelPromise;
5151
import io.netty.channel.embedded.EmbeddedChannel;
52+
import io.netty.handler.ssl.SslHandler;
5253

5354
class NettyAdaptor {
5455

5556
private final EmbeddedChannel nettyChannel;
5657
private final LinkedList<FlushOperation> flushOperations = new LinkedList<>();
5758

5859
NettyAdaptor(ChannelHandler... handlers) {
59-
nettyChannel = new EmbeddedChannel();
60-
nettyChannel.pipeline().addLast("write_captor", new ChannelOutboundHandlerAdapter() {
60+
this(null, handlers);
61+
}
6162

63+
NettyAdaptor(SslHandler sslHandler, ChannelHandler... handlers) {
64+
this.nettyChannel = new EmbeddedChannel();
65+
66+
nettyChannel.pipeline().addLast("write_captor", new ChannelOutboundHandlerAdapter() {
6267
@Override
6368
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
6469
// This is a little tricky. The embedded channel will complete the promise once it writes the message
@@ -75,19 +80,32 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)
7580
}
7681
}
7782
});
83+
if (sslHandler != null) {
84+
nettyChannel.pipeline().addAfter("write_captor", "ssl_handler", sslHandler);
85+
}
7886
nettyChannel.pipeline().addLast(handlers);
7987
}
8088

8189
public void close() throws Exception {
8290
assert flushOperations.isEmpty() : "Should close outbound operations before calling close";
8391

8492
ChannelFuture closeFuture = nettyChannel.close();
85-
// This should be safe as we are not a real network channel
86-
closeFuture.await();
87-
if (closeFuture.isSuccess() == false) {
88-
Throwable cause = closeFuture.cause();
89-
ExceptionsHelper.maybeDieOnAnotherThread(cause);
90-
throw (Exception) cause;
93+
if (nettyChannel.pipeline().get("ssl_handler") != null) {
94+
closeFuture.addListener(f -> {
95+
if (f.isSuccess() == false) {
96+
Throwable cause = closeFuture.cause();
97+
ExceptionsHelper.maybeDieOnAnotherThread(cause);
98+
throw (Exception) cause;
99+
}
100+
});
101+
} else {
102+
// This should be safe as we are not a real network channel
103+
closeFuture.await();
104+
if (closeFuture.isSuccess() == false) {
105+
Throwable cause = closeFuture.cause();
106+
ExceptionsHelper.maybeDieOnAnotherThread(cause);
107+
throw (Exception) cause;
108+
}
91109
}
92110
}
93111

plugins/transport-nio/src/main/java/org/opensearch/http/nio/NioHttpServerTransport.java

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.apache.logging.log4j.Logger;
3737
import org.opensearch.OpenSearchException;
3838
import org.opensearch.action.support.PlainActionFuture;
39+
import org.opensearch.common.Nullable;
3940
import org.opensearch.common.network.NetworkService;
4041
import org.opensearch.common.settings.ClusterSettings;
4142
import org.opensearch.common.settings.Settings;
@@ -47,6 +48,7 @@
4748
import org.opensearch.http.AbstractHttpServerTransport;
4849
import org.opensearch.http.HttpChannel;
4950
import org.opensearch.http.HttpServerChannel;
51+
import org.opensearch.http.nio.ssl.SslUtils;
5052
import org.opensearch.nio.BytesChannelContext;
5153
import org.opensearch.nio.ChannelFactory;
5254
import org.opensearch.nio.Config;
@@ -56,11 +58,15 @@
5658
import org.opensearch.nio.NioSocketChannel;
5759
import org.opensearch.nio.ServerChannelContext;
5860
import org.opensearch.nio.SocketChannelContext;
61+
import org.opensearch.plugins.SecureHttpTransportSettingsProvider;
5962
import org.opensearch.telemetry.tracing.Tracer;
6063
import org.opensearch.threadpool.ThreadPool;
6164
import org.opensearch.transport.nio.NioGroupFactory;
6265
import org.opensearch.transport.nio.PageAllocator;
6366

67+
import javax.net.ssl.SSLEngine;
68+
import javax.net.ssl.SSLException;
69+
6470
import java.io.IOException;
6571
import java.net.InetSocketAddress;
6672
import java.nio.channels.ServerSocketChannel;
@@ -97,6 +103,7 @@ public class NioHttpServerTransport extends AbstractHttpServerTransport {
97103

98104
private volatile NioGroup nioGroup;
99105
private ChannelFactory<NioHttpServerChannel, NioHttpChannel> channelFactory;
106+
private final SecureHttpTransportSettingsProvider secureHttpTransportSettingsProvider;
100107

101108
public NioHttpServerTransport(
102109
Settings settings,
@@ -109,6 +116,34 @@ public NioHttpServerTransport(
109116
NioGroupFactory nioGroupFactory,
110117
ClusterSettings clusterSettings,
111118
Tracer tracer
119+
) {
120+
this(
121+
settings,
122+
networkService,
123+
bigArrays,
124+
pageCacheRecycler,
125+
threadPool,
126+
xContentRegistry,
127+
dispatcher,
128+
nioGroupFactory,
129+
clusterSettings,
130+
null,
131+
tracer
132+
);
133+
}
134+
135+
public NioHttpServerTransport(
136+
Settings settings,
137+
NetworkService networkService,
138+
BigArrays bigArrays,
139+
PageCacheRecycler pageCacheRecycler,
140+
ThreadPool threadPool,
141+
NamedXContentRegistry xContentRegistry,
142+
Dispatcher dispatcher,
143+
NioGroupFactory nioGroupFactory,
144+
ClusterSettings clusterSettings,
145+
@Nullable SecureHttpTransportSettingsProvider secureHttpTransportSettingsProvider,
146+
Tracer tracer
112147
) {
113148
super(settings, networkService, bigArrays, threadPool, xContentRegistry, dispatcher, clusterSettings, tracer);
114149
this.pageAllocator = new PageAllocator(pageCacheRecycler);
@@ -127,6 +162,7 @@ public NioHttpServerTransport(
127162
this.reuseAddress = SETTING_HTTP_TCP_REUSE_ADDRESS.get(settings);
128163
this.tcpSendBufferSize = Math.toIntExact(SETTING_HTTP_TCP_SEND_BUFFER_SIZE.get(settings).getBytes());
129164
this.tcpReceiveBufferSize = Math.toIntExact(SETTING_HTTP_TCP_RECEIVE_BUFFER_SIZE.get(settings).getBytes());
165+
this.secureHttpTransportSettingsProvider = secureHttpTransportSettingsProvider;
130166

131167
logger.debug(
132168
"using max_chunk_size[{}], max_header_size[{}], max_initial_line_length[{}], max_content_length[{}],"
@@ -178,17 +214,18 @@ protected HttpServerChannel bind(InetSocketAddress socketAddress) throws IOExcep
178214
return httpServerChannel;
179215
}
180216

181-
protected ChannelFactory<NioHttpServerChannel, NioHttpChannel> channelFactory() {
182-
return new HttpChannelFactory();
217+
protected ChannelFactory<NioHttpServerChannel, NioHttpChannel> channelFactory() throws SSLException {
218+
return new HttpChannelFactory(secureHttpTransportSettingsProvider);
183219
}
184220

185221
protected void acceptChannel(NioSocketChannel socketChannel) {
186222
super.serverAcceptedChannel((HttpChannel) socketChannel);
187223
}
188224

189225
private class HttpChannelFactory extends ChannelFactory<NioHttpServerChannel, NioHttpChannel> {
226+
private final SecureHttpTransportSettingsProvider secureHttpTransportSettingsProvider;
190227

191-
private HttpChannelFactory() {
228+
private HttpChannelFactory(@Nullable SecureHttpTransportSettingsProvider secureHttpTransportSettingsProvider) {
192229
super(
193230
tcpNoDelay,
194231
tcpKeepAlive,
@@ -199,17 +236,25 @@ private HttpChannelFactory() {
199236
tcpSendBufferSize,
200237
tcpReceiveBufferSize
201238
);
239+
this.secureHttpTransportSettingsProvider = secureHttpTransportSettingsProvider;
202240
}
203241

204242
@Override
205-
public NioHttpChannel createChannel(NioSelector selector, SocketChannel channel, Config.Socket socketConfig) {
243+
public NioHttpChannel createChannel(NioSelector selector, SocketChannel channel, Config.Socket socketConfig) throws IOException {
244+
SSLEngine engine = null;
245+
if (secureHttpTransportSettingsProvider != null) {
246+
engine = secureHttpTransportSettingsProvider.buildSecureHttpServerEngine(settings, NioHttpServerTransport.this)
247+
.orElseGet(SslUtils::createDefaultServerSSLEngine);
248+
}
249+
206250
NioHttpChannel httpChannel = new NioHttpChannel(channel);
207251
HttpReadWriteHandler handler = new HttpReadWriteHandler(
208252
httpChannel,
209253
NioHttpServerTransport.this,
210254
handlingSettings,
211255
selector.getTaskScheduler(),
212-
threadPool::relativeTimeInMillis
256+
threadPool::relativeTimeInMillis,
257+
engine
213258
);
214259
Consumer<Exception> exceptionHandler = (e) -> onException(httpChannel, e);
215260
SocketChannelContext context = new BytesChannelContext(
@@ -244,6 +289,5 @@ public NioHttpServerChannel createServerChannel(
244289
httpServerChannel.setContext(context);
245290
return httpServerChannel;
246291
}
247-
248292
}
249293
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* The OpenSearch Contributors require contributions made to
5+
* this file be licensed under the Apache-2.0 license or a
6+
* compatible open source license.
7+
*
8+
* Modifications Copyright OpenSearch Contributors. See
9+
* GitHub history for details.
10+
*/
11+
package org.opensearch.http.nio.ssl;
12+
13+
import org.opensearch.OpenSearchSecurityException;
14+
15+
import javax.net.ssl.SSLContext;
16+
import javax.net.ssl.SSLEngine;
17+
18+
import java.security.NoSuchAlgorithmException;
19+
20+
public class SslUtils {
21+
private static final String[] DEFAULT_SSL_PROTOCOLS = { "TLSv1.3", "TLSv1.2", "TLSv1.1" };
22+
23+
private SslUtils() {
24+
25+
}
26+
27+
public static SSLEngine createDefaultServerSSLEngine() {
28+
try {
29+
final SSLEngine engine = SSLContext.getDefault().createSSLEngine();
30+
engine.setEnabledProtocols(DEFAULT_SSL_PROTOCOLS);
31+
engine.setUseClientMode(false);
32+
return engine;
33+
} catch (final NoSuchAlgorithmException ex) {
34+
throw new OpenSearchSecurityException("Unable to initialize default server SSL engine", ex);
35+
}
36+
}
37+
38+
public static SSLEngine createDefaultClientSSLEngine() {
39+
try {
40+
final SSLEngine engine = SSLContext.getDefault().createSSLEngine();
41+
engine.setEnabledProtocols(DEFAULT_SSL_PROTOCOLS);
42+
engine.setUseClientMode(true);
43+
return engine;
44+
} catch (final NoSuchAlgorithmException ex) {
45+
throw new OpenSearchSecurityException("Unable to initialize default client SSL engine", ex);
46+
}
47+
}
48+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* The OpenSearch Contributors require contributions made to
5+
* this file be licensed under the Apache-2.0 license or a
6+
* compatible open source license.
7+
*/
8+
9+
/**
10+
* SSL supporting utility classes
11+
*/
12+
package org.opensearch.http.nio.ssl;

0 commit comments

Comments
 (0)