Skip to content

Commit 9650783

Browse files
authored
feat: opentelemetry-otlp: Add provider-agnostic TLS feature for custom crypto backends (#3423)
1 parent 4a3aa77 commit 9650783

4 files changed

Lines changed: 77 additions & 14 deletions

File tree

opentelemetry-otlp/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## vNext
44

5+
- Add `tls-provider-agnostic` feature flag for environments that require a custom crypto backend (e.g., OpenSSL for FIPS compliance). Enables TLS code paths without bundling `ring` or `aws-lc-rs`.
56
- Add `build()` directly on `SpanExporterBuilder`, `MetricExporterBuilder`, and `LogExporterBuilder`
67
(before selecting a transport), which auto-selects the transport based on the
78
`OTEL_EXPORTER_OTLP_PROTOCOL` environment variable or enabled features.

opentelemetry-otlp/Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,13 @@ experimental-grpc-retry = ["grpc-tonic", "opentelemetry_sdk/experimental_async_r
8080
# http compression
8181
gzip-http = ["flate2"]
8282
zstd-http = ["zstd"]
83-
tls = ["tls-ring"] # Deprecated: use tls-ring or tls-aws-lc.
83+
tls = ["tls-ring"] # Deprecated: use tls-ring or tls-aws-lc or tls-provider-agnostic
8484
tls-ring = ["tonic/tls-ring"]
8585
tls-aws-lc = ["tonic/tls-aws-lc"]
86+
# Provider-agnostic TLS: enables TLS code paths without bundling a specific
87+
# crypto provider. Use this when you install a
88+
# CryptoProvider globally (e.g., via rustls-openssl for FIPS/OpenSSL environments).
89+
tls-provider-agnostic = ["tonic/_tls-any"]
8690
tls-roots = ["tonic/tls-native-roots"]
8791
tls-webpki-roots = ["tonic/tls-webpki-roots"]
8892

opentelemetry-otlp/src/exporter/tonic/mod.rs

Lines changed: 62 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ use tonic::codec::CompressionEncoding;
88
use tonic::metadata::{KeyAndValueRef, MetadataMap};
99
use tonic::service::Interceptor;
1010
use tonic::transport::Channel;
11-
#[cfg(any(feature = "tls", feature = "tls-ring", feature = "tls-aws-lc"))]
11+
#[cfg(any(
12+
feature = "tls",
13+
feature = "tls-ring",
14+
feature = "tls-aws-lc",
15+
feature = "tls-provider-agnostic"
16+
))]
1217
use tonic::transport::ClientTlsConfig;
1318

1419
use super::{default_headers, parse_header_string, OTEL_EXPORTER_OTLP_GRPC_ENDPOINT_DEFAULT};
@@ -52,7 +57,12 @@ pub(crate) struct TonicConfig {
5257
/// Custom metadata entries to send to the collector.
5358
pub(crate) metadata: Option<MetadataMap>,
5459
/// TLS settings for the collector endpoint.
55-
#[cfg(any(feature = "tls", feature = "tls-ring", feature = "tls-aws-lc"))]
60+
#[cfg(any(
61+
feature = "tls",
62+
feature = "tls-ring",
63+
feature = "tls-aws-lc",
64+
feature = "tls-provider-agnostic"
65+
))]
5666
pub(crate) tls_config: Option<ClientTlsConfig>,
5767
/// The compression algorithm to use when communicating with the collector.
5868
pub(crate) compression: Option<Compression>,
@@ -90,7 +100,7 @@ impl TryFrom<Compression> for tonic::codec::CompressionEncoding {
90100
///
91101
/// It allows you to
92102
/// - add additional metadata
93-
/// - set tls config (via the `tls-ring` or `tls-aws-lc` features)
103+
/// - set tls config (via the `tls-ring`, `tls-aws-lc`, or `tls-provider-agnostic` features)
94104
/// - specify custom [channel]s
95105
///
96106
/// [tonic]: <https://github.com/hyperium/tonic>
@@ -148,7 +158,12 @@ impl Default for TonicExporterBuilder {
148158
.try_into()
149159
.expect("Invalid tonic headers"),
150160
)),
151-
#[cfg(any(feature = "tls", feature = "tls-ring", feature = "tls-aws-lc"))]
161+
#[cfg(any(
162+
feature = "tls",
163+
feature = "tls-ring",
164+
feature = "tls-aws-lc",
165+
feature = "tls-provider-agnostic"
166+
))]
152167
tls_config: None,
153168
compression: None,
154169
channel: Option::default(),
@@ -244,20 +259,30 @@ impl TonicExporterBuilder {
244259
.scheme()
245260
.is_some_and(|s| *s == http::uri::Scheme::HTTPS);
246261

247-
#[cfg(not(any(feature = "tls", feature = "tls-ring", feature = "tls-aws-lc")))]
262+
#[cfg(not(any(
263+
feature = "tls",
264+
feature = "tls-ring",
265+
feature = "tls-aws-lc",
266+
feature = "tls-provider-agnostic"
267+
)))]
248268
if is_https {
249269
return Err(ExporterBuildError::InvalidConfig {
250270
name: "endpoint".to_string(),
251271
reason: format!(
252272
"endpoint '{}' uses HTTPS but no TLS feature is enabled; \
253-
enable one of the `tls-ring` or `tls-aws-lc` features on `opentelemetry-otlp`",
273+
enable one of the `tls-ring`, `tls-aws-lc`, or `tls-provider-agnostic` features on `opentelemetry-otlp`",
254274
endpoint_clone
255275
),
256276
});
257277
}
258278
let timeout = resolve_timeout(signal_timeout_var, config.timeout.as_ref());
259279

260-
#[cfg(any(feature = "tls", feature = "tls-ring", feature = "tls-aws-lc"))]
280+
#[cfg(any(
281+
feature = "tls",
282+
feature = "tls-ring",
283+
feature = "tls-aws-lc",
284+
feature = "tls-provider-agnostic"
285+
))]
261286
let channel = match self.tonic_config.tls_config {
262287
Some(tls_config) => endpoint
263288
.tls_config(tls_config)
@@ -270,7 +295,12 @@ impl TonicExporterBuilder {
270295
.timeout(timeout)
271296
.connect_lazy();
272297

273-
#[cfg(not(any(feature = "tls", feature = "tls-ring", feature = "tls-aws-lc")))]
298+
#[cfg(not(any(
299+
feature = "tls",
300+
feature = "tls-ring",
301+
feature = "tls-aws-lc",
302+
feature = "tls-provider-agnostic"
303+
)))]
274304
let channel = endpoint.timeout(timeout).connect_lazy();
275305

276306
otel_debug!(name: "TonicChannelBuilt", endpoint = endpoint_clone, timeout_in_millisecs = timeout.as_millis(), compression = format!("{:?}", compression), headers = format!("{:?}", headers_for_logging));
@@ -547,7 +577,12 @@ impl HasTonicConfig for TonicExporterBuilder {
547577
/// ```
548578
pub trait WithTonicConfig {
549579
/// Set the TLS settings for the collector endpoint.
550-
#[cfg(any(feature = "tls", feature = "tls-ring", feature = "tls-aws-lc"))]
580+
#[cfg(any(
581+
feature = "tls",
582+
feature = "tls-ring",
583+
feature = "tls-aws-lc",
584+
feature = "tls-provider-agnostic"
585+
))]
551586
fn with_tls_config(self, tls_config: ClientTlsConfig) -> Self;
552587

553588
/// Set custom metadata entries to send to the collector.
@@ -660,7 +695,12 @@ pub trait WithTonicConfig {
660695
}
661696

662697
impl<B: HasTonicConfig> WithTonicConfig for B {
663-
#[cfg(any(feature = "tls", feature = "tls-ring", feature = "tls-aws-lc"))]
698+
#[cfg(any(
699+
feature = "tls",
700+
feature = "tls-ring",
701+
feature = "tls-aws-lc",
702+
feature = "tls-provider-agnostic"
703+
))]
664704
fn with_tls_config(mut self, tls_config: ClientTlsConfig) -> Self {
665705
self.tonic_config().tls_config = Some(tls_config);
666706
self
@@ -970,7 +1010,12 @@ mod tests {
9701010
}
9711011

9721012
#[test]
973-
#[cfg(not(any(feature = "tls", feature = "tls-ring", feature = "tls-aws-lc")))]
1013+
#[cfg(not(any(
1014+
feature = "tls",
1015+
feature = "tls-ring",
1016+
feature = "tls-aws-lc",
1017+
feature = "tls-provider-agnostic"
1018+
)))]
9741019
fn test_https_endpoint_errors_without_tls_feature() {
9751020
use crate::exporter::ExporterBuildError;
9761021
use crate::SpanExporter;
@@ -995,7 +1040,12 @@ mod tests {
9951040
}
9961041

9971042
#[tokio::test]
998-
#[cfg(any(feature = "tls-ring", feature = "tls-aws-lc"))]
1043+
#[cfg(any(
1044+
feature = "tls",
1045+
feature = "tls-ring",
1046+
feature = "tls-aws-lc",
1047+
feature = "tls-provider-agnostic"
1048+
))]
9991049
async fn test_https_endpoint_succeeds_with_tls_feature() {
10001050
use crate::SpanExporter;
10011051
use crate::WithExportConfig;

opentelemetry-otlp/src/lib.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,9 @@
271271
//! * `zstd-tonic`: Use zstd compression for `tonic` grpc layer.
272272
//! * `tls-ring`: Enable rustls TLS support using ring for `tonic`.
273273
//! * `tls-aws-lc`: Enable rustls TLS support using aws-lc for `tonic`.
274+
//! * `tls-provider-agnostic`: Provider-agnostic TLS — enables TLS code paths without bundling a specific
275+
//! crypto provider. Use this when you install a `CryptoProvider` globally
276+
//! (e.g., via `rustls-openssl` for FIPS/OpenSSL environments).
274277
//! * `tls` (deprecated): Use `tls-ring` or `tls-aws-lc` instead.
275278
//! * `tls-roots`: Adds system trust roots to rustls-based gRPC clients using the rustls-native-certs crate (use with `tls-ring` or `tls-aws-lc`).
276279
//! * `tls-webpki-roots`: Embeds Mozilla's trust roots to rustls-based gRPC clients using the webpki-roots crate (use with `tls-ring` or `tls-aws-lc`).
@@ -811,7 +814,12 @@ pub mod tonic_types {
811814
}
812815

813816
/// Re-exported types from `tonic::transport`.
814-
#[cfg(any(feature = "tls", feature = "tls-ring", feature = "tls-aws-lc"))]
817+
#[cfg(any(
818+
feature = "tls",
819+
feature = "tls-ring",
820+
feature = "tls-aws-lc",
821+
feature = "tls-provider-agnostic"
822+
))]
815823
pub mod transport {
816824
#[doc(no_inline)]
817825
pub use tonic::transport::{Certificate, ClientTlsConfig, Identity};

0 commit comments

Comments
 (0)