Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
9cd6945
Add addServerConfig() to Netty4GrpcServerTransport to support TLS set…
finnegancarroll Jan 21, 2025
91c7836
Add SecureAuxTransportSettingsProvider to enable TLS for aux transports.
finnegancarroll Jan 21, 2025
60f5bc8
Add SecureNetty4GrpcServerTransport.
finnegancarroll Jan 21, 2025
dfe4f1a
Spotless apply
finnegancarroll Jan 21, 2025
5367f74
Register secure aux transports with Node.java.
finnegancarroll Jan 22, 2025
55613d6
Add SecureNetty4GrpcServerTransport.SETTING_GRPC_PORT to plugin setti…
finnegancarroll Jan 23, 2025
e248b23
Add keys/certs for secure gRPC transport test suite.
finnegancarroll Feb 3, 2025
51d1645
gRPC testing client.
finnegancarroll Feb 3, 2025
6caba67
Add SecureNetty4GrpcServerTransport unit tests.
finnegancarroll Feb 4, 2025
3fcc437
Add default ALPN settings to SSLContextWrapper.
finnegancarroll Feb 4, 2025
134aea5
Do not build default SSLContext for secure transport. Safer to fail.
finnegancarroll Feb 4, 2025
2a73686
WIP tests.
finnegancarroll Feb 4, 2025
9bfed42
boundAddress() public for testing.
finnegancarroll Feb 4, 2025
f4a0985
Remove proxy detector from gRPC test client.
finnegancarroll Feb 4, 2025
2564828
Netty4GrpcServerTransport health check test.
finnegancarroll Feb 4, 2025
09e489a
Small test naming change.
finnegancarroll Feb 4, 2025
7fd61f3
Add return info to test gRPC client.
finnegancarroll Feb 5, 2025
e63ed48
Remove insecure credentials from Netty4GrpcServerTransport.
finnegancarroll Feb 6, 2025
2a213f1
Refactor gRPC test client to accept SslContext.
finnegancarroll Feb 6, 2025
8e083f3
Refactor SecureAuxTransportSettingsProvider to implement SecureTransp…
finnegancarroll Feb 13, 2025
b57f175
Clean up test cases. Store SslContext in SecureNetty4GrpcServerTransp…
finnegancarroll Feb 13, 2025
d994f2b
Configure Netty server to re-use eventLoopGroup pool for service stubs.
finnegancarroll Feb 13, 2025
768ad81
Remove redundant settings from SecureNetty4GrpcServerTransport.
finnegancarroll Feb 13, 2025
56b32c7
Add initial readme to plugin root.
finnegancarroll Feb 14, 2025
e1268ea
Remove multiple transport type settings in GrpcPlugin. Not necessary.
finnegancarroll Feb 14, 2025
d80ce45
Remove depreacted constructor.
finnegancarroll Feb 14, 2025
8b13e86
Add IT infra to Grpc transport plugin.
finnegancarroll Feb 14, 2025
f933620
Spotless apply
finnegancarroll Feb 14, 2025
c2993be
Add initial cluster health gRPC IT.
finnegancarroll Feb 19, 2025
2bc6c7f
Rename GrpcTransportIT -> Netty4GrpcServerTransportIT.
finnegancarroll Feb 20, 2025
1619c3c
Move boundAddress() helper up to AuxTransport. Add helper in ITs to f…
finnegancarroll Feb 20, 2025
25e6e60
Spotless apply
finnegancarroll Feb 20, 2025
90b08bc
Changelog.
finnegancarroll Mar 25, 2025
fa1aa41
Javadocs for SecureTransportParameters.
finnegancarroll Feb 20, 2025
e4d1052
Fix minor naming conflict after rebase with flight server pr. boundAd…
finnegancarroll Feb 20, 2025
1b7e2fb
Javadocs for org.opensearch.transport.grpc.ssl + Netty4GrpcServerTran…
finnegancarroll Feb 21, 2025
0379d2f
Update SecureTransportParameters interface to match remote.
finnegancarroll Feb 24, 2025
093f8cd
Refactor SecureAuxTransportSettingsProvider to return a single builder.
finnegancarroll Feb 25, 2025
453c8b9
Remove redundant public.
finnegancarroll Feb 25, 2025
8ab0106
Comments
finnegancarroll Feb 25, 2025
aeebb88
Refactor SecureNetty4GrpcServerTransport to build and consume Reloada…
finnegancarroll Feb 25, 2025
025f36c
Fix test setting provider ALPN failure. Simplify with SslContextBuild…
finnegancarroll Feb 25, 2025
86f71dd
Spotless apply
finnegancarroll Feb 25, 2025
953b35f
Move integ tests to internalClusterTest so gradle can find these task…
finnegancarroll Feb 26, 2025
1af17e2
Update readme.
finnegancarroll Feb 26, 2025
b8dc25a
Formatting.
finnegancarroll Feb 26, 2025
cc65ce4
Provide default pooled allocator to newEngine in tests.
finnegancarroll Feb 26, 2025
f9cccfb
Add list services UT.
finnegancarroll Feb 26, 2025
9d3ea91
Spotless apply
finnegancarroll Feb 26, 2025
389e457
Add distinct setting keys for secure grpc transport: GRPC_SECURE_TRAN…
finnegancarroll Mar 17, 2025
a95be1c
Update readme. Add secure transport. Add remaining grpc settings.
finnegancarroll Mar 17, 2025
a7a3aa0
Javadocs for grpc port/portSettingKey.
finnegancarroll Mar 17, 2025
c1fe37b
Fix readme typos.
finnegancarroll Mar 17, 2025
42f844a
Refactor ReloadableSecureAuxTransportSslContext.
finnegancarroll Mar 20, 2025
2b05d1d
Javadocs clientAuthHelper & providerHelper.
finnegancarroll Mar 21, 2025
deb60fb
Remove code related to reloading certs. Remove dual mode.
finnegancarroll Mar 21, 2025
9a39b62
Spotless apply
finnegancarroll Mar 21, 2025
f6777db
Remove :libs:opensearch-core. Redundant with :test:framework.
finnegancarroll Mar 24, 2025
b8513fe
Chosen keystore/truststore not provided by OpenJDK
finnegancarroll Mar 24, 2025
6ce43c7
Update an add ssl test resources
finnegancarroll Mar 26, 2025
630861d
Move keystore/truststore builders to helper.
finnegancarroll Mar 26, 2025
ca7d08e
Move SecureAuxTransportSslContext to server only.
finnegancarroll Mar 26, 2025
0815c99
Abstract secure server ITs.
finnegancarroll Mar 26, 2025
8cbfd0b
Create IT for all client auth cases.
finnegancarroll Mar 26, 2025
322be46
Catch missing security params - Add more detailed error messages.
finnegancarroll Apr 2, 2025
d73a08d
Move portSettingKey init to constructor.
finnegancarroll Apr 2, 2025
9935be7
Clean up NettyGrpcClient shutdown.
finnegancarroll Apr 2, 2025
522b1de
Swap NettyGrpcClient listService from latch to future.
finnegancarroll Apr 2, 2025
e6b033b
NettyGrpcClient rename mTLS -> clientAuth.
finnegancarroll Apr 2, 2025
cd2fc69
Spotless apply
finnegancarroll Apr 2, 2025
bdaf3fe
Fix failure exception message assertion - Changed due to bc ssl provi…
finnegancarroll Apr 2, 2025
13ec303
Remove lingering certs - Redundant with keystores.
finnegancarroll Apr 3, 2025
caa6605
Force JDK ssl provider test client.
finnegancarroll Apr 3, 2025
2309786
Set ssl provider JDK for insecure grpc test client.
finnegancarroll Apr 4, 2025
ebe3557
Fix ssl failure test assertion accounting for different default jdk p…
finnegancarroll Apr 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Add ingestion management APIs for pause, resume and get ingestion state ([#17631](https://github.com/opensearch-project/OpenSearch/pull/17631))
- [Security Manager Replacement] Enhance Java Agent to intercept System::exit ([#17746](https://github.com/opensearch-project/OpenSearch/pull/17746))
- Support AutoExpand for SearchReplica ([#17741](https://github.com/opensearch-project/OpenSearch/pull/17741))
- Add TLS enabled SecureNetty4GrpcServerTransport ([#17406](https://github.com/opensearch-project/OpenSearch/pull/17406))

### Changed
- Migrate BC libs to their FIPS counterparts ([#14912](https://github.com/opensearch-project/OpenSearch/pull/14912))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ public StreamManager getStreamManager() {
* Retrieves the bound address of the FlightService.
* @return The BoundTransportAddress instance.
*/
@Override
public BoundTransportAddress getBoundAddress() {
return serverComponents.getBoundAddress();
}
Expand Down
42 changes: 42 additions & 0 deletions plugins/transport-grpc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# transport-grpc

An auxiliary transport which runs in parallel to the REST API.
The `transport-grpc` plugin initializes a new client/server transport implementing a gRPC protocol on Netty4.

Enable this transport with:

```
setting 'aux.transport.types', '[experimental-transport-grpc]'
setting 'aux.transport.experimental-transport-grpc.port', '9400-9500' //optional
```

For the secure transport:

```
setting 'aux.transport.types', '[experimental-secure-transport-grpc]'
setting 'aux.transport.experimental-secure-transport-grpc.port', '9400-9500' //optional
```

Other settings are agnostic as to the gRPC transport type:

```
setting 'grpc.publish_port', '9400'
setting 'grpc.host', '["0.0.0.0"]'
setting 'grpc.bind_host', '["0.0.0.0", "::", "10.0.0.1"]'
setting 'grpc.publish_host', '["thisnode.example.com"]'
setting 'grpc.netty.worker_count', '2'
```

## Testing

### Unit Tests

```
./gradlew :plugins:transport-grpc:test
```

### Integration Tests

```
./gradlew :plugins:transport-grpc:internalClusterTest
```
13 changes: 11 additions & 2 deletions plugins/transport-grpc/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import org.gradle.api.attributes.java.TargetJvmEnvironment

/*
* SPDX-License-Identifier: Apache-2.0
*
Expand All @@ -8,11 +6,21 @@ import org.gradle.api.attributes.java.TargetJvmEnvironment
* compatible open source license.
*/

apply plugin: 'opensearch.testclusters'
apply plugin: 'opensearch.internal-cluster-test'

opensearchplugin {
description = 'gRPC based transport implementation'
classname = 'org.opensearch.transport.grpc.GrpcPlugin'
}

testClusters {
integTest {
plugin(project.path)
setting 'aux.transport.types', '[experimental-transport-grpc]'
}
}

dependencies {
compileOnly "com.google.code.findbugs:jsr305:3.0.2"
runtimeOnly "com.google.guava:guava:${versions.guava}"
Expand All @@ -27,6 +35,7 @@ dependencies {
implementation "io.grpc:grpc-stub:${versions.grpc}"
implementation "io.grpc:grpc-util:${versions.grpc}"
implementation "io.perfmark:perfmark-api:0.26.0"
testImplementation project(':test:framework')
}

tasks.named("dependencyLicenses").configure {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* 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.
*/

package org.opensearch.transport.grpc;

import org.opensearch.action.admin.cluster.health.ClusterHealthResponse;
import org.opensearch.cluster.health.ClusterHealthStatus;
import org.opensearch.common.settings.Settings;
import org.opensearch.core.common.transport.TransportAddress;
import org.opensearch.plugins.Plugin;
import org.opensearch.test.OpenSearchIntegTestCase;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import io.grpc.health.v1.HealthCheckResponse;

import static org.opensearch.plugins.NetworkPlugin.AuxTransport.AUX_TRANSPORT_TYPES_KEY;
import static org.opensearch.transport.grpc.Netty4GrpcServerTransport.GRPC_TRANSPORT_SETTING_KEY;

public class Netty4GrpcServerTransportIT extends OpenSearchIntegTestCase {

private TransportAddress randomNetty4GrpcServerTransportAddr() {
List<TransportAddress> addresses = new ArrayList<>();
for (Netty4GrpcServerTransport transport : internalCluster().getInstances(Netty4GrpcServerTransport.class)) {
TransportAddress tAddr = new TransportAddress(transport.getBoundAddress().publishAddress().address());
addresses.add(tAddr);
}
return randomFrom(addresses);
}

@Override
protected Settings nodeSettings(int nodeOrdinal) {
return Settings.builder().put(super.nodeSettings(nodeOrdinal)).put(AUX_TRANSPORT_TYPES_KEY, GRPC_TRANSPORT_SETTING_KEY).build();
}

@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Collections.singleton(GrpcPlugin.class);
}

public void testStartGrpcTransportClusterHealth() throws Exception {
// REST api cluster health
ClusterHealthResponse healthResponse = client().admin().cluster().prepareHealth().get();
assertEquals(ClusterHealthStatus.GREEN, healthResponse.getStatus());

// gRPC transport service health
try (NettyGrpcClient client = new NettyGrpcClient.Builder().setAddress(randomNetty4GrpcServerTransportAddr()).build()) {
assertEquals(client.checkHealth(), HealthCheckResponse.ServingStatus.SERVING);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
/*
* 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.
*/

package org.opensearch.transport.grpc;

import org.opensearch.action.admin.cluster.health.ClusterHealthResponse;
import org.opensearch.cluster.health.ClusterHealthStatus;
import org.opensearch.common.settings.Settings;
import org.opensearch.core.common.transport.TransportAddress;
import org.opensearch.plugins.NetworkPlugin;
import org.opensearch.plugins.Plugin;
import org.opensearch.plugins.SecureAuxTransportSettingsProvider;
import org.opensearch.plugins.SecureHttpTransportSettingsProvider;
import org.opensearch.plugins.SecureSettingsFactory;
import org.opensearch.plugins.SecureTransportSettingsProvider;
import org.opensearch.test.OpenSearchIntegTestCase;
import org.opensearch.transport.grpc.ssl.SecureNetty4GrpcServerTransport;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;

import io.grpc.health.v1.HealthCheckResponse;

import static org.opensearch.plugins.NetworkPlugin.AuxTransport.AUX_TRANSPORT_TYPES_KEY;
import static org.opensearch.transport.grpc.SecureSettingsHelpers.getServerClientAuthNone;
import static org.opensearch.transport.grpc.SecureSettingsHelpers.getServerClientAuthOptional;
import static org.opensearch.transport.grpc.SecureSettingsHelpers.getServerClientAuthRequired;
import static org.opensearch.transport.grpc.ssl.SecureNetty4GrpcServerTransport.GRPC_SECURE_TRANSPORT_SETTING_KEY;

public abstract class SecureNetty4GrpcServerTransportIT extends OpenSearchIntegTestCase {

public static class MockSecurityPlugin extends Plugin implements NetworkPlugin {
public MockSecurityPlugin() {}

static class MockSecureSettingsFactory implements SecureSettingsFactory {
@Override
public Optional<SecureTransportSettingsProvider> getSecureTransportSettingsProvider(Settings settings) {
return Optional.empty();
}

@Override
public Optional<SecureHttpTransportSettingsProvider> getSecureHttpTransportSettingsProvider(Settings settings) {
return Optional.empty();
}

@Override
public Optional<SecureAuxTransportSettingsProvider> getSecureAuxTransportSettingsProvider(Settings settings) {
return Optional.empty();
}
}
}

protected TransportAddress randomNetty4GrpcServerTransportAddr() {
List<TransportAddress> addresses = new ArrayList<>();
for (SecureNetty4GrpcServerTransport transport : internalCluster().getInstances(SecureNetty4GrpcServerTransport.class)) {
TransportAddress tAddr = new TransportAddress(transport.getBoundAddress().publishAddress().address());
addresses.add(tAddr);
}
return randomFrom(addresses);
}

@Override
protected Settings nodeSettings(int nodeOrdinal) {
return Settings.builder()
.put(super.nodeSettings(nodeOrdinal))
.put(AUX_TRANSPORT_TYPES_KEY, GRPC_SECURE_TRANSPORT_SETTING_KEY)
.build();
}

@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return List.of(GrpcPlugin.class, MockSecurityPlugin.class);
}

private SecureSettingsHelpers.ConnectExceptions tryConnectClient(NettyGrpcClient client) {
try {
HealthCheckResponse.ServingStatus status = client.checkHealth();
if (status == HealthCheckResponse.ServingStatus.SERVING) {
return SecureSettingsHelpers.ConnectExceptions.NONE;
} else {
throw new RuntimeException("Illegal state - unexpected server status: " + status.toString());
}
} catch (Exception e) {
return SecureSettingsHelpers.ConnectExceptions.get(e);
}
}

protected SecureSettingsHelpers.ConnectExceptions plaintextClientConnect() throws Exception {
try (NettyGrpcClient client = new NettyGrpcClient.Builder().setAddress(randomNetty4GrpcServerTransportAddr()).build()) {
return tryConnectClient(client);
}
}

protected SecureSettingsHelpers.ConnectExceptions insecureClientConnect() throws Exception {
try (
NettyGrpcClient client = new NettyGrpcClient.Builder().setAddress(randomNetty4GrpcServerTransportAddr()).insecure(true).build()
) {
return tryConnectClient(client);
}
}

protected SecureSettingsHelpers.ConnectExceptions trustedCertClientConnect() throws Exception {
try (
NettyGrpcClient client = new NettyGrpcClient.Builder().setAddress(randomNetty4GrpcServerTransportAddr())
.clientAuth(true)
.build()
) {
return tryConnectClient(client);
}
}

public void testClusterHealth() {
ClusterHealthResponse healthResponse = client().admin().cluster().prepareHealth().get();
assertEquals(ClusterHealthStatus.GREEN, healthResponse.getStatus());
}

public static class SecureNetty4GrpcServerTransportNoAuthIT extends SecureNetty4GrpcServerTransportIT {
public static class NoAuthMockSecurityPlugin extends MockSecurityPlugin {
public NoAuthMockSecurityPlugin() {}

@Override
public Optional<SecureSettingsFactory> getSecureSettingFactory(Settings settings) {
return Optional.of(new MockSecureSettingsFactory() {
@Override
public Optional<SecureAuxTransportSettingsProvider> getSecureAuxTransportSettingsProvider(Settings settings) {
return Optional.of(getServerClientAuthNone());
}
});
}
}

@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return List.of(GrpcPlugin.class, NoAuthMockSecurityPlugin.class);
}

public void testPlaintextClientConnect() throws Exception {
assertEquals(plaintextClientConnect(), SecureSettingsHelpers.ConnectExceptions.UNAVAILABLE);
}

public void testInsecureClientConnect() throws Exception {
assertEquals(insecureClientConnect(), SecureSettingsHelpers.ConnectExceptions.NONE);
}

public void testTrustedClientConnect() throws Exception {
assertEquals(trustedCertClientConnect(), SecureSettingsHelpers.ConnectExceptions.NONE);
}
}

public static class SecureNetty4GrpcServerTransportOptionalAuthIT extends SecureNetty4GrpcServerTransportIT {
public static class OptAuthMockSecurityPlugin extends MockSecurityPlugin {
public OptAuthMockSecurityPlugin() {}

@Override
public Optional<SecureSettingsFactory> getSecureSettingFactory(Settings settings) {
return Optional.of(new MockSecureSettingsFactory() {
@Override
public Optional<SecureAuxTransportSettingsProvider> getSecureAuxTransportSettingsProvider(Settings settings) {
return Optional.of(getServerClientAuthOptional());
}
});
}
}

@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return List.of(GrpcPlugin.class, OptAuthMockSecurityPlugin.class);
}

public void testPlaintextClientConnect() throws Exception {
assertEquals(plaintextClientConnect(), SecureSettingsHelpers.ConnectExceptions.UNAVAILABLE);
}

public void testInsecureClientConnect() throws Exception {
assertEquals(insecureClientConnect(), SecureSettingsHelpers.ConnectExceptions.NONE);
}

public void testTrustedClientConnect() throws Exception {
assertEquals(trustedCertClientConnect(), SecureSettingsHelpers.ConnectExceptions.NONE);
}
}

public static class SecureNetty4GrpcServerTransportRequiredAuthIT extends SecureNetty4GrpcServerTransportIT {
public static class RequireAuthMockSecurityPlugin extends MockSecurityPlugin {
public RequireAuthMockSecurityPlugin() {}

@Override
public Optional<SecureSettingsFactory> getSecureSettingFactory(Settings settings) {
return Optional.of(new MockSecureSettingsFactory() {
@Override
public Optional<SecureAuxTransportSettingsProvider> getSecureAuxTransportSettingsProvider(Settings settings) {
return Optional.of(getServerClientAuthRequired());
}
});
}
}

@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return List.of(GrpcPlugin.class, RequireAuthMockSecurityPlugin.class);
}

public void testPlaintextClientConnect() throws Exception {
assertEquals(plaintextClientConnect(), SecureSettingsHelpers.ConnectExceptions.UNAVAILABLE);
}

public void testInsecureClientConnect() throws Exception {
assertEquals(insecureClientConnect(), SecureSettingsHelpers.ConnectExceptions.BAD_CERT);
}

public void testTrustedClientConnect() throws Exception {
assertEquals(trustedCertClientConnect(), SecureSettingsHelpers.ConnectExceptions.NONE);
}
}
}
Loading
Loading