Skip to content

Commit 78bf4f2

Browse files
committed
fix(sinks): separate Datadog validation from runtime construction
Signed-off-by: kurochan <[email protected]>
1 parent 304ef8f commit 78bf4f2

18 files changed

Lines changed: 594 additions & 281 deletions
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Datadog sink custom endpoints without a scheme now default to `https://`. Query parameters are
2+
removed when Vector appends its Datadog API path; endpoint query parameters are not supported for
3+
configuring Datadog API requests.
4+
5+
When migrating a configuration that relies on endpoint query parameters, remove the query string
6+
and use the Datadog sink's supported request settings or headers instead. Specify `http://` or
7+
`https://` explicitly when the endpoint must use a particular scheme.
8+
9+
authors: kurochan
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Prevent the `datadog_traces` sink from starting its APM statistics flusher while the sink is being
2+
built. The flusher now follows the sink lifecycle, avoiding leaked background tasks during
3+
configuration validation or a rolled-back reload. Shutdown waits only a bounded time for the final
4+
APM statistics flush when the endpoint is unreachable.
5+
6+
authors: kurochan
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Prevent configuration validation from panicking on macOS when a restricted environment has no
2+
available Keychain. Vector avoids loading platform root certificates when TLS certificate
3+
verification is disabled, unless a client identity requires native certificate-chain support.
4+
5+
authors: kurochan

lib/vector-core/src/tls/settings.rs

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -302,25 +302,17 @@ impl TlsSettings {
302302
}
303303
}
304304
}
305-
if self.authorities.is_empty() {
305+
if self.should_load_native_roots(for_server) {
306306
debug!("Fetching system root certs.");
307307

308308
cfg_if! {
309309
if #[cfg(windows)] {
310-
load_windows_certs(context).unwrap();
310+
load_windows_certs(context)?;
311311
} else if #[cfg(target_os = "macos")] {
312-
cfg_if! { // Panic in release builds, warn in debug builds.
313-
if #[cfg(debug_assertions)] {
314-
if let Err(error) = load_mac_certs(context) {
315-
warn!("Failed to load macOS certs: {error}");
316-
}
317-
} else {
318-
load_mac_certs(context).unwrap();
319-
}
320-
}
312+
load_mac_certs(context)?;
321313
}
322314
}
323-
} else {
315+
} else if !self.authorities.is_empty() {
324316
let mut store = X509StoreBuilder::new().context(NewStoreBuilderSnafu)?;
325317
for authority in &self.authorities {
326318
store
@@ -352,6 +344,11 @@ impl TlsSettings {
352344
Ok(())
353345
}
354346

347+
fn should_load_native_roots(&self, for_server: bool) -> bool {
348+
self.authorities.is_empty()
349+
&& (self.verify_certificate || (!for_server && self.identity.is_some()))
350+
}
351+
355352
/// Apply per-connection TLS settings.
356353
///
357354
/// `skip_server_name` must be set when the connection targets a forward proxy rather than the
@@ -839,6 +836,37 @@ mod test {
839836
assert_eq!(settings.authorities.len(), 0);
840837
}
841838

839+
#[test]
840+
fn apply_context_skips_system_roots_when_verification_is_disabled() {
841+
use openssl::ssl::SslMethod;
842+
843+
let settings = TlsSettings::from_options(Some(&TlsConfig {
844+
verify_certificate: Some(false),
845+
..Default::default()
846+
}))
847+
.expect("Failed to generate TLS settings");
848+
let mut context = SslContextBuilder::new(SslMethod::tls()).unwrap();
849+
850+
// In particular, this must not access the macOS keychain or Windows certificate store.
851+
settings
852+
.apply_context(&mut context)
853+
.expect("TLS context setup should not load native roots when verification is off");
854+
}
855+
856+
#[test]
857+
fn client_identity_loads_system_roots_when_verification_is_disabled() {
858+
let settings = TlsSettings::from_options(Some(&TlsConfig {
859+
verify_certificate: Some(false),
860+
crt_file: Some(TEST_PEM_CLIENT_CRT_PATH.into()),
861+
key_file: Some(TEST_PEM_CLIENT_KEY_PATH.into()),
862+
..Default::default()
863+
}))
864+
.expect("Failed to load client identity");
865+
866+
// Avoid native certificate-store access in this unit test.
867+
assert!(settings.should_load_native_roots(false));
868+
}
869+
842870
#[test]
843871
fn from_options_bad_certificate() {
844872
let options = TlsConfig {

src/sinks/datadog/events/config.rs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use http::Uri;
22
use indoc::indoc;
33
use tower::ServiceBuilder;
4-
use vector_lib::{config::proxy::ProxyConfig, configurable::configurable_component, schema};
4+
use vector_lib::{configurable::configurable_component, schema};
55
use vrl::value::Kind;
66

77
use super::{
@@ -23,7 +23,6 @@ use crate::{
2323
http::{HttpStatusRetryLogic, RetryStrategy},
2424
},
2525
},
26-
tls::MaybeTlsSettings,
2726
};
2827

2928
/// Configuration for the `datadog_events` sink.
@@ -64,12 +63,6 @@ impl DatadogEventsConfig {
6463
.into_uri())
6564
}
6665

67-
fn build_client(&self, proxy: &ProxyConfig) -> crate::Result<HttpClient> {
68-
let tls = MaybeTlsSettings::from_config(self.dd_common.tls.as_ref(), false)?;
69-
let client = HttpClient::new(tls, proxy)?;
70-
Ok(client)
71-
}
72-
7366
fn build_sink(
7467
&self,
7568
dd_common: &DatadogCommonConfig,
@@ -80,14 +73,13 @@ impl DatadogEventsConfig {
8073
let service =
8174
DatadogEventsService::new(endpoint, dd_common.default_api_key.clone(), client);
8275

83-
let request_settings = validated.request_settings.clone();
8476
let retry_logic = HttpStatusRetryLogic::new(
8577
|req: &DatadogEventsResponse| req.http_status,
8678
self.retry_strategy.clone(),
8779
);
8880

8981
let service = ServiceBuilder::new()
90-
.settings(request_settings, retry_logic)
82+
.settings(validated.request_settings.clone(), retry_logic)
9183
.service(service);
9284

9385
let sink = DatadogEventsSink { service };
@@ -145,9 +137,9 @@ impl ValidatedSink for DatadogEventsConfig {
145137
validated: &ValidatedEvents,
146138
cx: SinkContext,
147139
) -> crate::Result<(VectorSink, Healthcheck)> {
148-
let client = self.build_client(cx.proxy())?;
149-
let global = cx.extra_context.get_or_default::<datadog::Options>();
150-
let dd_common = self.dd_common.with_globals(global)?;
140+
let dd_common = self.dd_common.with_globals_from(&cx)?;
141+
// Events defaults to HTTP; explicit TLS configuration overrides it.
142+
let client = self.dd_common.build_client(cx.proxy(), false)?;
151143
let healthcheck = dd_common.build_healthcheck(client.clone())?;
152144
let endpoint = Self::events_endpoint(dd_common.endpoint.as_deref(), &dd_common.site)?;
153145
let sink = self.build_sink(&dd_common, client, validated, endpoint)?;

src/sinks/datadog/events/tests.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,30 @@ use vrl::event_path;
1010

1111
use super::*;
1212
use crate::{
13-
config::SinkConfig,
13+
config::{SinkConfig, SinkContext},
1414
event::EventArray,
15-
sinks::util::test::{build_test_server_status, load_sink},
15+
sinks::util::test::{build_test_server_status, load_sink, load_sink_with_context},
1616
test_util::{
1717
addr::next_addr,
1818
components::{self, COMPONENT_ERROR_TAGS, HTTP_SINK_TAGS},
1919
random_lines_with_stream,
2020
},
2121
};
2222

23+
#[tokio::test]
24+
async fn pure_validation_does_not_load_tls_files_but_full_build_does() {
25+
let config = indoc! {r#"
26+
default_api_key = "local-key"
27+
tls.enabled = true
28+
tls.ca_file = "/definitely/missing/vector-datadog-ca.pem"
29+
"#};
30+
let (config, cx) =
31+
load_sink_with_context::<DatadogEventsConfig>(config, SinkContext::default()).unwrap();
32+
33+
assert!(crate::config::ValidatedSink::validate(&config).is_ok());
34+
assert!(config.build(cx).await.is_err());
35+
}
36+
2337
fn random_events_with_stream(
2438
len: usize,
2539
count: usize,

0 commit comments

Comments
 (0)