Skip to content

Commit d7e1264

Browse files
authored
feat(infra_mode): add allowlist priority and excluded checks logic (#44740)
### What does this PR do? Adds support for prioritized allowlists per infrastructure mode and introduces an explicit exclusion list for integrations. ### Motivation This improves control over which checks are allowed to run in basic and other restricted modes, while keeping configuration flexible and explicit. ### Describe how you validated your changes CI ### Additional Notes None Co-authored-by: louis.coquerelle <louis.coquerelle@datadoghq.com>
1 parent b01a62c commit d7e1264

4 files changed

Lines changed: 180 additions & 12 deletions

File tree

pkg/collector/infra_mode.go

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,30 @@ import (
1515
// IsCheckAllowed returns true if the check is allowed.
1616
// When not in basic mode, all checks are allowed (returns true).
1717
// When in basic mode, only checks in the allowed list or starting with "custom_" are permitted.
18+
// Note: Legacy keys (excluded_checks, allowed_additional_checks) are aliased to mode-specific
19+
// keys in config.go via applyInfrastructureModeOverrides.
1820
func IsCheckAllowed(checkName string, cfg pkgconfigmodel.Reader) bool {
19-
// When not in basic mode, all checks are allowed
20-
if cfg.GetString("infrastructure_mode") != "basic" {
21-
return true
21+
if !cfg.GetBool("integration.enabled") {
22+
return false
23+
}
24+
25+
infraMode := cfg.GetString("infrastructure_mode")
26+
27+
// Check excluded list
28+
if slices.Contains(cfg.GetStringSlice("integration.excluded"), checkName) {
29+
return false
2230
}
2331

2432
// Allow all custom checks
2533
if strings.HasPrefix(checkName, "custom_") {
2634
return true
2735
}
2836

29-
// Check if it's in the allowed checks (default + additional)
30-
return slices.Contains(append(cfg.GetStringSlice("allowed_checks"), cfg.GetStringSlice("allowed_additional_checks")...), checkName)
37+
// If allowed checks is empty, all checks are allowed
38+
if allowedChecks := cfg.GetStringSlice("integration." + infraMode + ".allowed"); len(allowedChecks) == 0 || slices.Contains(allowedChecks, checkName) {
39+
return true
40+
}
41+
42+
// Check additional list
43+
return slices.Contains(cfg.GetStringSlice("integration.additional"), checkName)
3144
}

pkg/collector/infra_mode_test.go

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// Unless explicitly stated otherwise all files in this repository are licensed
2+
// under the Apache License Version 2.0.
3+
// This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
// Copyright 2016-present Datadog, Inc.
5+
6+
package collector
7+
8+
import (
9+
"testing"
10+
11+
"github.com/stretchr/testify/assert"
12+
13+
configmock "github.com/DataDog/datadog-agent/pkg/config/mock"
14+
pkgconfigmodel "github.com/DataDog/datadog-agent/pkg/config/model"
15+
)
16+
17+
func TestIsCheckAllowed(t *testing.T) {
18+
tests := []struct {
19+
name string
20+
checkName string
21+
setupCfg func(cfg pkgconfigmodel.Config)
22+
wantResult bool
23+
}{
24+
{
25+
name: "integration disabled returns false",
26+
checkName: "cpu",
27+
setupCfg: func(cfg pkgconfigmodel.Config) {
28+
cfg.Set("integration.enabled", false, pkgconfigmodel.SourceFile)
29+
},
30+
wantResult: false,
31+
},
32+
{
33+
name: "check in excluded list returns false",
34+
checkName: "disk",
35+
setupCfg: func(cfg pkgconfigmodel.Config) {
36+
cfg.Set("integration.enabled", true, pkgconfigmodel.SourceFile)
37+
cfg.Set("infrastructure_mode", "full", pkgconfigmodel.SourceFile)
38+
cfg.Set("integration.excluded", []string{"disk", "memory"}, pkgconfigmodel.SourceFile)
39+
},
40+
wantResult: false,
41+
},
42+
{
43+
name: "custom check is always allowed",
44+
checkName: "custom_mycheck",
45+
setupCfg: func(cfg pkgconfigmodel.Config) {
46+
cfg.Set("integration.enabled", true, pkgconfigmodel.SourceFile)
47+
cfg.Set("infrastructure_mode", "basic", pkgconfigmodel.SourceFile)
48+
},
49+
wantResult: true,
50+
},
51+
{
52+
name: "check in allowed list for basic mode returns true",
53+
checkName: "cpu",
54+
setupCfg: func(cfg pkgconfigmodel.Config) {
55+
cfg.Set("integration.enabled", true, pkgconfigmodel.SourceFile)
56+
cfg.Set("infrastructure_mode", "basic", pkgconfigmodel.SourceFile)
57+
cfg.Set("integration.basic.allowed", []string{"cpu", "memory"}, pkgconfigmodel.SourceFile)
58+
},
59+
wantResult: true,
60+
},
61+
{
62+
name: "check not in allowed list for basic mode returns false",
63+
checkName: "postgres",
64+
setupCfg: func(cfg pkgconfigmodel.Config) {
65+
cfg.Set("integration.enabled", true, pkgconfigmodel.SourceFile)
66+
cfg.Set("infrastructure_mode", "basic", pkgconfigmodel.SourceFile)
67+
cfg.Set("integration.basic.allowed", []string{"cpu", "memory"}, pkgconfigmodel.SourceFile)
68+
},
69+
wantResult: false,
70+
},
71+
{
72+
name: "check in additional list returns true",
73+
checkName: "postgres",
74+
setupCfg: func(cfg pkgconfigmodel.Config) {
75+
cfg.Set("integration.enabled", true, pkgconfigmodel.SourceFile)
76+
cfg.Set("infrastructure_mode", "basic", pkgconfigmodel.SourceFile)
77+
cfg.Set("integration.basic.allowed", []string{"cpu", "memory"}, pkgconfigmodel.SourceFile)
78+
cfg.Set("integration.additional", []string{"postgres"}, pkgconfigmodel.SourceFile)
79+
},
80+
wantResult: true,
81+
},
82+
{
83+
name: "excluded check takes precedence over custom prefix",
84+
checkName: "custom_excluded",
85+
setupCfg: func(cfg pkgconfigmodel.Config) {
86+
cfg.Set("integration.enabled", true, pkgconfigmodel.SourceFile)
87+
cfg.Set("infrastructure_mode", "full", pkgconfigmodel.SourceFile)
88+
cfg.Set("integration.excluded", []string{"custom_excluded"}, pkgconfigmodel.SourceFile)
89+
},
90+
wantResult: false,
91+
},
92+
{
93+
name: "end_user_device mode allows all checks",
94+
checkName: "any_check",
95+
setupCfg: func(cfg pkgconfigmodel.Config) {
96+
cfg.Set("integration.enabled", true, pkgconfigmodel.SourceFile)
97+
cfg.Set("infrastructure_mode", "end_user_device", pkgconfigmodel.SourceFile)
98+
},
99+
wantResult: true,
100+
},
101+
{
102+
name: "excluded takes precedence over allowed",
103+
checkName: "disk",
104+
setupCfg: func(cfg pkgconfigmodel.Config) {
105+
cfg.Set("integration.enabled", true, pkgconfigmodel.SourceFile)
106+
cfg.Set("infrastructure_mode", "basic", pkgconfigmodel.SourceFile)
107+
cfg.Set("integration.basic.allowed", []string{"cpu", "disk", "memory"}, pkgconfigmodel.SourceFile)
108+
cfg.Set("integration.excluded", []string{"disk"}, pkgconfigmodel.SourceFile)
109+
},
110+
wantResult: false,
111+
},
112+
}
113+
114+
for _, tt := range tests {
115+
t.Run(tt.name, func(t *testing.T) {
116+
cfg := configmock.New(t)
117+
tt.setupCfg(cfg)
118+
119+
result := IsCheckAllowed(tt.checkName, cfg)
120+
assert.Equal(t, tt.wantResult, result)
121+
})
122+
}
123+
}

pkg/config/setup/config.go

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,14 +1336,26 @@ func agent(config pkgconfigmodel.Setup) {
13361336
config.BindEnvAndSetDefault("allow_arbitrary_tags", false)
13371337
config.BindEnvAndSetDefault("use_proxy_for_cloud_metadata", false)
13381338

1339+
// Legacy alias for backward compatibility
1340+
// This applies to the current infrastructure_mode
1341+
config.BindEnvAndSetDefault("allowed_additional_checks", []string{})
1342+
1343+
config.BindEnvAndSetDefault("integration.enabled", true)
1344+
1345+
// integration.additional: additional checks to allow beyond the default set (user configured)
1346+
config.BindEnvAndSetDefault("integration.additional", []string{})
1347+
// integration.excluded: checks to exclude (user configured)
1348+
config.BindEnvAndSetDefault("integration.excluded", []string{})
1349+
13391350
// Infrastructure mode
13401351
// The infrastructure mode is used to determine the features that are available to the agent.
13411352
// The possible values are: full, basic, end_user_device.
13421353
config.BindEnvAndSetDefault("infrastructure_mode", "full")
13431354

1344-
// Infrastructure basic mode - allowed checks (UNDOCUMENTED)
1355+
// Infrastructure basic mode section [UNDOCUMENTED]
13451356
// Note: All checks starting with "custom_" are always allowed.
1346-
config.BindEnvAndSetDefault("allowed_checks", []string{
1357+
// integration.basic.allowed: default allowed checks (internal, should not need user configuration)
1358+
config.BindEnvAndSetDefault("integration.basic.allowed", []string{
13471359
"cpu",
13481360
"agent_telemetry",
13491361
"agentcrashdetect",
@@ -1369,11 +1381,6 @@ func agent(config pkgconfigmodel.Setup) {
13691381
"winproc",
13701382
})
13711383

1372-
// Infrastructure basic mode - additional checks
1373-
// When infrastructure_mode is set to "basic", only a limited set of checks are allowed to run.
1374-
// This setting allows customers to add additional checks to the allowlist beyond the default set.
1375-
config.BindEnvAndSetDefault("allowed_additional_checks", []string{})
1376-
13771384
// Configuration for TLS for outgoing connections
13781385
config.BindEnvAndSetDefault("min_tls_version", "tlsv1.2")
13791386

@@ -2815,6 +2822,13 @@ func toggleDefaultPayloads(config pkgconfigmodel.Config) {
28152822
func applyInfrastructureModeOverrides(config pkgconfigmodel.Config) {
28162823
infraMode := config.GetString("infrastructure_mode")
28172824

2825+
// Apply legacy alias: copy values from legacy key to integration.additional
2826+
// Legacy `allowed_additional_checks` -> `integration.additional`
2827+
if legacyAdditional := config.GetStringSlice("allowed_additional_checks"); len(legacyAdditional) > 0 {
2828+
combined := append(config.GetStringSlice("integration.additional"), legacyAdditional...)
2829+
config.Set("integration.additional", combined, pkgconfigmodel.SourceAgentRuntime)
2830+
}
2831+
28182832
if infraMode == "end_user_device" {
28192833
// Enable features for end_user_device mode
28202834
config.Set("process_config.process_collection.enabled", true, pkgconfigmodel.SourceInfraMode)

pkg/config/setup/config_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,24 @@ func TestNetworkPathDefaults(t *testing.T) {
670670
assert.Equal(t, false, config.GetBool("network_path.collector.disable_windows_driver"))
671671
}
672672

673+
func TestInfrastructureModeLegacyAliases(t *testing.T) {
674+
// Test that legacy allowed_additional_checks is aliased to mode-specific
675+
// key via applyInfrastructureModeOverrides
676+
datadogYaml := `
677+
infrastructure_mode: basic
678+
allowed_additional_checks:
679+
- prometheus
680+
- redis
681+
`
682+
config := confFromYAML(t, datadogYaml)
683+
applyInfrastructureModeOverrides(config)
684+
685+
// Legacy allowed_additional_checks should be merged into integration.additional
686+
additional := config.GetStringSlice("integration.additional")
687+
assert.Contains(t, additional, "prometheus")
688+
assert.Contains(t, additional, "redis")
689+
}
690+
673691
func TestUsePodmanLogsAndDockerPathOverride(t *testing.T) {
674692
// If use_podman_logs is true and docker_path_override is set, the config should return an error
675693
datadogYaml := `

0 commit comments

Comments
 (0)