Skip to content

Commit

Permalink
xds: implement XdsServerCredentials (#7636)
Browse files Browse the repository at this point in the history
Co-authored-by: Eric Anderson <ejona@google.com>
  • Loading branch information
sanjaypujare and ejona86 committed Nov 18, 2020
1 parent 79d2e0c commit 620d266
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 35 deletions.
Expand Up @@ -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);
}
Expand Down
18 changes: 16 additions & 2 deletions xds/src/main/java/io/grpc/xds/XdsServerBuilder.java
Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -66,6 +70,7 @@ protected ServerBuilder<?> 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;
}
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
}
Expand All @@ -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
Expand Down
45 changes: 45 additions & 0 deletions 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));
}
}
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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.
Expand All @@ -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<? extends Executor> offloadExecutorPool) {
return new ServerSdsProtocolNegotiator(
fallbackProtocolNegotiator.newNegotiator(offloadExecutorPool));
}
}

private static final class ClientFactory implements InternalProtocolNegotiator.ClientFactory {

private final InternalProtocolNegotiator.ClientFactory fallbackProtocolNegotiator;
Expand Down
53 changes: 22 additions & 31 deletions xds/src/test/java/io/grpc/xds/XdsSdsClientServerTest.java
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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");
}
}

Expand Down Expand Up @@ -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();

Expand All @@ -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(
Expand Down

0 comments on commit 620d266

Please sign in to comment.