Skip to content

Commit 2bdf726

Browse files
aqian01jszwedko
authored andcommitted
fix(agent-data-plane): avoid DNS for disabled ADP bootstrap (#2041)
## What changed - Gate remote-agent bootstrap on `data_plane.enabled` so default-disabled ADP exits before creating the Core Agent IPC client. - Add an explicit `HttpsCapableConnectorBuilder::without_dns_resolution()` mode. - Use no-DNS connector construction for Core Agent IPC, which targets `https://127.0.0.1:<cmd_port>` and does not require hostname resolution. - Avoid system DNS resolver construction for DNS-free connector transports such as Unix sockets and vsock. ## Why On hosts without nameservers in `/etc/resolv.conf`, ADP could fail during startup while constructing the HTTP connector for Core Agent IPC. This happened before ADP reached the disabled-exit path, creating noisy crash loops even when `data_plane.enabled` was false. ## Validation unit tests, integration test. Co-authored-by: andrew.qian <andrew.qian@datadoghq.com>
1 parent f546aa0 commit 2bdf726

6 files changed

Lines changed: 91 additions & 7 deletions

File tree

docker/Dockerfile.proxy-dumper

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@ FROM ${APP_IMAGE}
2020
# `root` user, we skip this step.
2121
#
2222
# For local builds, the regular Ubuntu application image needs to have the CA certificates installed, but it also uses
23-
# the `root` user, so we can install them without issue.
23+
# the `root` user, so we can install them without issue. Use the repository's available version because Ubuntu
24+
# repositories do not retain old exact package versions indefinitely.
2425
RUN test -d /usr/local/share/ca-certificates || apt-get update && \
25-
apt-get install -y --no-install-recommends ca-certificates=20240203 && \
26+
apt-get install -y --no-install-recommends ca-certificates && \
2627
apt-get clean
2728
COPY --from=builder /src/app/target/proxy-dumper /proxy-dumper
2829

docker/scripts/agent-data-plane/app/00-install-ca-certs.sh

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
# We only install them if they're missing. In CI, the application base image already ships CA
66
# certificates and may run as a non-root user, so we skip the install (and avoid needing root just to
77
# run apt-get). For local builds the plain Ubuntu base lacks them but runs as root, so the install
8-
# succeeds. The version is pinned to keep local builds reproducible.
8+
# succeeds. Use the repository's available version because Ubuntu repositories do not retain old
9+
# exact package versions indefinitely.
910

1011
set -eu
1112

@@ -14,6 +15,6 @@ if [ -d /usr/share/ca-certificates ]; then
1415
fi
1516

1617
apt-get update
17-
apt-get install --no-install-recommends -y ca-certificates=20240203
18+
apt-get install --no-install-recommends -y ca-certificates
1819
apt-get clean
1920
rm -rf /var/lib/apt/lists

lib/datadog-agent/commons/src/ipc/client/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ impl RemoteAgentClient {
6868
let auth_interceptor = BearerAuthInterceptor::from_file(&config.auth().auth_token_file_path()).await?;
6969
let ipc_cert_file_path = config.auth().ipc_cert_file_path();
7070
let client_tls_config = build_ipc_client_ipc_tls_config(ipc_cert_file_path).await?;
71-
let connector_builder = HttpsCapableConnectorBuilder::default();
71+
let connector_builder = HttpsCapableConnectorBuilder::default().without_dns_resolution();
7272
#[cfg(target_os = "linux")]
7373
let connector_builder = if let Some(addr) = config.vsock_addr()? {
7474
connector_builder.with_vsock_addr(addr)

lib/saluki-io/src/net/client/http/conn.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,7 @@ pub struct HttpsCapableConnectorBuilder {
421421
bytes_sent: Option<Counter>,
422422
error_telemetry: Option<HttpTransactionErrorTelemetry>,
423423
conn_age_limit: Option<Duration>,
424+
dns_resolution_disabled: bool,
424425
http_protocol: HttpProtocol,
425426
#[cfg(unix)]
426427
unix_socket_path: Option<PathBuf>,
@@ -476,6 +477,18 @@ impl HttpsCapableConnectorBuilder {
476477
self
477478
}
478479

480+
/// Disables DNS resolution for this connector.
481+
///
482+
/// This is intended for clients that only use transports or destinations that do not require
483+
/// DNS, such as Unix sockets, vsock, or literal-IP TCP endpoints. Hostname-based TCP
484+
/// destinations will fail to resolve when this is enabled.
485+
///
486+
/// Defaults to enabled.
487+
pub fn without_dns_resolution(mut self) -> Self {
488+
self.dns_resolution_disabled = true;
489+
self
490+
}
491+
479492
/// Sets a Unix domain socket path to route all connections through.
480493
///
481494
/// When set, the connector will connect to this Unix socket instead of performing DNS resolution
@@ -514,7 +527,13 @@ impl HttpsCapableConnectorBuilder {
514527
#[cfg(not(target_os = "linux"))]
515528
let vsock_only = false;
516529

517-
let hickory_resolver = if vsock_only {
530+
#[cfg(unix)]
531+
let unix_socket_only = self.unix_socket_path.is_some();
532+
#[cfg(not(unix))]
533+
let unix_socket_only = false;
534+
535+
let dns_resolution_disabled = self.dns_resolution_disabled || vsock_only || unix_socket_only;
536+
let hickory_resolver = if dns_resolution_disabled {
518537
HickoryResolver::noop()
519538
} else {
520539
build_dns_resolver(&self.error_telemetry)?
@@ -611,7 +630,7 @@ pub(super) fn check_connection_state(captured_conn: CaptureConnection) {
611630

612631
#[cfg(test)]
613632
mod tests {
614-
use super::{configure_tls_alpn_for_http_protocol, HttpProtocol};
633+
use super::{configure_tls_alpn_for_http_protocol, HttpProtocol, HttpsCapableConnectorBuilder};
615634

616635
fn empty_tls_config() -> rustls::ClientConfig {
617636
rustls::ClientConfig::builder_with_provider(default_crypto_provider().into())
@@ -645,6 +664,14 @@ mod tests {
645664
assert!(tls_config.alpn_protocols.is_empty());
646665
}
647666

667+
#[test]
668+
fn connector_builds_without_dns_resolution() {
669+
HttpsCapableConnectorBuilder::default()
670+
.without_dns_resolution()
671+
.build(empty_tls_config())
672+
.expect("connector should build with DNS resolution disabled");
673+
}
674+
648675
// vsock takes priority over unix when both are configured, matching Agent behavior.
649676
// We verify by checking the error does not mention "unix" — if unix had priority it would
650677
// fail with a socket-path error; vsock produces a connection or device error instead.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Issue: ADP/Core Agent IPC must not require system DNS.
2+
#
3+
# The Core Agent IPC endpoint is a literal loopback address (`https://127.0.0.1:<cmd_port>`),
4+
# so ADP should not need to load `/etc/resolv.conf` just to register with the Core Agent or
5+
# receive its initial configuration. This test clears the resolver config at container startup to
6+
# reproduce hosts where Hickory cannot load system DNS configuration.
7+
#
8+
# The test currently runs ADP in standalone mode until converged OTLP proxy endpoint ownership is
9+
# configurable; see the standalone-mode env comment below.
10+
11+
type: integration
12+
name: "adp-ipc-no-dns"
13+
description: "Verifies ADP can start when /etc/resolv.conf has no nameservers"
14+
timeout: 120s
15+
runtimes: [linux]
16+
17+
env:
18+
DD_API_KEY: "00000000000000000000000000000000"
19+
DD_HOSTNAME: "integration-test-ipc-no-dns"
20+
DD_DATA_PLANE_ENABLED: "true"
21+
# Run standalone for now because converged mode streams the Core Agent OTLP
22+
# receiver endpoints back to ADP. That prevents us from configuring ADP to own
23+
# the normal OTLP listener ports while the Core Agent listens on dummy upstream
24+
# ports for proxying.
25+
DD_DATA_PLANE_STANDALONE_MODE: "true"
26+
# OTLP proxy mode keeps ADP running without creating the normal Datadog forwarder,
27+
# so this test avoids normal intake DNS while /etc/resolv.conf is empty.
28+
DD_DATA_PLANE_DOGSTATSD_ENABLED: "false"
29+
DD_DATA_PLANE_OTLP_ENABLED: "true"
30+
DD_DATA_PLANE_OTLP_PROXY_ENABLED: "true"
31+
32+
container:
33+
files:
34+
- "empty-resolv-conf.sh:/etc/cont-init.d/01-empty-resolv-conf.sh"
35+
exposed_ports:
36+
- "58125/udp"
37+
38+
procedure:
39+
- parallel:
40+
- assertion: process_stable_for
41+
duration: 10s
42+
- assertion: log_contains
43+
pattern: "Topology healthy"
44+
timeout: 60s
45+
- assertion: log_not_contains
46+
pattern: "Failed to load system DNS configuration when creating DNS resolver for HTTP client"
47+
during: 10s
48+
- assertion: log_not_contains
49+
pattern: "panic|PANIC"
50+
regex: true
51+
during: 10s
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/sh
2+
set -eu
3+
4+
: > /etc/resolv.conf

0 commit comments

Comments
 (0)