Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

xds: implement XdsServerCredentials #7636

Merged
merged 3 commits into from Nov 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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