mirror of https://github.com/grpc/grpc-java.git
xds: add CertProviderServerSslContextProvider support (#7331)
This commit is contained in:
parent
39c49b0408
commit
ee9109eced
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* 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.internal.certprovider;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import io.envoyproxy.envoy.config.core.v3.Node;
|
||||||
|
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CertificateValidationContext;
|
||||||
|
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext;
|
||||||
|
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext.CombinedCertificateValidationContext;
|
||||||
|
import io.grpc.netty.GrpcSslContexts;
|
||||||
|
import io.grpc.xds.Bootstrapper.CertificateProviderInfo;
|
||||||
|
import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext;
|
||||||
|
import io.grpc.xds.internal.sds.trust.SdsTrustManagerFactory;
|
||||||
|
import io.netty.handler.ssl.SslContextBuilder;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.cert.CertStoreException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/** A server SslContext provider using CertificateProviderInstance to fetch secrets. */
|
||||||
|
final class CertProviderServerSslContextProvider extends CertProviderSslContextProvider {
|
||||||
|
|
||||||
|
private CertProviderServerSslContextProvider(
|
||||||
|
Node node,
|
||||||
|
Map<String, CertificateProviderInfo> certProviders,
|
||||||
|
CommonTlsContext.CertificateProviderInstance certInstance,
|
||||||
|
CommonTlsContext.CertificateProviderInstance rootCertInstance,
|
||||||
|
CertificateValidationContext staticCertValidationContext,
|
||||||
|
DownstreamTlsContext downstreamTlsContext,
|
||||||
|
CertificateProviderStore certificateProviderStore) {
|
||||||
|
super(
|
||||||
|
node,
|
||||||
|
certProviders,
|
||||||
|
checkNotNull(certInstance, "Server SSL requires certInstance"),
|
||||||
|
rootCertInstance,
|
||||||
|
staticCertValidationContext,
|
||||||
|
downstreamTlsContext,
|
||||||
|
certificateProviderStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final SslContextBuilder getSslContextBuilder(
|
||||||
|
CertificateValidationContext certificateValidationContextdationContext)
|
||||||
|
throws CertStoreException, CertificateException, IOException {
|
||||||
|
SslContextBuilder sslContextBuilder = SslContextBuilder.forServer(savedKey, savedCertChain);
|
||||||
|
setClientAuthValues(
|
||||||
|
sslContextBuilder,
|
||||||
|
isMtls()
|
||||||
|
? new SdsTrustManagerFactory(
|
||||||
|
savedTrustedRoots.toArray(new X509Certificate[0]),
|
||||||
|
certificateValidationContextdationContext)
|
||||||
|
: null);
|
||||||
|
sslContextBuilder = GrpcSslContexts.configure(sslContextBuilder);
|
||||||
|
return sslContextBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates CertProviderServerSslContextProvider. */
|
||||||
|
static final class Factory {
|
||||||
|
private static final Factory DEFAULT_INSTANCE =
|
||||||
|
new Factory(CertificateProviderStore.getInstance());
|
||||||
|
private final CertificateProviderStore certificateProviderStore;
|
||||||
|
|
||||||
|
@VisibleForTesting Factory(CertificateProviderStore certificateProviderStore) {
|
||||||
|
this.certificateProviderStore = certificateProviderStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Factory getInstance() {
|
||||||
|
return DEFAULT_INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
CertProviderServerSslContextProvider getProvider(
|
||||||
|
DownstreamTlsContext downstreamTlsContext,
|
||||||
|
Node node,
|
||||||
|
Map<String, CertificateProviderInfo> certProviders) {
|
||||||
|
checkNotNull(downstreamTlsContext, "downstreamTlsContext");
|
||||||
|
CommonTlsContext commonTlsContext = downstreamTlsContext.getCommonTlsContext();
|
||||||
|
CommonTlsContext.CertificateProviderInstance rootCertInstance = null;
|
||||||
|
CertificateValidationContext staticCertValidationContext = null;
|
||||||
|
if (commonTlsContext.hasCombinedValidationContext()) {
|
||||||
|
CombinedCertificateValidationContext combinedValidationContext =
|
||||||
|
commonTlsContext.getCombinedValidationContext();
|
||||||
|
if (combinedValidationContext.hasValidationContextCertificateProviderInstance()) {
|
||||||
|
rootCertInstance =
|
||||||
|
combinedValidationContext.getValidationContextCertificateProviderInstance();
|
||||||
|
}
|
||||||
|
if (combinedValidationContext.hasDefaultValidationContext()) {
|
||||||
|
staticCertValidationContext = combinedValidationContext.getDefaultValidationContext();
|
||||||
|
}
|
||||||
|
} else if (commonTlsContext.hasValidationContextCertificateProviderInstance()) {
|
||||||
|
rootCertInstance = commonTlsContext.getValidationContextCertificateProviderInstance();
|
||||||
|
} else if (commonTlsContext.hasValidationContext()) {
|
||||||
|
staticCertValidationContext = commonTlsContext.getValidationContext();
|
||||||
|
}
|
||||||
|
CommonTlsContext.CertificateProviderInstance certInstance = null;
|
||||||
|
if (commonTlsContext.hasTlsCertificateCertificateProviderInstance()) {
|
||||||
|
certInstance = commonTlsContext.getTlsCertificateCertificateProviderInstance();
|
||||||
|
}
|
||||||
|
return new CertProviderServerSslContextProvider(
|
||||||
|
node,
|
||||||
|
certProviders,
|
||||||
|
certInstance,
|
||||||
|
rootCertInstance,
|
||||||
|
staticCertValidationContext,
|
||||||
|
downstreamTlsContext,
|
||||||
|
certificateProviderStore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -24,6 +24,7 @@ import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext;
|
||||||
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.SdsSecretConfig;
|
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.SdsSecretConfig;
|
||||||
import io.grpc.netty.GrpcSslContexts;
|
import io.grpc.netty.GrpcSslContexts;
|
||||||
import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext;
|
import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext;
|
||||||
|
import io.grpc.xds.internal.sds.trust.SdsTrustManagerFactory;
|
||||||
import io.netty.handler.ssl.SslContextBuilder;
|
import io.netty.handler.ssl.SslContextBuilder;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.cert.CertStoreException;
|
import java.security.cert.CertStoreException;
|
||||||
|
|
@ -85,7 +86,11 @@ final class SdsServerSslContextProvider extends SdsSslContextProvider {
|
||||||
tlsCertificate.hasPassword()
|
tlsCertificate.hasPassword()
|
||||||
? tlsCertificate.getPassword().getInlineString()
|
? tlsCertificate.getPassword().getInlineString()
|
||||||
: null);
|
: null);
|
||||||
setClientAuthValues(sslContextBuilder, localCertValidationContext);
|
setClientAuthValues(
|
||||||
|
sslContextBuilder,
|
||||||
|
localCertValidationContext != null
|
||||||
|
? new SdsTrustManagerFactory(localCertValidationContext)
|
||||||
|
: null);
|
||||||
return sslContextBuilder;
|
return sslContextBuilder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext;
|
||||||
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.TlsCertificate;
|
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.TlsCertificate;
|
||||||
import io.grpc.netty.GrpcSslContexts;
|
import io.grpc.netty.GrpcSslContexts;
|
||||||
import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext;
|
import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext;
|
||||||
|
import io.grpc.xds.internal.sds.trust.SdsTrustManagerFactory;
|
||||||
import io.netty.handler.ssl.SslContext;
|
import io.netty.handler.ssl.SslContext;
|
||||||
import io.netty.handler.ssl.SslContextBuilder;
|
import io.netty.handler.ssl.SslContextBuilder;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
@ -108,7 +109,8 @@ final class SecretVolumeServerSslContextProvider extends SslContextProvider {
|
||||||
SslContextBuilder sslContextBuilder =
|
SslContextBuilder sslContextBuilder =
|
||||||
GrpcSslContexts.forServer(
|
GrpcSslContexts.forServer(
|
||||||
new File(certificateChain), new File(privateKey), privateKeyPassword);
|
new File(certificateChain), new File(privateKey), privateKeyPassword);
|
||||||
setClientAuthValues(sslContextBuilder, certContext);
|
setClientAuthValues(
|
||||||
|
sslContextBuilder, certContext != null ? new SdsTrustManagerFactory(certContext) : null);
|
||||||
return sslContextBuilder.build();
|
return sslContextBuilder.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ package io.grpc.xds.internal.sds;
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static com.google.common.base.Preconditions.checkState;
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
|
|
||||||
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CertificateValidationContext;
|
|
||||||
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext;
|
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext;
|
||||||
import io.grpc.xds.EnvoyServerProtoData.BaseTlsContext;
|
import io.grpc.xds.EnvoyServerProtoData.BaseTlsContext;
|
||||||
import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext;
|
import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext;
|
||||||
|
|
@ -70,11 +69,11 @@ public abstract class SslContextProvider implements Closeable {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setClientAuthValues(
|
protected void setClientAuthValues(
|
||||||
SslContextBuilder sslContextBuilder, CertificateValidationContext localCertValidationContext)
|
SslContextBuilder sslContextBuilder, SdsTrustManagerFactory sdsTrustManagerFactory)
|
||||||
throws CertificateException, IOException, CertStoreException {
|
throws CertificateException, IOException, CertStoreException {
|
||||||
DownstreamTlsContext downstreamTlsContext = getDownstreamTlsContext();
|
DownstreamTlsContext downstreamTlsContext = getDownstreamTlsContext();
|
||||||
if (localCertValidationContext != null) {
|
if (sdsTrustManagerFactory != null) {
|
||||||
sslContextBuilder.trustManager(new SdsTrustManagerFactory(localCertValidationContext));
|
sslContextBuilder.trustManager(sdsTrustManagerFactory);
|
||||||
sslContextBuilder.clientAuth(
|
sslContextBuilder.clientAuth(
|
||||||
downstreamTlsContext.isRequireClientCertificate()
|
downstreamTlsContext.isRequireClientCertificate()
|
||||||
? ClientAuth.REQUIRE
|
? ClientAuth.REQUIRE
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import static io.grpc.xds.internal.sds.CommonTlsContextTestsUtil.SERVER_1_PEM_FI
|
||||||
import static io.grpc.xds.internal.sds.CommonTlsContextTestsUtil.doChecksOnSslContext;
|
import static io.grpc.xds.internal.sds.CommonTlsContextTestsUtil.doChecksOnSslContext;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.util.concurrent.MoreExecutors;
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
import io.envoyproxy.envoy.config.core.v3.DataSource;
|
import io.envoyproxy.envoy.config.core.v3.DataSource;
|
||||||
|
|
@ -270,7 +271,7 @@ public class CertProviderClientSslContextProviderTest {
|
||||||
|
|
||||||
static class QueuedExecutor implements Executor {
|
static class QueuedExecutor implements Executor {
|
||||||
/** A list of Runnables to be run in order. */
|
/** A list of Runnables to be run in order. */
|
||||||
private final Queue<Runnable> runQueue = new ConcurrentLinkedQueue<>();
|
@VisibleForTesting final Queue<Runnable> runQueue = new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void execute(Runnable r) {
|
public synchronized void execute(Runnable r) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,278 @@
|
||||||
|
/*
|
||||||
|
* 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.internal.certprovider;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static io.grpc.xds.internal.certprovider.CertProviderClientSslContextProviderTest.QueuedExecutor;
|
||||||
|
import static io.grpc.xds.internal.certprovider.CommonCertProviderTestUtils.getCertFromResourceName;
|
||||||
|
import static io.grpc.xds.internal.sds.CommonTlsContextTestsUtil.CA_PEM_FILE;
|
||||||
|
import static io.grpc.xds.internal.sds.CommonTlsContextTestsUtil.CLIENT_PEM_FILE;
|
||||||
|
import static io.grpc.xds.internal.sds.CommonTlsContextTestsUtil.SERVER_0_KEY_FILE;
|
||||||
|
import static io.grpc.xds.internal.sds.CommonTlsContextTestsUtil.SERVER_0_PEM_FILE;
|
||||||
|
import static io.grpc.xds.internal.sds.CommonTlsContextTestsUtil.SERVER_1_KEY_FILE;
|
||||||
|
import static io.grpc.xds.internal.sds.CommonTlsContextTestsUtil.SERVER_1_PEM_FILE;
|
||||||
|
import static io.grpc.xds.internal.sds.CommonTlsContextTestsUtil.doChecksOnSslContext;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
|
import io.envoyproxy.envoy.config.core.v3.DataSource;
|
||||||
|
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CertificateValidationContext;
|
||||||
|
import io.grpc.xds.Bootstrapper;
|
||||||
|
import io.grpc.xds.EnvoyServerProtoData;
|
||||||
|
import io.grpc.xds.internal.sds.CommonTlsContextTestsUtil;
|
||||||
|
import io.grpc.xds.internal.sds.CommonTlsContextTestsUtil.TestCallback;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.JUnit4;
|
||||||
|
|
||||||
|
/** Unit tests for {@link CertProviderServerSslContextProvider}. */
|
||||||
|
@RunWith(JUnit4.class)
|
||||||
|
public class CertProviderServerSslContextProviderTest {
|
||||||
|
|
||||||
|
CertificateProviderRegistry certificateProviderRegistry;
|
||||||
|
CertificateProviderStore certificateProviderStore;
|
||||||
|
private CertProviderServerSslContextProvider.Factory certProviderServerSslContextProviderFactory;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
certificateProviderRegistry = new CertificateProviderRegistry();
|
||||||
|
certificateProviderStore = new CertificateProviderStore(certificateProviderRegistry);
|
||||||
|
certProviderServerSslContextProviderFactory =
|
||||||
|
new CertProviderServerSslContextProvider.Factory(certificateProviderStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Helper method to build CertProviderServerSslContextProvider. */
|
||||||
|
private CertProviderServerSslContextProvider getSslContextProvider(
|
||||||
|
String certInstanceName,
|
||||||
|
String rootInstanceName,
|
||||||
|
Bootstrapper.BootstrapInfo bootstrapInfo,
|
||||||
|
Iterable<String> alpnProtocols,
|
||||||
|
CertificateValidationContext staticCertValidationContext,
|
||||||
|
boolean requireClientCert) {
|
||||||
|
EnvoyServerProtoData.DownstreamTlsContext downstreamTlsContext =
|
||||||
|
CommonTlsContextTestsUtil.buildDownstreamTlsContextForCertProviderInstance(
|
||||||
|
certInstanceName,
|
||||||
|
"cert-default",
|
||||||
|
rootInstanceName,
|
||||||
|
"root-default",
|
||||||
|
alpnProtocols,
|
||||||
|
staticCertValidationContext,
|
||||||
|
requireClientCert);
|
||||||
|
return certProviderServerSslContextProviderFactory.getProvider(
|
||||||
|
downstreamTlsContext,
|
||||||
|
bootstrapInfo.getNode().toEnvoyProtoNode(),
|
||||||
|
bootstrapInfo.getCertProviders());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProviderForServer_mtls() throws Exception {
|
||||||
|
final CertificateProvider.DistributorWatcher[] watcherCaptor =
|
||||||
|
new CertificateProvider.DistributorWatcher[1];
|
||||||
|
TestCertificateProvider.createAndRegisterProviderProvider(
|
||||||
|
certificateProviderRegistry, watcherCaptor, "testca", 0);
|
||||||
|
CertProviderServerSslContextProvider provider =
|
||||||
|
getSslContextProvider(
|
||||||
|
"gcp_id",
|
||||||
|
"gcp_id",
|
||||||
|
CommonCertProviderTestUtils.getTestBootstrapInfo(),
|
||||||
|
/* alpnProtocols= */ null,
|
||||||
|
/* staticCertValidationContext= */ null,
|
||||||
|
/* requireClientCert= */ true);
|
||||||
|
|
||||||
|
assertThat(provider.savedKey).isNull();
|
||||||
|
assertThat(provider.savedCertChain).isNull();
|
||||||
|
assertThat(provider.savedTrustedRoots).isNull();
|
||||||
|
assertThat(provider.getSslContext()).isNull();
|
||||||
|
|
||||||
|
// now generate cert update
|
||||||
|
watcherCaptor[0].updateCertificate(
|
||||||
|
CommonCertProviderTestUtils.getPrivateKey(SERVER_0_KEY_FILE),
|
||||||
|
ImmutableList.of(getCertFromResourceName(SERVER_0_PEM_FILE)));
|
||||||
|
assertThat(provider.savedKey).isNotNull();
|
||||||
|
assertThat(provider.savedCertChain).isNotNull();
|
||||||
|
assertThat(provider.getSslContext()).isNull();
|
||||||
|
|
||||||
|
// now generate root cert update
|
||||||
|
watcherCaptor[0].updateTrustedRoots(ImmutableList.of(getCertFromResourceName(CA_PEM_FILE)));
|
||||||
|
assertThat(provider.getSslContext()).isNotNull();
|
||||||
|
assertThat(provider.savedKey).isNull();
|
||||||
|
assertThat(provider.savedCertChain).isNull();
|
||||||
|
assertThat(provider.savedTrustedRoots).isNull();
|
||||||
|
|
||||||
|
TestCallback testCallback =
|
||||||
|
CommonTlsContextTestsUtil.getValueThruCallback(provider);
|
||||||
|
|
||||||
|
doChecksOnSslContext(true, testCallback.updatedSslContext, /* expectedApnProtos= */ null);
|
||||||
|
TestCallback testCallback1 =
|
||||||
|
CommonTlsContextTestsUtil.getValueThruCallback(provider);
|
||||||
|
assertThat(testCallback1.updatedSslContext).isSameInstanceAs(testCallback.updatedSslContext);
|
||||||
|
|
||||||
|
// just do root cert update: sslContext should still be the same
|
||||||
|
watcherCaptor[0].updateTrustedRoots(
|
||||||
|
ImmutableList.of(getCertFromResourceName(CLIENT_PEM_FILE)));
|
||||||
|
assertThat(provider.savedKey).isNull();
|
||||||
|
assertThat(provider.savedCertChain).isNull();
|
||||||
|
assertThat(provider.savedTrustedRoots).isNotNull();
|
||||||
|
testCallback1 = CommonTlsContextTestsUtil.getValueThruCallback(provider);
|
||||||
|
assertThat(testCallback1.updatedSslContext).isSameInstanceAs(testCallback.updatedSslContext);
|
||||||
|
|
||||||
|
// now update id cert: sslContext should be updated i.e.different from the previous one
|
||||||
|
watcherCaptor[0].updateCertificate(
|
||||||
|
CommonCertProviderTestUtils.getPrivateKey(SERVER_1_KEY_FILE),
|
||||||
|
ImmutableList.of(getCertFromResourceName(SERVER_1_PEM_FILE)));
|
||||||
|
assertThat(provider.savedKey).isNull();
|
||||||
|
assertThat(provider.savedCertChain).isNull();
|
||||||
|
assertThat(provider.savedTrustedRoots).isNull();
|
||||||
|
assertThat(provider.getSslContext()).isNotNull();
|
||||||
|
testCallback1 = CommonTlsContextTestsUtil.getValueThruCallback(provider);
|
||||||
|
assertThat(testCallback1.updatedSslContext).isNotSameInstanceAs(testCallback.updatedSslContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProviderForServer_queueExecutor() throws Exception {
|
||||||
|
final CertificateProvider.DistributorWatcher[] watcherCaptor =
|
||||||
|
new CertificateProvider.DistributorWatcher[1];
|
||||||
|
TestCertificateProvider.createAndRegisterProviderProvider(
|
||||||
|
certificateProviderRegistry, watcherCaptor, "testca", 0);
|
||||||
|
CertProviderServerSslContextProvider provider =
|
||||||
|
getSslContextProvider(
|
||||||
|
"gcp_id",
|
||||||
|
"gcp_id",
|
||||||
|
CommonCertProviderTestUtils.getTestBootstrapInfo(),
|
||||||
|
/* alpnProtocols= */ null,
|
||||||
|
/* staticCertValidationContext= */ null,
|
||||||
|
/* requireClientCert= */ true);
|
||||||
|
QueuedExecutor queuedExecutor = new QueuedExecutor();
|
||||||
|
|
||||||
|
TestCallback testCallback =
|
||||||
|
CommonTlsContextTestsUtil.getValueThruCallback(provider, queuedExecutor);
|
||||||
|
assertThat(queuedExecutor.runQueue).isEmpty();
|
||||||
|
|
||||||
|
// now generate cert update
|
||||||
|
watcherCaptor[0].updateCertificate(
|
||||||
|
CommonCertProviderTestUtils.getPrivateKey(SERVER_0_KEY_FILE),
|
||||||
|
ImmutableList.of(getCertFromResourceName(SERVER_0_PEM_FILE)));
|
||||||
|
assertThat(queuedExecutor.runQueue).isEmpty(); // still empty
|
||||||
|
|
||||||
|
// now generate root cert update
|
||||||
|
watcherCaptor[0].updateTrustedRoots(ImmutableList.of(getCertFromResourceName(CA_PEM_FILE)));
|
||||||
|
assertThat(queuedExecutor.runQueue).hasSize(1);
|
||||||
|
queuedExecutor.drain();
|
||||||
|
|
||||||
|
doChecksOnSslContext(true, testCallback.updatedSslContext, /* expectedApnProtos= */ null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProviderForServer_tls() throws Exception {
|
||||||
|
final CertificateProvider.DistributorWatcher[] watcherCaptor =
|
||||||
|
new CertificateProvider.DistributorWatcher[1];
|
||||||
|
TestCertificateProvider.createAndRegisterProviderProvider(
|
||||||
|
certificateProviderRegistry, watcherCaptor, "testca", 0);
|
||||||
|
CertProviderServerSslContextProvider provider =
|
||||||
|
getSslContextProvider(
|
||||||
|
"gcp_id",
|
||||||
|
/* rootInstanceName= */ null,
|
||||||
|
CommonCertProviderTestUtils.getTestBootstrapInfo(),
|
||||||
|
/* alpnProtocols= */ null,
|
||||||
|
/* staticCertValidationContext= */ null,
|
||||||
|
/* requireClientCert= */ false);
|
||||||
|
|
||||||
|
assertThat(provider.savedKey).isNull();
|
||||||
|
assertThat(provider.savedCertChain).isNull();
|
||||||
|
assertThat(provider.savedTrustedRoots).isNull();
|
||||||
|
assertThat(provider.getSslContext()).isNull();
|
||||||
|
|
||||||
|
// now generate cert update
|
||||||
|
watcherCaptor[0].updateCertificate(
|
||||||
|
CommonCertProviderTestUtils.getPrivateKey(SERVER_0_KEY_FILE),
|
||||||
|
ImmutableList.of(getCertFromResourceName(SERVER_0_PEM_FILE)));
|
||||||
|
|
||||||
|
assertThat(provider.getSslContext()).isNotNull();
|
||||||
|
assertThat(provider.savedKey).isNull();
|
||||||
|
assertThat(provider.savedCertChain).isNull();
|
||||||
|
assertThat(provider.savedTrustedRoots).isNull();
|
||||||
|
|
||||||
|
TestCallback testCallback =
|
||||||
|
CommonTlsContextTestsUtil.getValueThruCallback(provider);
|
||||||
|
|
||||||
|
doChecksOnSslContext(true, testCallback.updatedSslContext, /* expectedApnProtos= */ null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProviderForServer_sslContextException_onError() throws Exception {
|
||||||
|
CertificateValidationContext staticCertValidationContext =
|
||||||
|
CertificateValidationContext.newBuilder()
|
||||||
|
.setTrustedCa(DataSource.newBuilder().setInlineString("foo"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final CertificateProvider.DistributorWatcher[] watcherCaptor =
|
||||||
|
new CertificateProvider.DistributorWatcher[1];
|
||||||
|
TestCertificateProvider.createAndRegisterProviderProvider(
|
||||||
|
certificateProviderRegistry, watcherCaptor, "testca", 0);
|
||||||
|
CertProviderServerSslContextProvider provider =
|
||||||
|
getSslContextProvider(
|
||||||
|
/* certInstanceName= */ "gcp_id",
|
||||||
|
/* rootInstanceName= */ "gcp_id",
|
||||||
|
CommonCertProviderTestUtils.getTestBootstrapInfo(),
|
||||||
|
/* alpnProtocols= */null,
|
||||||
|
staticCertValidationContext,
|
||||||
|
/* requireClientCert= */ true);
|
||||||
|
|
||||||
|
// now generate cert update
|
||||||
|
watcherCaptor[0].updateCertificate(
|
||||||
|
CommonCertProviderTestUtils.getPrivateKey(SERVER_0_KEY_FILE),
|
||||||
|
ImmutableList.of(getCertFromResourceName(SERVER_0_PEM_FILE)));
|
||||||
|
|
||||||
|
TestCallback testCallback = new TestCallback(MoreExecutors.directExecutor());
|
||||||
|
provider.addCallback(testCallback);
|
||||||
|
try {
|
||||||
|
watcherCaptor[0].updateTrustedRoots(ImmutableList.of(getCertFromResourceName(CA_PEM_FILE)));
|
||||||
|
fail("exception expected");
|
||||||
|
} catch (RuntimeException expected) {
|
||||||
|
assertThat(expected)
|
||||||
|
.hasMessageThat()
|
||||||
|
.contains("only static certificateValidationContext expected");
|
||||||
|
}
|
||||||
|
assertThat(testCallback.updatedThrowable).isNotNull();
|
||||||
|
assertThat(testCallback.updatedThrowable)
|
||||||
|
.hasCauseThat()
|
||||||
|
.hasMessageThat()
|
||||||
|
.contains("only static certificateValidationContext expected");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProviderForServer_certInstanceNull_expectError() throws Exception {
|
||||||
|
final CertificateProvider.DistributorWatcher[] watcherCaptor =
|
||||||
|
new CertificateProvider.DistributorWatcher[1];
|
||||||
|
TestCertificateProvider.createAndRegisterProviderProvider(
|
||||||
|
certificateProviderRegistry, watcherCaptor, "testca", 0);
|
||||||
|
try {
|
||||||
|
getSslContextProvider(
|
||||||
|
/* certInstanceName= */ null,
|
||||||
|
/* rootInstanceName= */ null,
|
||||||
|
CommonCertProviderTestUtils.getTestBootstrapInfo(),
|
||||||
|
/* alpnProtocols= */ null,
|
||||||
|
/* staticCertValidationContext= */ null,
|
||||||
|
/* requireClientCert= */ false);
|
||||||
|
fail("exception expected");
|
||||||
|
} catch (NullPointerException expected) {
|
||||||
|
assertThat(expected).hasMessageThat().contains("Server SSL requires certInstance");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -533,6 +533,27 @@ public class CommonTlsContextTestsUtil {
|
||||||
staticCertValidationContext));
|
staticCertValidationContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Helper method to build DownstreamTlsContext for CertProvider tests. */
|
||||||
|
public static EnvoyServerProtoData.DownstreamTlsContext
|
||||||
|
buildDownstreamTlsContextForCertProviderInstance(
|
||||||
|
@Nullable String certInstanceName,
|
||||||
|
@Nullable String certName,
|
||||||
|
@Nullable String rootInstanceName,
|
||||||
|
@Nullable String rootCertName,
|
||||||
|
Iterable<String> alpnProtocols,
|
||||||
|
CertificateValidationContext staticCertValidationContext,
|
||||||
|
boolean requireClientCert) {
|
||||||
|
return buildInternalDownstreamTlsContext(
|
||||||
|
buildCommonTlsContextForCertProviderInstance(
|
||||||
|
certInstanceName,
|
||||||
|
certName,
|
||||||
|
rootInstanceName,
|
||||||
|
rootCertName,
|
||||||
|
alpnProtocols,
|
||||||
|
staticCertValidationContext), requireClientCert);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Perform some simple checks on sslContext. */
|
/** Perform some simple checks on sslContext. */
|
||||||
public static void doChecksOnSslContext(boolean server, SslContext sslContext,
|
public static void doChecksOnSslContext(boolean server, SslContext sslContext,
|
||||||
List<String> expectedApnProtos) {
|
List<String> expectedApnProtos) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue