xds: implement XdsServerCredentials (#7636)

Co-authored-by: Eric Anderson <ejona@google.com>
This commit is contained in:
sanjaypujare 2020-11-18 12:46:29 -08:00 committed by GitHub
parent 79d2e0c326
commit 620d266677
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 107 additions and 35 deletions

View File

@ -49,9 +49,9 @@ public final class InternalNettyServerCredentials {
* @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);
}

View File

@ -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<XdsServerBui
private final NettyServerBuilder delegate;
private final int port;
private final boolean freezeNegotiator;
private ProtocolNegotiator fallbackProtocolNegotiator;
private ErrorNotifier errorNotifier;
private XdsServerBuilder(NettyServerBuilder nettyDelegate, int port) {
private XdsServerBuilder(NettyServerBuilder nettyDelegate, int port, boolean freezeNegotiator) {
this.delegate = nettyDelegate;
this.port = port;
this.freezeNegotiator = freezeNegotiator;
}
@Override
@ -66,6 +70,7 @@ public final class XdsServerBuilder extends ForwardingServerBuilder<XdsServerBui
*/
@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 final class XdsServerBuilder extends ForwardingServerBuilder<XdsServerBui
@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 final class XdsServerBuilder extends ForwardingServerBuilder<XdsServerBui
@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 final class XdsServerBuilder extends ForwardingServerBuilder<XdsServerBui
/** 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 final class XdsServerBuilder extends ForwardingServerBuilder<XdsServerBui
/** 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

View File

@ -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));
}
}

View File

@ -21,6 +21,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
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 io.netty.util.AsciiString;
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 final class SdsProtocolNegotiators {
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 final class SdsProtocolNegotiators {
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<? extends Executor> offloadExecutorPool) {
return new ServerSdsProtocolNegotiator(
fallbackProtocolNegotiator.newNegotiator(offloadExecutorPool));
}
}
private static final class ClientFactory implements InternalProtocolNegotiator.ClientFactory {
private final InternalProtocolNegotiator.ClientFactory fallbackProtocolNegotiator;

View File

@ -35,13 +35,14 @@ import io.grpc.Attributes;
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.testing.protobuf.SimpleServiceGrpc;
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 class XdsSdsClientServerTest {
}
@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 @@ public class XdsSdsClientServerTest {
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 @@ public class XdsSdsClientServerTest {
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(