Skip to content

Commit

Permalink
Add TlsConfigurationRegistry to OTel
Browse files Browse the repository at this point in the history
  • Loading branch information
geoand committed Jun 7, 2024
1 parent 60e1fe1 commit 269d8e5
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 36 deletions.
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 @@ -23,7 +23,7 @@ static Optional<TlsConfiguration> from(TlsConfigurationRegistry registry, Option
}
return maybeConfiguration;
}
return registry.getDefault();
return Optional.empty();
}

/**
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 {

}

0 comments on commit 269d8e5

Please sign in to comment.