Skip to content

Commit 02d2f08

Browse files
1 parent ce40c73 commit 02d2f08

4 files changed

Lines changed: 29 additions & 109 deletions

File tree

comp/dataplane/preflightmode/impl/config.go

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -116,22 +116,13 @@ var preflightModeGlobalOverrides = map[string]any{
116116
// buildPreflightConfig returns the configuration ADP should run with during a preflight mode
117117
// pre-flight.
118118
//
119-
// The Agent configuration as the operator supplied it is used as the base, and overrides are
120-
// applied on top of it: this ensures that ADP is configured as close as possible to how it would
121-
// be when running normally, with only the necessary changes to run it in "preflight" mode:
122-
// don't take over DSD, don't run any other pipelines, don't log to disk, and don't reserve buffer
123-
// pools sized for traffic that a one-metric pre-flight will never see.
124-
//
125-
// Deliberately AllSettingsWithoutDefault and not AllSettings. A normally-supervised ADP is started
126-
// with `--config /etc/datadog-agent/datadog.yaml`, so it sees the operator's settings and fills in
127-
// the rest from its own defaults; handing it the Agent's defaults instead would be a different
128-
// configuration, not a more faithful one. It is also incorrect: AllSettings renders a default
129-
// indistinguishably from a value the operator asked for, and dd_url's default is a non-empty
130-
// https://app.datadoghq.com. Since an explicit dd_url beats `site` in ADP just as it does in the
131-
// Core Agent, a site-only config came out of AllSettings pointing the pre-flight -- metrics and
132-
// API key both -- at US1 no matter what site the operator had configured.
119+
// The full Agent configuration as it exists at the time of this call is used as the base,
120+
// and overrides are applied on top of it: this ensures that ADP is configured as close as possible
121+
// to how it would be when running normally, with only the necessary changes to run it in "preflight" mode:
122+
// don't take over DSD, don't run any other pipelines, don't log to disk, and don't reserve buffer pools
123+
// sized for traffic that a one-metric pre-flight will never see.
133124
func buildPreflightConfig(cfg pkgconfigmodel.Reader, l listener) map[string]any {
134-
out := cfg.AllSettingsWithoutDefault()
125+
out := cfg.AllSettings()
135126
if out == nil {
136127
out = map[string]any{}
137128
}
@@ -157,14 +148,12 @@ func buildPreflightConfig(cfg pkgconfigmodel.Reader, l listener) map[string]any
157148

158149
// writePreflightConfig renders the preflight configuration into workDir and returns its path.
159150
//
160-
// The file holds every setting the operator supplied -- see buildPreflightConfig for why the
161-
// Agent's own defaults are deliberately left out -- so every credential the Agent was given in
162-
// plain text -- api_key, app_key, proxy credentials, additional_endpoints keys -- ends up in it.
163-
// Not, however, anything from a secret backend: dropping the defaults layer does not drop the
164-
// secrets layer, so AllSettingsWithoutDefault would still render a resolved secret, but
165-
// isEligible refuses to run the pre-flight at all when secrets are in use, precisely so that
166-
// this file cannot be how a secret first reaches the disk. The working directory is removed when
167-
// the run finishes, and again from stop if the run does not unwind in time.
151+
// The file holds the Agent's entire resolved configuration, so every credential the Agent was
152+
// given in plain text -- api_key, app_key, proxy credentials, additional_endpoints keys -- ends
153+
// up in it. Not, however, anything from a secret backend: AllSettings would merge the secrets
154+
// layer, but isEligible refuses to run the pre-flight at all when secrets are in use, precisely
155+
// so that this file cannot be how a secret first reaches the disk. The working directory is
156+
// removed when the run finishes, and again from stop if the run does not unwind in time.
168157
//
169158
// The 0600 below is what restricts the file on Unix. It does nothing on Windows, where the
170159
// mode is not an access control mechanism at all; there the file is covered by the ACL

comp/dataplane/preflightmode/impl/config_test.go

Lines changed: 15 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -73,84 +73,26 @@ func TestBuildPreflightConfigCarriesOperatorSettings(t *testing.T) {
7373
requireEq(t, got, "proxy.https", "http://proxy.internal:3128")
7474
}
7575

76-
// TestBuildPreflightConfigCarriesOnlyOperatorSettings documents the choice to base the preflight
77-
// config on AllSettingsWithoutDefault: everything the operator configured, and nothing they did
78-
// not.
76+
// TestBuildPreflightConfigCarriesTheWholeAgentConfig documents the deliberate choice to base
77+
// the preflight config on AllSettings, defaults included, rather than only the settings the
78+
// operator touched.
7979
//
80-
// The point of the pre-flight is for ADP to see the configuration it would really run with, and a
81-
// normally-supervised ADP is started with `--config /etc/datadog-agent/datadog.yaml` -- the
82-
// operator's settings, with ADP's own defaults underneath. Passing the Agent's defaults instead
83-
// would be a different configuration, not a more faithful one, and for dd_url it was an actively
84-
// wrong one (see TestBuildPreflightConfigDropsUnsetDDURL).
85-
//
86-
// Passing the operator's settings through wholesale is safe because ADP ignores keys it does not
87-
// recognise: verified against agent-data-plane 1.4.0 by running it with the full Core Agent
88-
// config, including Core-Agent-only sections, with no resulting warning or error (see
89-
// TestBuildPreflightConfigPassesThroughCoreAgentOnlySettings).
90-
func TestBuildPreflightConfigCarriesOnlyOperatorSettings(t *testing.T) {
91-
cfg := configmock.New(t)
92-
cfg.Set("forwarder_timeout", 42, pkgconfigmodel.SourceFile)
93-
94-
got := buildPreflightConfig(cfg, newListener(t.TempDir()))
95-
96-
// A setting the operator tuned reaches ADP, so it forwards the way the Agent would.
97-
requireEq(t, got, "forwarder_timeout", 42)
98-
99-
// One they never touched does not, so ADP applies its own default rather than the Agent's.
100-
_, present := get(t, got, "logs_config")
101-
assert.False(t, present, "a section the operator never configured should not reach ADP")
102-
}
103-
104-
// TestBuildPreflightConfigCarriesEnvSourcedSettings is the case that matters most in a container,
105-
// where the operator configures the Agent entirely through DD_ variables and datadog.yaml is
106-
// close to empty.
107-
//
108-
// It is load-bearing for the pre-flight specifically: childEnv strips the whole DD_ namespace from
109-
// the preflight process, so the generated file is the only channel these settings have. A dump
110-
// that dropped them would leave ADP with no api_key and no site at all.
111-
func TestBuildPreflightConfigCarriesEnvSourcedSettings(t *testing.T) {
112-
t.Setenv("DD_API_KEY", "0123456789abcdef0123456789abcdef")
113-
t.Setenv("DD_SITE", "datad0g.com")
114-
115-
cfg := configmock.New(t)
116-
// The Agent resolves DD_PROXY_* into the config at startup rather than leaving it on the env
117-
// layer, writing it back as config-post-init; mirror that here so the dump under test is the
118-
// one the real preflight sees.
119-
cfg.Set("proxy.https", "http://proxy.internal:3128", pkgconfigmodel.SourceConfigPostInit)
120-
121-
got := buildPreflightConfig(cfg, newListener(t.TempDir()))
122-
123-
requireEq(t, got, "api_key", "0123456789abcdef0123456789abcdef")
124-
requireEq(t, got, "site", "datad0g.com")
125-
requireEq(t, got, "proxy.https", "http://proxy.internal:3128")
126-
}
127-
128-
// TestBuildPreflightConfigDropsUnsetDDURL is the regression this policy exists for.
129-
//
130-
// dd_url's default is a non-empty https://app.datadoghq.com, and an explicit dd_url beats `site`
131-
// in ADP just as it does in the Core Agent. Rendered as a default by AllSettings, it pointed the
132-
// pre-flight -- metrics and API key both -- at US1 regardless of the configured site.
133-
func TestBuildPreflightConfigDropsUnsetDDURL(t *testing.T) {
134-
cfg := configmock.New(t)
135-
cfg.Set("site", "datad0g.com", pkgconfigmodel.SourceFile)
136-
137-
got := buildPreflightConfig(cfg, newListener(t.TempDir()))
138-
139-
_, present := get(t, got, "dd_url")
140-
assert.False(t, present, "an unset dd_url must not reach ADP as though it were configured")
141-
requireEq(t, got, "site", "datad0g.com")
142-
}
143-
144-
// TestBuildPreflightConfigKeepsConfiguredDDURL is the other half: a dd_url the operator really set
145-
// is part of the configuration ADP is meant to run against, and must survive.
146-
func TestBuildPreflightConfigKeepsConfiguredDDURL(t *testing.T) {
80+
// The point of the pre-flight is for ADP to see the configuration it would really run with,
81+
// and passing everything through is the closest approximation. It is safe because ADP
82+
// ignores keys it does not recognise: verified against agent-data-plane 1.4.0 by running it
83+
// with the full Core Agent config, including Core-Agent-only sections, with no resulting
84+
// warning or error (see TestBuildPreflightConfigPassesThroughCoreAgentOnlySettings).
85+
func TestBuildPreflightConfigCarriesTheWholeAgentConfig(t *testing.T) {
14786
cfg := configmock.New(t)
148-
cfg.Set("site", "datad0g.com", pkgconfigmodel.SourceFile)
149-
cfg.Set("dd_url", "https://app.datad0g.com", pkgconfigmodel.SourceFile)
15087

15188
got := buildPreflightConfig(cfg, newListener(t.TempDir()))
15289

153-
requireEq(t, got, "dd_url", "https://app.datad0g.com")
90+
// Defaults ADP shares with the Agent come through, so it forwards the way the Agent
91+
// would.
92+
_, present := get(t, got, "forwarder_timeout")
93+
assert.True(t, present, "the Agent's forwarder settings should reach ADP")
94+
_, present = get(t, got, "site")
95+
assert.True(t, present, "the Agent's site should reach ADP")
15496
}
15597

15698
func TestBuildPreflightConfigOverrides(t *testing.T) {

comp/dataplane/preflightmode/impl/eligible.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ const (
6161
// secretsInUse reports whether the Agent's configuration involves secrets at all, along with a human-readable reason
6262
// when it does.
6363
//
64-
// This is a gate on preflight mode because the pre-flight writes the Agent's configuration as the operator supplied it
65-
// to disk for ADP to read (see writePreflightConfig). Anything the secret resolver pulled into memory would therefore be
64+
// This is a gate on preflight mode because the pre-flight writes the Agent's entire resolved configuration to disk for
65+
// ADP to read (see writePreflightConfig). Anything the secret resolver pulled into memory would therefore be
6666
// materialized in plaintext in a file. The working directory is locked down to the Agent's own account and removed when
6767
// the run finishes, but a value the operator deliberately kept out of any file on the host should not be written to one
6868
// for the sake of a pre-flight check that only exists until ADP goes GA. So when secrets are involved we skip the

releasenotes/notes/adp-preflight-respect-site-75be9ee772bef041.yaml

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)