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

Add TlsConfigurationRegistry to OTel #41048

Merged
merged 2 commits into from
Jun 7, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import io.quarkus.opentelemetry.runtime.config.runtime.exporter.OtlpExporterRuntimeConfig;
import io.quarkus.opentelemetry.runtime.exporter.otlp.LateBoundBatchSpanProcessor;
import io.quarkus.opentelemetry.runtime.exporter.otlp.OTelExporterRecorder;
import io.quarkus.tls.TlsConfigurationRegistry;
import io.quarkus.tls.TlsRegistryBuildItem;
import io.quarkus.vertx.core.deployment.CoreVertxBuildItem;

Expand Down Expand Up @@ -64,6 +65,7 @@ void createBatchSpanProcessor(OTelExporterRecorder recorder,
.unremovable()
.addInjectionPoint(ParameterizedType.create(DotName.createSimple(Instance.class),
new Type[] { ClassType.create(DotName.createSimple(SpanExporter.class.getName())) }, null))
.addInjectionPoint(ClassType.create(DotName.createSimple(TlsConfigurationRegistry.class)))
.createWith(recorder.batchSpanProcessorForOtlp(otelRuntimeConfig, exporterRuntimeConfig,
vertxBuildItem.getVertx()))
.done());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@ public interface OtlpExporterTracesConfig {
@WithName("trust-cert")
TrustCert trustCert();

/**
* The name of the TLS configuration to use.
* <p>
* If not set and the default TLS configuration is configured ({@code quarkus.tls.*}) then that will be used.
* If a name is configured, it uses the configuration from {@code quarkus.tls.<name>.*}
* If a name is configured, but no TLS configuration is found with that name then an error will be thrown.
*/
Optional<String> tlsConfigurationName();

/**
* Set proxy options
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessorBuilder;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import io.quarkus.arc.Arc;
import io.quarkus.arc.SyntheticCreationalContext;
import io.quarkus.opentelemetry.runtime.config.runtime.OTelRuntimeConfig;
import io.quarkus.opentelemetry.runtime.config.runtime.exporter.CompressionType;
Expand All @@ -35,7 +34,6 @@
import io.quarkus.tls.TlsConfigurationRegistry;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpClientOptions;
import io.vertx.core.net.KeyCertOptions;
import io.vertx.core.net.PemKeyCertOptions;
import io.vertx.core.net.PemTrustOptions;
import io.vertx.core.net.ProxyOptions;
Expand Down Expand Up @@ -63,7 +61,10 @@ public LateBoundBatchSpanProcessor apply(
}

try {
var spanExporter = createSpanExporter(exporterRuntimeConfig, vertx.get(), baseUri);
TlsConfigurationRegistry tlsConfigurationRegistry = context
.getInjectedReference(TlsConfigurationRegistry.class);
var spanExporter = createSpanExporter(exporterRuntimeConfig, vertx.get(), baseUri,
tlsConfigurationRegistry);

BatchSpanProcessorBuilder processorBuilder = BatchSpanProcessor.builder(spanExporter);

Expand All @@ -80,7 +81,9 @@ public LateBoundBatchSpanProcessor apply(
}

private SpanExporter createSpanExporter(OtlpExporterRuntimeConfig exporterRuntimeConfig,
Vertx vertx, final URI baseUri) {
Vertx vertx,
URI baseUri,
TlsConfigurationRegistry tlsConfigurationRegistry) {
OtlpExporterTracesConfig tracesConfig = exporterRuntimeConfig.traces();
if (tracesConfig.protocol().isEmpty()) {
throw new IllegalStateException("No OTLP protocol specified. " +
Expand All @@ -89,17 +92,18 @@ private SpanExporter createSpanExporter(OtlpExporterRuntimeConfig exporterRuntim

String protocol = tracesConfig.protocol().get();
if (GRPC.equals(protocol)) {
return createOtlpGrpcSpanExporter(exporterRuntimeConfig, vertx, baseUri);
return createOtlpGrpcSpanExporter(exporterRuntimeConfig, vertx, baseUri, tlsConfigurationRegistry);
} else if (HTTP_PROTOBUF.equals(protocol)) {
return createHttpSpanExporter(exporterRuntimeConfig, vertx, baseUri, protocol);
return createHttpSpanExporter(exporterRuntimeConfig, vertx, baseUri, protocol, tlsConfigurationRegistry);
}

throw new IllegalArgumentException(String.format("Unsupported OTLP protocol %s specified. " +
"Please check `quarkus.otel.exporter.otlp.traces.protocol` property", protocol));
}

private SpanExporter createOtlpGrpcSpanExporter(OtlpExporterRuntimeConfig exporterRuntimeConfig,
Vertx vertx, final URI baseUri) {
Vertx vertx, final URI baseUri,
TlsConfigurationRegistry tlsConfigurationRegistry) {

OtlpExporterTracesConfig tracesConfig = exporterRuntimeConfig.traces();

Expand All @@ -111,13 +115,14 @@ private SpanExporter createOtlpGrpcSpanExporter(OtlpExporterRuntimeConfig export
determineCompression(tracesConfig),
tracesConfig.timeout(),
populateTracingExportHttpHeaders(tracesConfig),
new HttpClientOptionsConsumer(tracesConfig, baseUri),
new HttpClientOptionsConsumer(tracesConfig, baseUri, tlsConfigurationRegistry),
vertx);

}

private SpanExporter createHttpSpanExporter(OtlpExporterRuntimeConfig exporterRuntimeConfig, Vertx vertx,
URI baseUri, String protocol) {
URI baseUri, String protocol,
TlsConfigurationRegistry tlsConfigurationRegistry) {

OtlpExporterTracesConfig tracesConfig = exporterRuntimeConfig.traces();

Expand All @@ -132,7 +137,7 @@ private SpanExporter createHttpSpanExporter(OtlpExporterRuntimeConfig exporterRu
tracesConfig.timeout(),
populateTracingExportHttpHeaders(tracesConfig),
exportAsJson ? "application/json" : "application/x-protobuf",
new HttpClientOptionsConsumer(tracesConfig, baseUri),
new HttpClientOptionsConsumer(tracesConfig, baseUri, tlsConfigurationRegistry),
vertx),
MeterProvider::noop,
exportAsJson));
Expand Down Expand Up @@ -193,10 +198,15 @@ private static boolean excludeDefaultEndpoint(String endpoint) {
static class HttpClientOptionsConsumer implements Consumer<HttpClientOptions> {
private final OtlpExporterTracesConfig tracesConfig;
private final URI baseUri;
private final Optional<TlsConfiguration> maybeTlsConfiguration;
private final TlsConfigurationRegistry tlsConfigurationRegistry;

public HttpClientOptionsConsumer(OtlpExporterTracesConfig tracesConfig, URI baseUri) {
public HttpClientOptionsConsumer(OtlpExporterTracesConfig tracesConfig, URI baseUri,
TlsConfigurationRegistry tlsConfigurationRegistry) {
this.tracesConfig = tracesConfig;
this.baseUri = baseUri;
this.maybeTlsConfiguration = TlsConfiguration.from(tlsConfigurationRegistry, tracesConfig.tlsConfigurationName());
this.tlsConfigurationRegistry = tlsConfigurationRegistry;
}

@Override
Expand All @@ -208,24 +218,22 @@ public void accept(HttpClientOptions options) {
}

private void configureTLS(HttpClientOptions options) {
// TODO: this can reuse existing stuff when /~https://github.com/quarkusio/quarkus/pull/33228 is in
options.setKeyCertOptions(toPemKeyCertOptions());
options.setPemTrustOptions(toPemTrustOptions());
configureKeyCertOptions(options);
configureTrustOptions(options);

if (OTelExporterUtil.isHttps(baseUri)) {
options.setSsl(true);
options.setUseAlpn(true);
}

boolean globalTrustAll = false;
if (Arc.container() != null) {
TlsConfigurationRegistry registry = Arc.container().select(TlsConfigurationRegistry.class).orNull();
if (registry != null) {
globalTrustAll = registry.getDefault().map(TlsConfiguration::isTrustAll).orElse(false);
}
}

if (globalTrustAll) {
boolean trustAll = maybeTlsConfiguration.map(TlsConfiguration::isTrustAll).orElseGet(
new Supplier<>() {
@Override
public Boolean get() {
return tlsConfigurationRegistry.getDefault().map(TlsConfiguration::isTrustAll).orElse(false);
}
});
if (trustAll) {
options.setTrustAll(true);
options.setVerifyHost(false);
}
Expand Down Expand Up @@ -279,10 +287,15 @@ private void configureProxyOptionsFromJDKSysProps(HttpClientOptions options) {
}
}

private KeyCertOptions toPemKeyCertOptions() {
private void configureKeyCertOptions(HttpClientOptions options) {
if (maybeTlsConfiguration.isPresent()) {
options.setKeyCertOptions(maybeTlsConfiguration.get().getKeyStoreOptions());
return;
}

OtlpExporterTracesConfig.KeyCert keyCert = tracesConfig.keyCert();
if (keyCert.certs().isEmpty() && keyCert.keys().isEmpty()) {
return null;
return;
}

PemKeyCertOptions pemKeyCertOptions = new PemKeyCertOptions();
Expand All @@ -296,10 +309,15 @@ private KeyCertOptions toPemKeyCertOptions() {
pemKeyCertOptions.addKeyPath(cert);
}
}
return pemKeyCertOptions;
options.setKeyCertOptions(pemKeyCertOptions);
}

private PemTrustOptions toPemTrustOptions() {
private void configureTrustOptions(HttpClientOptions options) {
if (maybeTlsConfiguration.isPresent()) {
options.setTrustOptions(maybeTlsConfiguration.get().getTrustStoreOptions());
return;
}

OtlpExporterTracesConfig.TrustCert trustCert = tracesConfig.trustCert();
if (trustCert.certs().isPresent()) {
List<String> certs = trustCert.certs().get();
Expand All @@ -308,10 +326,9 @@ private PemTrustOptions toPemTrustOptions() {
for (String cert : trustCert.certs().get()) {
pemTrustOptions.addCertPath(cert);
}
return pemTrustOptions;
options.setPemTrustOptions(pemTrustOptions);
}
}
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

import io.quarkus.opentelemetry.runtime.config.runtime.exporter.CompressionType;
import io.quarkus.opentelemetry.runtime.config.runtime.exporter.OtlpExporterTracesConfig;
import io.quarkus.tls.TlsConfiguration;
import io.quarkus.tls.TlsConfigurationRegistry;
import io.vertx.core.http.HttpClientOptions;

class HttpClientOptionsConsumerTest {
Expand All @@ -23,7 +25,8 @@ class HttpClientOptionsConsumerTest {
void testNoProxy() {
OTelExporterRecorder.HttpClientOptionsConsumer consumer = new OTelExporterRecorder.HttpClientOptionsConsumer(
createExporterConfig(false),
URI.create("http://localhost:4317"));
URI.create("http://localhost:4317"),
new NoopTlsConfigurationRegistry());

HttpClientOptions httpClientOptions = new HttpClientOptions();
consumer.accept(httpClientOptions);
Expand All @@ -34,7 +37,8 @@ void testNoProxy() {
void testWithProxy() {
OTelExporterRecorder.HttpClientOptionsConsumer consumer = new OTelExporterRecorder.HttpClientOptionsConsumer(
createExporterConfig(true),
URI.create("http://localhost:4317"));
URI.create("http://localhost:4317"),
new NoopTlsConfigurationRegistry());

HttpClientOptions httpClientOptions = new HttpClientOptions();
consumer.accept(httpClientOptions);
Expand Down Expand Up @@ -102,6 +106,11 @@ public Optional<List<String>> certs() {
};
}

@Override
public Optional<String> tlsConfigurationName() {
return Optional.empty();
}

@Override
public ProxyConfig proxyOptions() {
return new ProxyConfig() {
Expand Down Expand Up @@ -133,4 +142,21 @@ public Optional<String> host() {
}
};
}

private static class NoopTlsConfigurationRegistry implements TlsConfigurationRegistry {
@Override
public Optional<TlsConfiguration> get(String name) {
return Optional.empty();
}

@Override
public Optional<TlsConfiguration> getDefault() {
return Optional.empty();
}

@Override
public void register(String name, TlsConfiguration configuration) {

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@ public Optional<List<String>> certs() {
};
}

@Override
public Optional<String> tlsConfigurationName() {
return Optional.empty();
}

@Override
public ProxyConfig proxyOptions() {
return new ProxyConfig() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@
*/
public interface TlsConfiguration {

static Optional<TlsConfiguration> from(TlsConfigurationRegistry registry, Optional<String> name) {
if (name.isPresent()) {
Optional<TlsConfiguration> maybeConfiguration = registry.get(name.get());
if (maybeConfiguration.isEmpty()) {
throw new IllegalStateException("Unable to find the TLS configuration for name " + name + ".");
}
return maybeConfiguration;
}
return Optional.empty();
}

/**
* Returns the key store.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public class OtelCollectorLifecycleManager implements QuarkusTestResourceLifecyc
private boolean enableTLS = false;
private boolean preventTrustCert = false;
private boolean enableCompression = false;
private String tlsRegistryName = null;
private Vertx vertx;

private HttpServer server;
Expand Down Expand Up @@ -77,6 +78,10 @@ public void init(Map<String, String> initArgs) {
if (initArgs.containsKey("protocol")) {
protocol = initArgs.get("protocol");
}

if (initArgs.containsKey("tlsRegistryName")) {
tlsRegistryName = initArgs.get("tlsRegistryName");
}
}

@Override
Expand Down Expand Up @@ -130,11 +135,21 @@ public Map<String, String> start() {
if (enableTLS) {
result.put("quarkus.otel.exporter.otlp.traces.endpoint",
"https://" + collector.getHost() + ":" + collector.getMappedPort(secureEndpointPort));
if (!preventTrustCert) {
result.put("quarkus.otel.exporter.otlp.traces.trust-cert.certs", serverTls.certificatePath());
if (tlsRegistryName != null) {
result.put("quarkus.otel.exporter.otlp.traces.tls-configuration-name", tlsRegistryName);
if (!preventTrustCert) {
result.put(String.format("quarkus.tls.%s.trust-store.pem.certs", tlsRegistryName),
serverTls.certificatePath());
}
result.put(String.format("quarkus.tls.%s.key-store.pem.0.cert", tlsRegistryName), clientTlS.certificatePath());
result.put(String.format("quarkus.tls.%s.key-store.pem.0.key", tlsRegistryName), clientTlS.privateKeyPath());
} else {
if (!preventTrustCert) {
result.put("quarkus.otel.exporter.otlp.traces.trust-cert.certs", serverTls.certificatePath());
}
result.put("quarkus.otel.exporter.otlp.traces.key-cert.certs", clientTlS.certificatePath());
result.put("quarkus.otel.exporter.otlp.traces.key-cert.keys", clientTlS.privateKeyPath());
}
result.put("quarkus.otel.exporter.otlp.traces.key-cert.certs", clientTlS.certificatePath());
result.put("quarkus.otel.exporter.otlp.traces.key-cert.keys", clientTlS.privateKeyPath());
} else {
result.put("quarkus.otel.exporter.otlp.traces.endpoint",
"http://" + collector.getHost() + ":" + collector.getMappedPort(inSecureEndpointPort));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.quarkus.it.opentelemetry.vertx.exporter.http;

import io.quarkus.it.opentelemetry.vertx.exporter.AbstractExporterTest;
import io.quarkus.it.opentelemetry.vertx.exporter.OtelCollectorLifecycleManager;
import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.common.ResourceArg;
import io.quarkus.test.junit.QuarkusTest;

@QuarkusTest
@QuarkusTestResource(value = OtelCollectorLifecycleManager.class, initArgs = {
@ResourceArg(name = "enableTLS", value = "true"),
@ResourceArg(name = "enableCompression", value = "true"),
@ResourceArg(name = "protocol", value = "http/protobuf"),
@ResourceArg(name = "tlsRegistryName", value = "otel")
}, restrictToAnnotatedClass = true)
public class HttpWithTLSWithCompressionUsingRegistryTest extends AbstractExporterTest {

}
Loading