From 1f9bbb98ac9fa1cc4b6cc85608e071325101af80 Mon Sep 17 00:00:00 2001 From: Francisco Bento Date: Fri, 24 Feb 2023 15:49:57 -0300 Subject: [PATCH] Introduce mTLS support for JaegerRemoteSamplerBuilder (#5209) --- ...ry-sdk-extension-jaeger-remote-sampler.txt | 4 +- .../sampler/JaegerRemoteSamplerBuilder.java | 9 ++++ .../sampler/JaegerRemoteSamplerTest.java | 49 +++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-extension-jaeger-remote-sampler.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-extension-jaeger-remote-sampler.txt index df26146497b..2b005215e68 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-extension-jaeger-remote-sampler.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-extension-jaeger-remote-sampler.txt @@ -1,2 +1,4 @@ Comparing source compatibility of against -No changes. \ No newline at end of file +*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.extension.trace.jaeger.sampler.JaegerRemoteSamplerBuilder (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.extension.trace.jaeger.sampler.JaegerRemoteSamplerBuilder setClientTls(byte[], byte[]) diff --git a/sdk-extensions/jaeger-remote-sampler/src/main/java/io/opentelemetry/sdk/extension/trace/jaeger/sampler/JaegerRemoteSamplerBuilder.java b/sdk-extensions/jaeger-remote-sampler/src/main/java/io/opentelemetry/sdk/extension/trace/jaeger/sampler/JaegerRemoteSamplerBuilder.java index f290c40e630..9cf7d7696bd 100644 --- a/sdk-extensions/jaeger-remote-sampler/src/main/java/io/opentelemetry/sdk/extension/trace/jaeger/sampler/JaegerRemoteSamplerBuilder.java +++ b/sdk-extensions/jaeger-remote-sampler/src/main/java/io/opentelemetry/sdk/extension/trace/jaeger/sampler/JaegerRemoteSamplerBuilder.java @@ -65,6 +65,15 @@ public JaegerRemoteSamplerBuilder setTrustedCertificates(byte[] trustedCertifica return this; } + /** + * Sets the client key and the certificate chain to use for verifying client when TLS is enabled. + * The key must be PKCS8, and both must be in PEM format. + */ + public JaegerRemoteSamplerBuilder setClientTls(byte[] privateKeyPem, byte[] certificatePem) { + delegate.setClientTls(privateKeyPem, certificatePem); + return this; + } + /** * Sets the polling interval for configuration updates. If unset, defaults to {@value * DEFAULT_POLLING_INTERVAL_MILLIS}ms. Must be positive. diff --git a/sdk-extensions/jaeger-remote-sampler/src/test/java/io/opentelemetry/sdk/extension/trace/jaeger/sampler/JaegerRemoteSamplerTest.java b/sdk-extensions/jaeger-remote-sampler/src/test/java/io/opentelemetry/sdk/extension/trace/jaeger/sampler/JaegerRemoteSamplerTest.java index 4ea64d8e370..0eb50298e57 100644 --- a/sdk-extensions/jaeger-remote-sampler/src/test/java/io/opentelemetry/sdk/extension/trace/jaeger/sampler/JaegerRemoteSamplerTest.java +++ b/sdk-extensions/jaeger-remote-sampler/src/test/java/io/opentelemetry/sdk/extension/trace/jaeger/sampler/JaegerRemoteSamplerTest.java @@ -8,6 +8,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.awaitility.Awaitility.await; +import static org.junit.jupiter.api.Named.named; +import static org.junit.jupiter.params.provider.Arguments.arguments; import com.linecorp.armeria.common.grpc.protocol.ArmeriaStatusException; import com.linecorp.armeria.server.ServerBuilder; @@ -16,6 +18,7 @@ import com.linecorp.armeria.testing.junit5.server.SelfSignedCertificateExtension; import com.linecorp.armeria.testing.junit5.server.ServerExtension; import io.github.netmikey.logunit.api.LogCapturer; +import io.netty.handler.ssl.ClientAuth; import io.opentelemetry.internal.testing.slf4j.SuppressLogger; import io.opentelemetry.sdk.extension.trace.jaeger.proto.api_v2.Sampling; import io.opentelemetry.sdk.extension.trace.jaeger.proto.api_v2.Sampling.RateLimitingSamplingStrategy; @@ -29,12 +32,18 @@ import java.util.concurrent.CompletionStage; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; import javax.annotation.Nullable; import org.awaitility.core.ThrowingRunnable; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; import org.slf4j.event.Level; import org.slf4j.event.LoggingEvent; @@ -61,7 +70,12 @@ private static void addGrpcError(int code, @Nullable String message) { @RegisterExtension static final SelfSignedCertificateExtension certificate = new SelfSignedCertificateExtension(); + @RegisterExtension @Order(2) + static final SelfSignedCertificateExtension clientCertificate = + new SelfSignedCertificateExtension(); + + @Order(3) @RegisterExtension static final ServerExtension server = new ServerExtension() { @@ -98,6 +112,11 @@ protected CompletionStage handleMessage( sb.http(0); sb.https(0); sb.tls(certificate.certificateFile(), certificate.privateKeyFile()); + sb.tlsCustomizer( + ssl -> { + ssl.clientAuth(ClientAuth.OPTIONAL); + ssl.trustManager(clientCertificate.certificate()); + }); } }; @@ -140,6 +159,36 @@ void tlsConnectionWorks() throws IOException { } } + @ParameterizedTest + @ArgumentsSource(ClientPrivateKeyProvider.class) + void clientTlsConnectionWorks(byte[] privateKey) throws IOException { + try (JaegerRemoteSampler sampler = + JaegerRemoteSampler.builder() + .setEndpoint(server.httpsUri().toString()) + .setPollingInterval(1, TimeUnit.SECONDS) + .setTrustedCertificates(Files.readAllBytes(certificate.certificateFile().toPath())) + .setClientTls( + privateKey, Files.readAllBytes(clientCertificate.certificateFile().toPath())) + .setServiceName(SERVICE_NAME) + .build()) { + + await().untilAsserted(samplerIsType(sampler, RateLimitingSampler.class)); + + // verify + assertThat(sampler.getDescription()).contains("RateLimitingSampler{999.00}"); + } + } + + private static class ClientPrivateKeyProvider implements ArgumentsProvider { + @Override + @SuppressWarnings("PrimitiveArrayPassedToVarargsMethod") + public Stream provideArguments(ExtensionContext context) throws Exception { + return Stream.of( + arguments(named("PEM", Files.readAllBytes(clientCertificate.privateKeyFile().toPath()))), + arguments(named("DER", clientCertificate.privateKey().getEncoded()))); + } + } + @Test void description() { try (JaegerRemoteSampler sampler =