From 620d266677a964150416e6cd774201e9d0a34b39 Mon Sep 17 00:00:00 2001 From: sanjaypujare Date: Wed, 18 Nov 2020 12:46:29 -0800 Subject: [PATCH] xds: implement XdsServerCredentials (#7636) Co-authored-by: Eric Anderson --- .../netty/InternalNettyServerCredentials.java | 4 +- .../java/io/grpc/xds/XdsServerBuilder.java | 18 ++++++- .../io/grpc/xds/XdsServerCredentials.java | 45 ++++++++++++++++ .../internal/sds/SdsProtocolNegotiators.java | 22 ++++++++ .../io/grpc/xds/XdsSdsClientServerTest.java | 53 ++++++++----------- 5 files changed, 107 insertions(+), 35 deletions(-) create mode 100644 xds/src/main/java/io/grpc/xds/XdsServerCredentials.java diff --git a/netty/src/main/java/io/grpc/netty/InternalNettyServerCredentials.java b/netty/src/main/java/io/grpc/netty/InternalNettyServerCredentials.java index 16e58d94369..3f56344527f 100644 --- a/netty/src/main/java/io/grpc/netty/InternalNettyServerCredentials.java +++ b/netty/src/main/java/io/grpc/netty/InternalNettyServerCredentials.java @@ -49,9 +49,9 @@ public static ServerCredentials create(InternalProtocolNegotiator.ServerFactory * @throws IllegalArgumentException if unable to convert */ public static InternalProtocolNegotiator.ServerFactory toNegotiator( - ServerCredentials channelCredentials) { + ServerCredentials serverCredentials) { final ProtocolNegotiators.FromServerCredentialsResult result = - ProtocolNegotiators.from(channelCredentials); + ProtocolNegotiators.from(serverCredentials); if (result.error != null) { throw new IllegalArgumentException(result.error); } diff --git a/xds/src/main/java/io/grpc/xds/XdsServerBuilder.java b/xds/src/main/java/io/grpc/xds/XdsServerBuilder.java index e3fb0b3d98e..3876148eb35 100644 --- a/xds/src/main/java/io/grpc/xds/XdsServerBuilder.java +++ b/xds/src/main/java/io/grpc/xds/XdsServerBuilder.java @@ -17,12 +17,14 @@ package io.grpc.xds; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; import io.grpc.Attributes; import io.grpc.ExperimentalApi; import io.grpc.ForwardingServerBuilder; import io.grpc.Internal; import io.grpc.Server; import io.grpc.ServerBuilder; +import io.grpc.ServerCredentials; import io.grpc.Status; import io.grpc.netty.InternalNettyServerBuilder; import io.grpc.netty.InternalProtocolNegotiator.ProtocolNegotiator; @@ -46,12 +48,14 @@ public final class XdsServerBuilder extends ForwardingServerBuilder delegate() { */ @ExperimentalApi("https://github.com/grpc/grpc-java/issues/7514") public XdsServerBuilder useXdsSecurityWithPlaintextFallback() { + Preconditions.checkState(!freezeNegotiator, "Method unavailable when using ServerCredentials"); this.fallbackProtocolNegotiator = InternalProtocolNegotiators.serverPlaintext(); return this; } @@ -80,6 +85,7 @@ public XdsServerBuilder useXdsSecurityWithPlaintextFallback() { @ExperimentalApi("https://github.com/grpc/grpc-java/issues/7514") public XdsServerBuilder useXdsSecurityWithTransportSecurityFallback( File certChain, File privateKey) throws SSLException { + Preconditions.checkState(!freezeNegotiator, "Method unavailable when using ServerCredentials"); SslContext sslContext = SslContextBuilder.forServer(certChain, privateKey).build(); this.fallbackProtocolNegotiator = InternalProtocolNegotiators.serverTls(sslContext); return this; @@ -95,6 +101,7 @@ public XdsServerBuilder useXdsSecurityWithTransportSecurityFallback( @ExperimentalApi("https://github.com/grpc/grpc-java/issues/7514") public XdsServerBuilder useXdsSecurityWithTransportSecurityFallback( InputStream certChain, InputStream privateKey) throws SSLException { + Preconditions.checkState(!freezeNegotiator, "Method unavailable when using ServerCredentials"); SslContext sslContext = SslContextBuilder.forServer(certChain, privateKey).build(); this.fallbackProtocolNegotiator = InternalProtocolNegotiators.serverTls(sslContext); return this; @@ -103,6 +110,7 @@ public XdsServerBuilder useXdsSecurityWithTransportSecurityFallback( /** Set the fallback protocolNegotiator. Pass null to unset a previously set value. */ public XdsServerBuilder fallbackProtocolNegotiator( ProtocolNegotiator fallbackProtocolNegotiator) { + Preconditions.checkState(!freezeNegotiator, "Method unavailable when using ServerCredentials"); this.fallbackProtocolNegotiator = fallbackProtocolNegotiator; return this; } @@ -116,7 +124,13 @@ public XdsServerBuilder errorNotifier(ErrorNotifier errorNotifier) { /** Creates a gRPC server builder for the given port. */ public static XdsServerBuilder forPort(int port) { NettyServerBuilder nettyDelegate = NettyServerBuilder.forAddress(new InetSocketAddress(port)); - return new XdsServerBuilder(nettyDelegate, port); + return new XdsServerBuilder(nettyDelegate, port, /* freezeNegotiator= */ false); + } + + /** Creates a gRPC server builder for the given port. */ + public static XdsServerBuilder forPort(int port, ServerCredentials serverCredentials) { + NettyServerBuilder nettyDelegate = NettyServerBuilder.forPort(port, serverCredentials); + return new XdsServerBuilder(nettyDelegate, port, /* freezeNegotiator= */ true); } @Override diff --git a/xds/src/main/java/io/grpc/xds/XdsServerCredentials.java b/xds/src/main/java/io/grpc/xds/XdsServerCredentials.java new file mode 100644 index 00000000000..65f5102308c --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/XdsServerCredentials.java @@ -0,0 +1,45 @@ +/* + * Copyright 2020 The gRPC Authors + * + * 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. + */ + +package io.grpc.xds; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.grpc.ExperimentalApi; +import io.grpc.ServerCredentials; +import io.grpc.netty.InternalNettyServerCredentials; +import io.grpc.netty.InternalProtocolNegotiator; +import io.grpc.xds.internal.sds.SdsProtocolNegotiators; + +@ExperimentalApi("https://github.com/grpc/grpc-java/issues/7621") +public class XdsServerCredentials { + private XdsServerCredentials() {} // prevent instantiation + + /** + * Creates credentials to be configured by xDS, falling back to other credentials if no + * TLS configuration is provided by xDS. + * + * @param fallback Credentials to fall back to. + * + * @throws IllegalArgumentException if fallback is unable to be used + */ + public static ServerCredentials create(ServerCredentials fallback) { + InternalProtocolNegotiator.ServerFactory fallbackNegotiator = + InternalNettyServerCredentials.toNegotiator(checkNotNull(fallback, "fallback")); + return InternalNettyServerCredentials.create( + SdsProtocolNegotiators.serverProtocolNegotiatorFactory(fallbackNegotiator)); + } +} diff --git a/xds/src/main/java/io/grpc/xds/internal/sds/SdsProtocolNegotiators.java b/xds/src/main/java/io/grpc/xds/internal/sds/SdsProtocolNegotiators.java index 9adb595be57..85041360f79 100644 --- a/xds/src/main/java/io/grpc/xds/internal/sds/SdsProtocolNegotiators.java +++ b/xds/src/main/java/io/grpc/xds/internal/sds/SdsProtocolNegotiators.java @@ -21,6 +21,7 @@ import com.google.common.annotations.VisibleForTesting; import io.grpc.Attributes; import io.grpc.internal.GrpcUtil; +import io.grpc.internal.ObjectPool; import io.grpc.netty.GrpcHttp2ConnectionHandler; import io.grpc.netty.InternalNettyChannelBuilder; import io.grpc.netty.InternalNettyChannelBuilder.ProtocolNegotiatorFactory; @@ -42,6 +43,7 @@ import java.security.cert.CertStoreException; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executor; import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.Nullable; @@ -84,6 +86,11 @@ public static InternalProtocolNegotiator.ClientFactory clientProtocolNegotiatorF return new ClientFactory(fallbackNegotiator); } + public static InternalProtocolNegotiator.ServerFactory serverProtocolNegotiatorFactory( + @Nullable InternalProtocolNegotiator.ServerFactory fallbackNegotiator) { + return new ServerFactory(fallbackNegotiator); + } + /** * Creates an SDS based {@link ProtocolNegotiator} for a {@link io.grpc.netty.NettyServerBuilder}. * If xDS returns no DownstreamTlsContext, it will fall back to plaintext. @@ -95,6 +102,21 @@ public static ServerSdsProtocolNegotiator serverProtocolNegotiator( return new ServerSdsProtocolNegotiator(fallbackProtocolNegotiator); } + private static final class ServerFactory implements InternalProtocolNegotiator.ServerFactory { + + private final InternalProtocolNegotiator.ServerFactory fallbackProtocolNegotiator; + + private ServerFactory(InternalProtocolNegotiator.ServerFactory fallbackNegotiator) { + this.fallbackProtocolNegotiator = fallbackNegotiator; + } + + @Override + public ProtocolNegotiator newNegotiator(ObjectPool offloadExecutorPool) { + return new ServerSdsProtocolNegotiator( + fallbackProtocolNegotiator.newNegotiator(offloadExecutorPool)); + } + } + private static final class ClientFactory implements InternalProtocolNegotiator.ClientFactory { private final InternalProtocolNegotiator.ClientFactory fallbackProtocolNegotiator; diff --git a/xds/src/test/java/io/grpc/xds/XdsSdsClientServerTest.java b/xds/src/test/java/io/grpc/xds/XdsSdsClientServerTest.java index 1f7ed3dcccb..790dddf763f 100644 --- a/xds/src/test/java/io/grpc/xds/XdsSdsClientServerTest.java +++ b/xds/src/test/java/io/grpc/xds/XdsSdsClientServerTest.java @@ -35,13 +35,14 @@ import io.grpc.EquivalentAddressGroup; import io.grpc.Grpc; import io.grpc.InsecureChannelCredentials; +import io.grpc.InsecureServerCredentials; import io.grpc.ManagedChannelBuilder; import io.grpc.NameResolver; import io.grpc.NameResolverProvider; import io.grpc.NameResolverRegistry; +import io.grpc.ServerCredentials; import io.grpc.Status; import io.grpc.StatusRuntimeException; -import io.grpc.netty.InternalProtocolNegotiator.ProtocolNegotiator; import io.grpc.netty.InternalProtocolNegotiators; import io.grpc.stub.StreamObserver; import io.grpc.testing.GrpcCleanupRule; @@ -51,7 +52,6 @@ import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext; import io.grpc.xds.EnvoyServerProtoData.UpstreamTlsContext; import io.grpc.xds.internal.sds.CommonTlsContextTestsUtil; -import io.grpc.xds.internal.sds.SdsProtocolNegotiators; import io.grpc.xds.internal.sds.SslContextProviderSupplier; import io.grpc.xds.internal.sds.TlsContextManagerImpl; import io.grpc.xds.internal.sds.XdsChannelBuilder; @@ -129,18 +129,12 @@ public void plaintextClientServer_withDefaultTlsContext() throws IOException, UR } @Test - public void nullFallbackProtocolNegotiator_expectException() - throws IOException, URISyntaxException { - buildServerWithTlsContext(/* downstreamTlsContext= */ null, - /* fallbackProtocolNegotiator= */ null); - - SimpleServiceGrpc.SimpleServiceBlockingStub blockingStub = - getBlockingStub(/* upstreamTlsContext= */ null, /* overrideAuthority= */ null); + public void nullFallbackCredentials_expectException() throws IOException, URISyntaxException { try { - unaryRpc("buddy", blockingStub); + buildServerWithTlsContext(/* downstreamTlsContext= */ null, /* fallbackCredentials= */ null); fail("exception expected"); - } catch (StatusRuntimeException sre) { - assertThat(sre.getStatus().getCode()).isEqualTo(Status.UNAVAILABLE.getCode()); + } catch (NullPointerException npe) { + assertThat(npe).hasMessageThat().isEqualTo("fallback"); } } @@ -309,8 +303,8 @@ private XdsClient.ListenerWatcher performMtlsTestAndGetListenerWatcher( final XdsClientWrapperForServerSds xdsClientWrapperForServerSds = XdsClientWrapperForServerSdsTest.createXdsClientWrapperForServerSds( port, /* downstreamTlsContext= */ downstreamTlsContext); - buildServerWithFallbackProtocolNegotiator(xdsClientWrapperForServerSds, - InternalProtocolNegotiators.serverPlaintext(), downstreamTlsContext); + buildServerWithFallbackServerCredentials( + xdsClientWrapperForServerSds, InsecureServerCredentials.create(), downstreamTlsContext); XdsClient.ListenerWatcher listenerWatcher = xdsClientWrapperForServerSds.getListenerWatcher(); @@ -323,46 +317,43 @@ private XdsClient.ListenerWatcher performMtlsTestAndGetListenerWatcher( private void buildServerWithTlsContext(DownstreamTlsContext downstreamTlsContext) throws IOException { - buildServerWithTlsContext(downstreamTlsContext, - InternalProtocolNegotiators.serverPlaintext()); + buildServerWithTlsContext(downstreamTlsContext, InsecureServerCredentials.create()); } - private void buildServerWithTlsContext(DownstreamTlsContext downstreamTlsContext, - ProtocolNegotiator fallbackProtocolNegotiator) + private void buildServerWithTlsContext( + DownstreamTlsContext downstreamTlsContext, ServerCredentials fallbackCredentials) throws IOException { XdsClient mockXdsClient = mock(XdsClient.class); XdsClientWrapperForServerSds xdsClientWrapperForServerSds = new XdsClientWrapperForServerSds(port); xdsClientWrapperForServerSds.start(mockXdsClient); - buildServerWithFallbackProtocolNegotiator( - xdsClientWrapperForServerSds, fallbackProtocolNegotiator, downstreamTlsContext); + buildServerWithFallbackServerCredentials( + xdsClientWrapperForServerSds, fallbackCredentials, downstreamTlsContext); } - private void buildServerWithFallbackProtocolNegotiator( + private void buildServerWithFallbackServerCredentials( XdsClientWrapperForServerSds xdsClientWrapperForServerSds, - ProtocolNegotiator fallbackProtocolNegotiator, + ServerCredentials fallbackCredentials, DownstreamTlsContext downstreamTlsContext) throws IOException { - SdsProtocolNegotiators.ServerSdsProtocolNegotiator serverSdsProtocolNegotiator = - new SdsProtocolNegotiators.ServerSdsProtocolNegotiator(fallbackProtocolNegotiator); - buildServer( - port, serverSdsProtocolNegotiator, xdsClientWrapperForServerSds, downstreamTlsContext); + ServerCredentials xdsCredentials = XdsServerCredentials.create(fallbackCredentials); + buildServer(port, xdsCredentials, xdsClientWrapperForServerSds, downstreamTlsContext); } private void buildServer( int port, - SdsProtocolNegotiators.ServerSdsProtocolNegotiator serverSdsProtocolNegotiator, + ServerCredentials serverCredentials, XdsClientWrapperForServerSds xdsClientWrapperForServerSds, DownstreamTlsContext downstreamTlsContext) throws IOException { - XdsServerBuilder builder = XdsServerBuilder.forPort(port).addService(new SimpleServiceImpl()); + XdsServerBuilder builder = XdsServerBuilder.forPort(port, serverCredentials) + .addService(new SimpleServiceImpl()); XdsServerTestHelper.generateListenerUpdate( xdsClientWrapperForServerSds.getListenerWatcher(), port, - downstreamTlsContext, + downstreamTlsContext, /* tlsContext2= */null); - cleanupRule.register( - builder.buildServer(xdsClientWrapperForServerSds, serverSdsProtocolNegotiator)).start(); + cleanupRule.register(builder.buildServer(xdsClientWrapperForServerSds, null)).start(); } static EnvoyServerProtoData.Listener buildListener(