diff --git a/cmd/agent/api/internal/agent/agent.go b/cmd/agent/api/internal/agent/agent.go index ec5888d3c099ef..abe8b7a036c0b0 100644 --- a/cmd/agent/api/internal/agent/agent.go +++ b/cmd/agent/api/internal/agent/agent.go @@ -25,6 +25,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/common/signals" "github.com/DataDog/datadog-agent/cmd/agent/gui" "github.com/DataDog/datadog-agent/comp/core/flare" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/comp/core/workloadmeta" dogstatsdServer "github.com/DataDog/datadog-agent/comp/dogstatsd/server" dogstatsddebug "github.com/DataDog/datadog-agent/comp/dogstatsd/serverDebug" @@ -42,7 +43,6 @@ import ( "github.com/DataDog/datadog-agent/pkg/gohai" "github.com/DataDog/datadog-agent/pkg/logs/diagnostic" "github.com/DataDog/datadog-agent/pkg/metadata/inventories" - "github.com/DataDog/datadog-agent/pkg/secrets" "github.com/DataDog/datadog-agent/pkg/status" "github.com/DataDog/datadog-agent/pkg/status/health" "github.com/DataDog/datadog-agent/pkg/tagger" @@ -66,6 +66,7 @@ func SetupHandlers( hostMetadata host.Component, invAgent inventoryagent.Component, invHost inventoryhost.Component, + secretResolver secrets.Component, ) *mux.Router { r.HandleFunc("/version", common.GetVersion).Methods("GET") @@ -89,7 +90,7 @@ func SetupHandlers( r.HandleFunc("/workload-list", func(w http.ResponseWriter, r *http.Request) { getWorkloadList(w, r, wmeta) }).Methods("GET") - r.HandleFunc("/secrets", secretInfo).Methods("GET") + r.HandleFunc("/secrets", func(w http.ResponseWriter, r *http.Request) { secretInfo(w, r, secretResolver) }).Methods("GET") r.HandleFunc("/metadata/{payload}", func(w http.ResponseWriter, r *http.Request) { metadataPayload(w, r, hostMetadata, invAgent, invHost) }).Methods("GET") r.HandleFunc("/diagnose", func(w http.ResponseWriter, r *http.Request) { getDiagnose(w, r, senderManager) }).Methods("POST") @@ -427,8 +428,8 @@ func getWorkloadList(w http.ResponseWriter, r *http.Request, wmeta workloadmeta. w.Write(jsonDump) } -func secretInfo(w http.ResponseWriter, r *http.Request) { - secrets.GetDebugInfo(w) +func secretInfo(w http.ResponseWriter, _ *http.Request, secretResolver secrets.Component) { + secretResolver.GetDebugInfo(w) } func metadataPayload(w http.ResponseWriter, r *http.Request, hostMetadataComp host.Component, invAgent inventoryagent.Component, invHost inventoryhost.Component) { diff --git a/cmd/agent/api/server.go b/cmd/agent/api/server.go index 3e187d870cf3e4..0f6eb8e925ef9c 100644 --- a/cmd/agent/api/server.go +++ b/cmd/agent/api/server.go @@ -29,6 +29,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/api/internal/agent" "github.com/DataDog/datadog-agent/cmd/agent/api/internal/check" "github.com/DataDog/datadog-agent/comp/core/flare" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/comp/core/workloadmeta" workloadmetaServer "github.com/DataDog/datadog-agent/comp/core/workloadmeta/server" "github.com/DataDog/datadog-agent/comp/dogstatsd/replay" @@ -64,6 +65,7 @@ func StartServer( hostMetadata host.Component, invAgent inventoryagent.Component, invHost inventoryhost.Component, + secretResolver secrets.Component, ) error { err := initializeTLS() if err != nil { @@ -146,6 +148,7 @@ func StartServer( hostMetadata, invAgent, invHost, + secretResolver, ))) mux.Handle("/check/", http.StripPrefix("/check", check.SetupHandlers(checkMux))) mux.Handle("/", gwmux) diff --git a/cmd/agent/command/command.go b/cmd/agent/command/command.go index e17bc534bd8b48..c3c28178a118ef 100644 --- a/cmd/agent/command/command.go +++ b/cmd/agent/command/command.go @@ -46,7 +46,7 @@ type SubcommandFactory func(globalParams *GlobalParams) []*cobra.Command // without secrets and logger disabled). func GetDefaultCoreBundleParams(globalParams *GlobalParams) core.BundleParams { return core.BundleParams{ - ConfigParams: config.NewAgentParamsWithoutSecrets(globalParams.ConfFilePath), + ConfigParams: config.NewAgentParams(globalParams.ConfFilePath), LogParams: log.ForOneShot(LoggerName, "off", true)} } diff --git a/cmd/agent/common/autodiscovery.go b/cmd/agent/common/autodiscovery.go index 81a02ad1d8c365..0b3d466efca72f 100644 --- a/cmd/agent/common/autodiscovery.go +++ b/cmd/agent/common/autodiscovery.go @@ -14,6 +14,7 @@ import ( "go.uber.org/atomic" utilserror "k8s.io/apimachinery/pkg/util/errors" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/autodiscovery" "github.com/DataDog/datadog-agent/pkg/autodiscovery/integration" "github.com/DataDog/datadog-agent/pkg/autodiscovery/providers" @@ -37,8 +38,8 @@ var ( legacyProviders = []string{"kubelet", "container", "docker"} ) -func setupAutoDiscovery(confSearchPaths []string, metaScheduler *scheduler.MetaScheduler) *autodiscovery.AutoConfig { - ad := autodiscovery.NewAutoConfig(metaScheduler) +func setupAutoDiscovery(confSearchPaths []string, metaScheduler *scheduler.MetaScheduler, secretResolver secrets.Component) *autodiscovery.AutoConfig { + ad := autodiscovery.NewAutoConfig(metaScheduler, secretResolver) providers.InitConfigFilesReader(confSearchPaths) ad.AddConfigProvider( providers.NewFileConfigProvider(), diff --git a/cmd/agent/common/helpers.go b/cmd/agent/common/helpers.go index d381a2739c611f..1e501f6afe9a56 100644 --- a/cmd/agent/common/helpers.go +++ b/cmd/agent/common/helpers.go @@ -13,30 +13,21 @@ import ( "strings" "github.com/DataDog/datadog-agent/cmd/agent/common/path" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/autodiscovery/integration" "github.com/DataDog/datadog-agent/pkg/config" "github.com/DataDog/datadog-agent/pkg/config/model" "github.com/DataDog/datadog-agent/pkg/config/settings" "github.com/DataDog/datadog-agent/pkg/util/log" + "github.com/DataDog/datadog-agent/pkg/util/optional" "github.com/DataDog/viper" ) -// SetupConfigWithWarnings fires up the configuration system and returns warnings if any. -func SetupConfigWithWarnings(confFilePath, configName string) (*config.Warnings, error) { - return setupConfig(config.Datadog, "datadog.yaml", confFilePath, configName, false, true, config.SystemProbe.GetEnvVars()) -} - -// SetupConfigWithoutSecrets fires up the configuration system without secrets support -func SetupConfigWithoutSecrets(confFilePath string, configName string) error { - _, err := setupConfig(config.Datadog, "datadog.yaml", confFilePath, configName, true, true, config.SystemProbe.GetEnvVars()) - return err -} - -func setupConfig(cfg config.Config, origin string, confFilePath string, configName string, withoutSecrets bool, failOnMissingFile bool, additionalKnownEnvVars []string) (*config.Warnings, error) { - if configName != "" { - cfg.SetConfigName(configName) - } +// SetupConfigForTest fires up the configuration system and returns warnings if any. +func SetupConfigForTest(confFilePath string) (*config.Warnings, error) { + cfg := config.Datadog + origin := "datadog.yaml" // set the paths where a config file is expected if len(confFilePath) != 0 { // if the configuration file path was supplied on the command line, @@ -49,10 +40,10 @@ func setupConfig(cfg config.Config, origin string, confFilePath string, configNa } cfg.AddConfigPath(path.DefaultConfPath) // load the configuration - warnings, err := config.LoadDatadogCustom(cfg, origin, !withoutSecrets, nil) + warnings, err := config.LoadDatadogCustom(cfg, origin, optional.NewNoneOption[secrets.Component](), nil) // If `!failOnMissingFile`, do not issue an error if we cannot find the default config file. var e viper.ConfigFileNotFoundError - if err != nil && (failOnMissingFile || !errors.As(err, &e) || confFilePath != "") { + if err != nil && (!errors.As(err, &e) || confFilePath != "") { // special-case permission-denied with a clearer error message if errors.Is(err, fs.ErrPermission) { if runtime.GOOS == "windows" { diff --git a/cmd/agent/common/import.go b/cmd/agent/common/import.go index 89e00285bb5f96..8c540dfd52421e 100644 --- a/cmd/agent/common/import.go +++ b/cmd/agent/common/import.go @@ -53,7 +53,7 @@ func ImportConfig(oldConfigDir string, newConfigDir string, force bool) error { // setup the configuration system config.Datadog.AddConfigPath(newConfigDir) - _, err = config.Load() + _, err = config.LoadWithoutSecret() if err != nil { return fmt.Errorf("unable to load Datadog config file: %s", err) } diff --git a/cmd/agent/common/loader.go b/cmd/agent/common/loader.go index bdd39a9664aa52..91cc79dde364a7 100644 --- a/cmd/agent/common/loader.go +++ b/cmd/agent/common/loader.go @@ -11,6 +11,7 @@ import ( "path/filepath" "github.com/DataDog/datadog-agent/cmd/agent/common/path" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/comp/core/workloadmeta" "github.com/DataDog/datadog-agent/pkg/aggregator/sender" "github.com/DataDog/datadog-agent/pkg/autodiscovery/scheduler" @@ -56,7 +57,7 @@ func GetWorkloadmetaInit() workloadmeta.InitHelper { // LoadComponents configures several common Agent components: // tagger, collector, scheduler and autodiscovery -func LoadComponents(ctx context.Context, senderManager sender.SenderManager, confdPath string) { +func LoadComponents(ctx context.Context, senderManager sender.SenderManager, secretResolver secrets.Component, confdPath string) { confSearchPaths := []string{ confdPath, @@ -71,7 +72,7 @@ func LoadComponents(ctx context.Context, senderManager sender.SenderManager, con // No big concern here, but be sure to understand there is an implicit // assumption about the initializtion of the tagger prior to being here. // because of subscription to metadata store. - AC = setupAutoDiscovery(confSearchPaths, scheduler.NewMetaScheduler()) + AC = setupAutoDiscovery(confSearchPaths, scheduler.NewMetaScheduler(), secretResolver) sbomScanner, err := scanner.CreateGlobalScanner(config.Datadog) if err != nil { @@ -83,5 +84,4 @@ func LoadComponents(ctx context.Context, senderManager sender.SenderManager, con // create the Collector instance and start all the components // NOTICE: this will also setup the Python environment, if available Coll = collector.NewCollector(senderManager, GetPythonPaths()...) - } diff --git a/cmd/agent/subcommands/configcheck/command.go b/cmd/agent/subcommands/configcheck/command.go index 4b1629029e124b..bf4cf2dd2e5495 100644 --- a/cmd/agent/subcommands/configcheck/command.go +++ b/cmd/agent/subcommands/configcheck/command.go @@ -18,6 +18,7 @@ import ( "github.com/DataDog/datadog-agent/comp/core" "github.com/DataDog/datadog-agent/comp/core/config" "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/flare" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -44,7 +45,8 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { return fxutil.OneShot(run, fx.Supply(cliParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewAgentParamsWithSecrets(globalParams.ConfFilePath), + ConfigParams: config.NewAgentParams(globalParams.ConfFilePath), + SecretParams: secrets.NewEnabledParams(), LogParams: log.ForOneShot("CORE", "off", true)}), core.Bundle, ) diff --git a/cmd/agent/subcommands/configcheck/command_test.go b/cmd/agent/subcommands/configcheck/command_test.go index ffd214a03b8e24..ca5ff3b149c6f4 100644 --- a/cmd/agent/subcommands/configcheck/command_test.go +++ b/cmd/agent/subcommands/configcheck/command_test.go @@ -12,6 +12,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/command" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -20,8 +21,8 @@ func TestCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"configcheck", "-v"}, run, - func(cliParams *cliParams, coreParams core.BundleParams) { + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { require.Equal(t, true, cliParams.verbose) - require.Equal(t, true, coreParams.ConfigLoadSecrets()) + require.Equal(t, true, secretParams.Enabled) }) } diff --git a/cmd/agent/subcommands/diagnose/command.go b/cmd/agent/subcommands/diagnose/command.go index 809fc720af8ddb..b0cb9624643114 100644 --- a/cmd/agent/subcommands/diagnose/command.go +++ b/cmd/agent/subcommands/diagnose/command.go @@ -77,7 +77,7 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { return fxutil.OneShot(cmdDiagnose, fx.Supply(cliParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewAgentParamsWithoutSecrets(globalParams.ConfFilePath), + ConfigParams: config.NewAgentParams(globalParams.ConfFilePath), LogParams: log.ForOneShot("CORE", "off", true)}), core.Bundle, diagnosesendermanagerimpl.Module, diff --git a/cmd/agent/subcommands/diagnose/command_test.go b/cmd/agent/subcommands/diagnose/command_test.go index 28a401ec03e45a..d72468da1d80f6 100644 --- a/cmd/agent/subcommands/diagnose/command_test.go +++ b/cmd/agent/subcommands/diagnose/command_test.go @@ -12,6 +12,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/command" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -20,8 +21,8 @@ func TestDiagnoseCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"diagnose"}, cmdDiagnose, - func(cliParams *cliParams, coreParams core.BundleParams) { - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { + require.Equal(t, false, secretParams.Enabled) }) } @@ -30,8 +31,8 @@ func TestShowMetadataV5Command(t *testing.T) { Commands(&command.GlobalParams{}), []string{"diagnose", "show-metadata", "v5"}, printPayload, - func(cliParams *cliParams, coreParams core.BundleParams) { - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { + require.Equal(t, false, secretParams.Enabled) require.Equal(t, "v5", cliParams.payloadName) }) } @@ -41,8 +42,8 @@ func TestShowMetadataGohaiCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"diagnose", "show-metadata", "gohai"}, printPayload, - func(cliParams *cliParams, coreParams core.BundleParams) { - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { + require.Equal(t, false, secretParams.Enabled) require.Equal(t, "gohai", cliParams.payloadName) }) } @@ -52,8 +53,8 @@ func TestShowMetadataInventoryCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"diagnose", "show-metadata", "inventory"}, printPayload, - func(cliParams *cliParams, coreParams core.BundleParams) { - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { + require.Equal(t, false, secretParams.Enabled) require.Equal(t, "inventory", cliParams.payloadName) }) } @@ -63,8 +64,8 @@ func TestShowMetadataInventoryAgentCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"diagnose", "show-metadata", "inventory-agent"}, printPayload, - func(cliParams *cliParams, coreParams core.BundleParams) { - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { + require.Equal(t, false, secretParams.Enabled) require.Equal(t, "inventory-agent", cliParams.payloadName) }) } diff --git a/cmd/agent/subcommands/dogstatsdcapture/command_test.go b/cmd/agent/subcommands/dogstatsdcapture/command_test.go index dab85b28730f71..24e6ce93a887a4 100644 --- a/cmd/agent/subcommands/dogstatsdcapture/command_test.go +++ b/cmd/agent/subcommands/dogstatsdcapture/command_test.go @@ -13,6 +13,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/command" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -21,9 +22,9 @@ func TestCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"dogstatsd-capture", "-d", "10s", "-z"}, dogstatsdCapture, - func(cliParams *cliParams, coreParams core.BundleParams) { + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { require.Equal(t, 10*time.Second, cliParams.dsdCaptureDuration) require.True(t, cliParams.dsdCaptureCompressed) - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + require.Equal(t, false, secretParams.Enabled) }) } diff --git a/cmd/agent/subcommands/dogstatsdreplay/command_test.go b/cmd/agent/subcommands/dogstatsdreplay/command_test.go index bfa81a583c5155..d1878986e093cf 100644 --- a/cmd/agent/subcommands/dogstatsdreplay/command_test.go +++ b/cmd/agent/subcommands/dogstatsdreplay/command_test.go @@ -12,6 +12,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/command" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -20,8 +21,8 @@ func TestCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"dogstatsd-replay", "-v"}, dogstatsdReplay, - func(cliParams *cliParams, coreParams core.BundleParams) { + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { require.True(t, cliParams.dsdVerboseReplay) - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + require.Equal(t, false, secretParams.Enabled) }) } diff --git a/cmd/agent/subcommands/dogstatsdstats/command_test.go b/cmd/agent/subcommands/dogstatsdstats/command_test.go index 8543bc495fad5e..83d9420048b467 100644 --- a/cmd/agent/subcommands/dogstatsdstats/command_test.go +++ b/cmd/agent/subcommands/dogstatsdstats/command_test.go @@ -12,6 +12,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/command" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -20,8 +21,8 @@ func TestCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"dogstatsd-stats", "--json"}, requestDogstatsdStats, - func(cliParams *cliParams, coreParams core.BundleParams) { + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { require.True(t, cliParams.jsonStatus) - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + require.Equal(t, false, secretParams.Enabled) }) } diff --git a/cmd/agent/subcommands/flare/command.go b/cmd/agent/subcommands/flare/command.go index 034259a0e2927c..9e14c659197209 100644 --- a/cmd/agent/subcommands/flare/command.go +++ b/cmd/agent/subcommands/flare/command.go @@ -27,6 +27,7 @@ import ( "github.com/DataDog/datadog-agent/comp/core/flare" "github.com/DataDog/datadog-agent/comp/core/flare/helpers" "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/comp/core/sysprobeconfig" "github.com/DataDog/datadog-agent/comp/core/sysprobeconfig/sysprobeconfigimpl" "github.com/DataDog/datadog-agent/comp/metadata/inventoryagent" @@ -70,7 +71,7 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { Long: ``, RunE: func(cmd *cobra.Command, args []string) error { cliParams.args = args - config := config.NewAgentParamsWithSecrets(globalParams.ConfFilePath, + config := config.NewAgentParams(globalParams.ConfFilePath, config.WithSecurityAgentConfigFilePaths([]string{ path.Join(commonpath.DefaultConfPath, "security-agent.yaml"), }), @@ -81,6 +82,7 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { fx.Supply(cliParams), fx.Supply(core.BundleParams{ ConfigParams: config, + SecretParams: secrets.NewEnabledParams(), SysprobeConfigParams: sysprobeconfigimpl.NewParams(sysprobeconfigimpl.WithSysProbeConfFilePath(globalParams.SysProbeConfFilePath)), LogParams: log.ForOneShot(command.LoggerName, "off", false), }), diff --git a/cmd/agent/subcommands/flare/command_test.go b/cmd/agent/subcommands/flare/command_test.go index bc8c4e631d441a..39574c394837be 100644 --- a/cmd/agent/subcommands/flare/command_test.go +++ b/cmd/agent/subcommands/flare/command_test.go @@ -17,6 +17,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/command" "github.com/DataDog/datadog-agent/comp/core" "github.com/DataDog/datadog-agent/comp/core/flare" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/config" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -159,8 +160,8 @@ func TestCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"flare", "1234"}, makeFlare, - func(cliParams *cliParams, coreParams core.BundleParams) { + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { require.Equal(t, []string{"1234"}, cliParams.args) - require.Equal(t, true, coreParams.ConfigLoadSecrets()) + require.Equal(t, true, secretParams.Enabled) }) } diff --git a/cmd/agent/subcommands/hostname/command.go b/cmd/agent/subcommands/hostname/command.go index 7141ffef732b8f..a5e9fca7f19ea3 100644 --- a/cmd/agent/subcommands/hostname/command.go +++ b/cmd/agent/subcommands/hostname/command.go @@ -39,7 +39,7 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { return fxutil.OneShot(getHostname, fx.Supply(cliParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewAgentParamsWithoutSecrets(globalParams.ConfFilePath), + ConfigParams: config.NewAgentParams(globalParams.ConfFilePath), LogParams: log.ForOneShot(command.LoggerName, "off", false)}), // never output anything but hostname core.Bundle, ) diff --git a/cmd/agent/subcommands/hostname/command_test.go b/cmd/agent/subcommands/hostname/command_test.go index ae6239afc8dafe..ee572dd7cd1e66 100644 --- a/cmd/agent/subcommands/hostname/command_test.go +++ b/cmd/agent/subcommands/hostname/command_test.go @@ -12,6 +12,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/command" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -20,7 +21,7 @@ func TestCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"hostname"}, getHostname, - func(cliParams *cliParams, coreParams core.BundleParams) { - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { + require.Equal(t, false, secretParams.Enabled) }) } diff --git a/cmd/agent/subcommands/integrations/command.go b/cmd/agent/subcommands/integrations/command.go index 7bea9bc23d8040..e5bc29e629bcbe 100644 --- a/cmd/agent/subcommands/integrations/command.go +++ b/cmd/agent/subcommands/integrations/command.go @@ -111,7 +111,7 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { return fxutil.OneShot(callback, fx.Supply(cliParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewAgentParamsWithoutSecrets(globalParams.ConfFilePath, config.WithConfigMissingOK(true))}), + ConfigParams: config.NewAgentParams(globalParams.ConfFilePath, config.WithConfigMissingOK(true))}), core.Bundle, ) } diff --git a/cmd/agent/subcommands/integrations/command_test.go b/cmd/agent/subcommands/integrations/command_test.go index 46a2897683a638..7356668d293cc1 100644 --- a/cmd/agent/subcommands/integrations/command_test.go +++ b/cmd/agent/subcommands/integrations/command_test.go @@ -16,6 +16,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/command" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -24,10 +25,10 @@ func TestInstallCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"integration", "install", "foo==1.0", "-v"}, install, - func(cliParams *cliParams, coreParams core.BundleParams) { + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { require.Equal(t, []string{"foo==1.0"}, cliParams.args) require.Equal(t, 1, cliParams.verbose) - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + require.Equal(t, false, secretParams.Enabled) require.Equal(t, true, coreParams.ConfigMissingOK()) }) } @@ -48,10 +49,10 @@ func TestRemoveCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"integration", "remove", "foo"}, remove, - func(cliParams *cliParams, coreParams core.BundleParams) { + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { require.Equal(t, []string{"foo"}, cliParams.args) require.Equal(t, 0, cliParams.verbose) - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + require.Equal(t, false, secretParams.Enabled) require.Equal(t, true, coreParams.ConfigMissingOK()) }) } @@ -61,10 +62,10 @@ func TestFreezeCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"integration", "freeze"}, list, - func(cliParams *cliParams, coreParams core.BundleParams) { + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { require.Equal(t, []string{}, cliParams.args) require.Equal(t, 0, cliParams.verbose) - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + require.Equal(t, false, secretParams.Enabled) require.Equal(t, true, coreParams.ConfigMissingOK()) }) } @@ -74,10 +75,10 @@ func TestShowCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"integration", "show", "foo"}, show, - func(cliParams *cliParams, coreParams core.BundleParams) { + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { require.Equal(t, []string{"foo"}, cliParams.args) require.Equal(t, 0, cliParams.verbose) - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + require.Equal(t, false, secretParams.Enabled) require.Equal(t, true, coreParams.ConfigMissingOK()) }) } diff --git a/cmd/agent/subcommands/jmx/command.go b/cmd/agent/subcommands/jmx/command.go index 150dec6de33581..bde526d33dba9e 100644 --- a/cmd/agent/subcommands/jmx/command.go +++ b/cmd/agent/subcommands/jmx/command.go @@ -27,6 +27,7 @@ import ( "github.com/DataDog/datadog-agent/comp/core" "github.com/DataDog/datadog-agent/comp/core/config" "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/comp/core/workloadmeta" "github.com/DataDog/datadog-agent/comp/core/workloadmeta/collectors" "github.com/DataDog/datadog-agent/pkg/autodiscovery/integration" @@ -90,7 +91,8 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { cliParams.jmxLogLevel = "debug" } params := core.BundleParams{ - ConfigParams: config.NewAgentParamsWithSecrets(globalParams.ConfFilePath), + ConfigParams: config.NewAgentParams(globalParams.ConfFilePath), + SecretParams: secrets.NewEnabledParams(), LogParams: log.ForOneShot(command.LoggerName, cliParams.jmxLogLevel, false)} if cliParams.logFile != "" { params.LogParams.LogToFile(cliParams.logFile) @@ -235,7 +237,7 @@ func disableCmdPort() { // runJmxCommandConsole sets up the common utils necessary for JMX, and executes the command // with the Console reporter -func runJmxCommandConsole(config config.Component, cliParams *cliParams, wmeta workloadmeta.Component, diagnoseSendermanager diagnosesendermanager.Component) error { +func runJmxCommandConsole(config config.Component, cliParams *cliParams, wmeta workloadmeta.Component, diagnoseSendermanager diagnosesendermanager.Component, secretResolver secrets.Component) error { // This prevents log-spam from "comp/core/workloadmeta/collectors/internal/remote/process_collector/process_collector.go" // It appears that this collector creates some contention in AD. // Disabling it is both more efficient and gets rid of this log spam @@ -252,7 +254,7 @@ func runJmxCommandConsole(config config.Component, cliParams *cliParams, wmeta w } // The Autoconfig instance setup happens in the workloadmeta start hook // create and setup the Collector and others. - common.LoadComponents(context.Background(), senderManager, config.GetString("confd_path")) + common.LoadComponents(context.Background(), senderManager, secretResolver, config.GetString("confd_path")) common.AC.LoadAndRun(context.Background()) // Create the CheckScheduler, but do not attach it to diff --git a/cmd/agent/subcommands/jmx/command_test.go b/cmd/agent/subcommands/jmx/command_test.go index 0cf739c5cef202..0db864483eef94 100644 --- a/cmd/agent/subcommands/jmx/command_test.go +++ b/cmd/agent/subcommands/jmx/command_test.go @@ -16,6 +16,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/command" "github.com/DataDog/datadog-agent/cmd/agent/common/path" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -27,14 +28,14 @@ func TestCollectCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"jmx", "collect"}, runJmxCommandConsole, - func(cliParams *cliParams, coreParams core.BundleParams) { + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { require.Equal(t, "collect", cliParams.command) require.Equal(t, "debug", cliParams.jmxLogLevel) require.Equal(t, "debug", coreParams.LogLevelFn(nil)) require.Equal(t, "", cliParams.logFile) require.Equal(t, "", coreParams.LogFileFn(nil)) require.Equal(t, "CORE", coreParams.LoggerName()) - require.Equal(t, true, coreParams.ConfigLoadSecrets()) + require.Equal(t, true, secretParams.Enabled) }) }) @@ -43,14 +44,14 @@ func TestCollectCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"jmx", "collect", "--log-level", "info"}, runJmxCommandConsole, - func(cliParams *cliParams, coreParams core.BundleParams) { + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { require.Equal(t, "collect", cliParams.command) require.Equal(t, "info", cliParams.jmxLogLevel) require.Equal(t, "info", coreParams.LogLevelFn(nil)) require.Equal(t, "", cliParams.logFile) require.Equal(t, "", coreParams.LogFileFn(nil)) require.Equal(t, "CORE", coreParams.LoggerName()) - require.Equal(t, true, coreParams.ConfigLoadSecrets()) + require.Equal(t, true, secretParams.Enabled) }) }) @@ -59,14 +60,14 @@ func TestCollectCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"jmx", "collect", "--flare", "--log-level", "info"}, runJmxCommandConsole, - func(cliParams *cliParams, coreParams core.BundleParams) { + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { require.Equal(t, "collect", cliParams.command) require.Equal(t, "debug", cliParams.jmxLogLevel) // overrides --log-level require.Equal(t, "debug", coreParams.LogLevelFn(nil)) // overrides --log-level require.True(t, strings.HasPrefix(cliParams.logFile, path.DefaultJMXFlareDirectory)) require.Equal(t, cliParams.logFile, coreParams.LogFileFn(nil)) require.Equal(t, "CORE", coreParams.LoggerName()) - require.Equal(t, true, coreParams.ConfigLoadSecrets()) + require.Equal(t, true, secretParams.Enabled) }) }) } diff --git a/cmd/agent/subcommands/launchgui/command.go b/cmd/agent/subcommands/launchgui/command.go index df594f5acc84a3..90bad7fd1f4ab0 100644 --- a/cmd/agent/subcommands/launchgui/command.go +++ b/cmd/agent/subcommands/launchgui/command.go @@ -40,7 +40,7 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { return fxutil.OneShot(launchGui, fx.Supply(cliParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewAgentParamsWithoutSecrets(globalParams.ConfFilePath)}), + ConfigParams: config.NewAgentParams(globalParams.ConfFilePath)}), core.Bundle, ) }, diff --git a/cmd/agent/subcommands/launchgui/command_test.go b/cmd/agent/subcommands/launchgui/command_test.go index 5f5ad2d03e597c..2c5c10f802db56 100644 --- a/cmd/agent/subcommands/launchgui/command_test.go +++ b/cmd/agent/subcommands/launchgui/command_test.go @@ -12,6 +12,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/command" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -20,7 +21,7 @@ func TestCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"launch-gui"}, launchGui, - func(cliParams *cliParams, coreParams core.BundleParams) { - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { + require.Equal(t, false, secretParams.Enabled) }) } diff --git a/cmd/agent/subcommands/remoteconfig/command.go b/cmd/agent/subcommands/remoteconfig/command.go index 375b5841b67609..08bd20bba4bf36 100644 --- a/cmd/agent/subcommands/remoteconfig/command.go +++ b/cmd/agent/subcommands/remoteconfig/command.go @@ -44,7 +44,7 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { return fxutil.OneShot(state, fx.Supply(cliParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewAgentParamsWithoutSecrets(globalParams.ConfFilePath)}), + ConfigParams: config.NewAgentParams(globalParams.ConfFilePath)}), core.Bundle, ) }, diff --git a/cmd/agent/subcommands/remoteconfig/command_test.go b/cmd/agent/subcommands/remoteconfig/command_test.go index a79dc986cd372b..d8d7e39ae3584a 100644 --- a/cmd/agent/subcommands/remoteconfig/command_test.go +++ b/cmd/agent/subcommands/remoteconfig/command_test.go @@ -12,6 +12,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/command" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -20,7 +21,7 @@ func TestCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"remote-config"}, state, - func(cliParams *cliParams, coreParams core.BundleParams) { - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { + require.Equal(t, false, secretParams.Enabled) }) } diff --git a/cmd/agent/subcommands/run/command.go b/cmd/agent/subcommands/run/command.go index 9cf28852450a70..685d02395cc3ef 100644 --- a/cmd/agent/subcommands/run/command.go +++ b/cmd/agent/subcommands/run/command.go @@ -43,6 +43,7 @@ import ( "github.com/DataDog/datadog-agent/comp/core/config" "github.com/DataDog/datadog-agent/comp/core/flare" "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/comp/core/sysprobeconfig" "github.com/DataDog/datadog-agent/comp/core/sysprobeconfig/sysprobeconfigimpl" "github.com/DataDog/datadog-agent/comp/core/telemetry" @@ -152,7 +153,8 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { return fxutil.OneShot(run, fx.Supply(cliParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewAgentParamsWithSecrets(globalParams.ConfFilePath), + ConfigParams: config.NewAgentParams(globalParams.ConfFilePath), + SecretParams: secrets.NewEnabledParams(), SysprobeConfigParams: sysprobeconfigimpl.NewParams(sysprobeconfigimpl.WithSysProbeConfFilePath(globalParams.SysProbeConfFilePath)), LogParams: log.ForDaemon(command.LoggerName, "log_file", path.DefaultLogFile), }), @@ -202,6 +204,7 @@ func run(log log.Component, hostMetadata host.Component, invAgent inventoryagent.Component, invHost inventoryhost.Component, + secretResolver secrets.Component, _ netflowServer.Component, _ langDetectionCl.Component, ) error { @@ -263,6 +266,7 @@ func run(log log.Component, hostMetadata, invAgent, invHost, + secretResolver, ); err != nil { return err } @@ -320,14 +324,14 @@ func getSharedFxOption() fx.Option { // Workloadmeta component needs to be initialized before this hook is executed, and thus is included // in the function args to order the execution. This pattern might be worth revising because it is // error prone. - fx.Invoke(func(lc fx.Lifecycle, demultiplexer demultiplexer.Component, _ workloadmeta.Component) { + fx.Invoke(func(lc fx.Lifecycle, demultiplexer demultiplexer.Component, _ workloadmeta.Component, secretResolver secrets.Component) { lc.Append(fx.Hook{ OnStart: func(ctx context.Context) error { // Main context passed to components mainCtx, _ := pkgcommon.GetMainCtxCancel() // create and setup the Autoconfig instance - common.LoadComponents(mainCtx, demultiplexer, pkgconfig.Datadog.GetString("confd_path")) + common.LoadComponents(mainCtx, demultiplexer, secretResolver, pkgconfig.Datadog.GetString("confd_path")) return nil }, OnStop: func(ctx context.Context) error { @@ -386,6 +390,7 @@ func startAgent( hostMetadata host.Component, invAgent inventoryagent.Component, invHost inventoryhost.Component, + secretResolver secrets.Component, ) error { var err error @@ -537,6 +542,7 @@ func startAgent( hostMetadata, invAgent, invHost, + secretResolver, ); err != nil { return log.Errorf("Error while starting api server, exiting: %v", err) } diff --git a/cmd/agent/subcommands/run/command_test.go b/cmd/agent/subcommands/run/command_test.go index c20456f9d0d2a0..ad5a8a0319b295 100644 --- a/cmd/agent/subcommands/run/command_test.go +++ b/cmd/agent/subcommands/run/command_test.go @@ -14,6 +14,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/command" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/comp/core/workloadmeta" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -23,8 +24,8 @@ func TestCommand(t *testing.T) { Commands(newGlobalParamsTest(t)), []string{"run"}, run, - func(cliParams *cliParams, coreParams core.BundleParams) { - require.Equal(t, true, coreParams.ConfigLoadSecrets()) + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { + require.Equal(t, true, secretParams.Enabled) }) workloadmeta.SetGlobalStore(nil) } @@ -34,9 +35,9 @@ func TestCommandPidfile(t *testing.T) { Commands(newGlobalParamsTest(t)), []string{"run", "--pidfile", "/pid/file"}, run, - func(cliParams *cliParams, coreParams core.BundleParams) { + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { require.Equal(t, "/pid/file", cliParams.pidfilePath) - require.Equal(t, true, coreParams.ConfigLoadSecrets()) + require.Equal(t, true, secretParams.Enabled) }) workloadmeta.SetGlobalStore(nil) } diff --git a/cmd/agent/subcommands/run/command_windows.go b/cmd/agent/subcommands/run/command_windows.go index dc62d3b290d65d..f9ff99ae6aa73b 100644 --- a/cmd/agent/subcommands/run/command_windows.go +++ b/cmd/agent/subcommands/run/command_windows.go @@ -10,10 +10,11 @@ package run import ( "context" - _ "expvar" // Blank import used because this isn't directly used in this file + _ "expvar" // Blank import used because this isn't directly used in this file + _ "net/http/pprof" // Blank import used because this isn't directly used in this file + "github.com/DataDog/datadog-agent/comp/checks/winregistry" winregistryimpl "github.com/DataDog/datadog-agent/comp/checks/winregistry/impl" - _ "net/http/pprof" // Blank import used because this isn't directly used in this file "go.uber.org/fx" @@ -135,7 +136,8 @@ func StartAgentWithDefaults(ctxChan <-chan context.Context) (<-chan error, error }, // no config file path specification in this situation fx.Supply(core.BundleParams{ - ConfigParams: config.NewAgentParamsWithSecrets(""), + ConfigParams: config.NewAgentParams(""), + SecretParams: secrets.NewEnabledParams(), SysprobeConfigParams: sysprobeconfigimpl.NewParams(), LogParams: log.ForDaemon(command.LoggerName, "log_file", path.DefaultLogFile), }), diff --git a/cmd/agent/subcommands/secret/command_test.go b/cmd/agent/subcommands/secret/command_test.go index f329036d17d86a..1c9cd3d42ab0ab 100644 --- a/cmd/agent/subcommands/secret/command_test.go +++ b/cmd/agent/subcommands/secret/command_test.go @@ -12,6 +12,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/command" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -20,7 +21,7 @@ func TestCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"secret"}, secret, - func(cliParams *cliParams, coreParams core.BundleParams) { - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { + require.Equal(t, false, secretParams.Enabled) }) } diff --git a/cmd/agent/subcommands/secrethelper/command.go b/cmd/agent/subcommands/secrethelper/command.go index be0cecebe4df2e..0ada236b010fda 100644 --- a/cmd/agent/subcommands/secrethelper/command.go +++ b/cmd/agent/subcommands/secrethelper/command.go @@ -3,8 +3,6 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2016-present Datadog, Inc. -//go:build secrets - // Package secrethelper implements 'agent secret-helper' package secrethelper diff --git a/cmd/agent/subcommands/secrethelper/command_nosecrets.go b/cmd/agent/subcommands/secrethelper/command_nosecrets.go deleted file mode 100644 index 2135264f934f97..00000000000000 --- a/cmd/agent/subcommands/secrethelper/command_nosecrets.go +++ /dev/null @@ -1,20 +0,0 @@ -// Unless explicitly stated otherwise all files in this repository are licensed -// under the Apache License Version 2.0. -// This product includes software developed at Datadog (https://www.datadoghq.com/). -// Copyright 2016-present Datadog, Inc. - -//go:build !secrets - -// Package secrethelper implements 'agent secret-helper' -package secrethelper - -import ( - "github.com/spf13/cobra" - - "github.com/DataDog/datadog-agent/cmd/agent/command" -) - -// Commands returns nil when compiling without the secrets build flag -func Commands(*command.GlobalParams) []*cobra.Command { - return nil -} diff --git a/cmd/agent/subcommands/snmp/command.go b/cmd/agent/subcommands/snmp/command.go index ea6ea8d9a44519..cef7b3e44b7edb 100644 --- a/cmd/agent/subcommands/snmp/command.go +++ b/cmd/agent/subcommands/snmp/command.go @@ -22,6 +22,7 @@ import ( "github.com/DataDog/datadog-agent/comp/core" "github.com/DataDog/datadog-agent/comp/core/config" "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" utilFunc "github.com/DataDog/datadog-agent/pkg/snmp/gosnmplib" parse "github.com/DataDog/datadog-agent/pkg/snmp/snmpparse" "github.com/DataDog/datadog-agent/pkg/util/fxutil" @@ -96,7 +97,8 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { return fxutil.OneShot(snmpwalk, fx.Supply(cliParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewAgentParamsWithSecrets(globalParams.ConfFilePath), + ConfigParams: config.NewAgentParams(globalParams.ConfFilePath), + SecretParams: secrets.NewEnabledParams(), LogParams: log.ForOneShot(command.LoggerName, "off", true)}), core.Bundle, ) diff --git a/cmd/agent/subcommands/status/command.go b/cmd/agent/subcommands/status/command.go index 9846fecf0dfba0..88b30ee873dc17 100644 --- a/cmd/agent/subcommands/status/command.go +++ b/cmd/agent/subcommands/status/command.go @@ -67,7 +67,7 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { return fxutil.OneShot(statusCmd, fx.Supply(cliParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewAgentParamsWithoutSecrets(globalParams.ConfFilePath), + ConfigParams: config.NewAgentParams(globalParams.ConfFilePath), SysprobeConfigParams: sysprobeconfigimpl.NewParams(sysprobeconfigimpl.WithSysProbeConfFilePath(globalParams.SysProbeConfFilePath)), LogParams: log.ForOneShot(command.LoggerName, "off", true)}), core.Bundle, diff --git a/cmd/agent/subcommands/status/command_test.go b/cmd/agent/subcommands/status/command_test.go index 5ff9db627a2614..a269bdc4a5fada 100644 --- a/cmd/agent/subcommands/status/command_test.go +++ b/cmd/agent/subcommands/status/command_test.go @@ -13,6 +13,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/command" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -22,10 +23,10 @@ func TestStatusCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"status", "-j"}, statusCmd, - func(cliParams *cliParams, coreParams core.BundleParams) { + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { require.Equal(t, []string{}, cliParams.args) require.Equal(t, true, cliParams.jsonStatus) - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + require.Equal(t, false, secretParams.Enabled) }) } @@ -35,9 +36,9 @@ func TestComponentStatusCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"status", "component", "abc"}, componentStatusCmd, - func(cliParams *cliParams, coreParams core.BundleParams) { + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { require.Equal(t, []string{"abc"}, cliParams.args) require.Equal(t, false, cliParams.jsonStatus) - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + require.Equal(t, false, secretParams.Enabled) }) } diff --git a/cmd/agent/subcommands/stop/command_test.go b/cmd/agent/subcommands/stop/command_test.go index 33e665dba90abb..935ab1b9b866dc 100644 --- a/cmd/agent/subcommands/stop/command_test.go +++ b/cmd/agent/subcommands/stop/command_test.go @@ -14,6 +14,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/command" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -22,7 +23,7 @@ func TestCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"stop"}, stop, - func(cliParams *cliParams, coreParams core.BundleParams) { - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { + require.Equal(t, false, secretParams.Enabled) }) } diff --git a/cmd/agent/subcommands/streamep/command_test.go b/cmd/agent/subcommands/streamep/command_test.go index dbd0348826b694..84a742089c6f6d 100644 --- a/cmd/agent/subcommands/streamep/command_test.go +++ b/cmd/agent/subcommands/streamep/command_test.go @@ -12,6 +12,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/command" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -20,8 +21,8 @@ func TestCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"stream-event-platform", "--type", "foo"}, streamEventPlatform, - func(cliParams *cliParams, coreParams core.BundleParams) { - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { + require.Equal(t, false, secretParams.Enabled) require.Equal(t, "foo", cliParams.filters.Type) }) } diff --git a/cmd/agent/subcommands/streamlogs/command_test.go b/cmd/agent/subcommands/streamlogs/command_test.go index 58c5c599c0d5ff..12fa358993db9c 100644 --- a/cmd/agent/subcommands/streamlogs/command_test.go +++ b/cmd/agent/subcommands/streamlogs/command_test.go @@ -12,6 +12,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/command" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -20,8 +21,8 @@ func TestCommand(t *testing.T) { Commands(&command.GlobalParams{}), []string{"stream-logs", "--type", "foo"}, streamLogs, - func(cliParams *cliParams, coreParams core.BundleParams) { - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { + require.Equal(t, false, secretParams.Enabled) require.Equal(t, "foo", cliParams.filters.Type) }) } diff --git a/cmd/cluster-agent-cloudfoundry/subcommands/run/command.go b/cmd/cluster-agent-cloudfoundry/subcommands/run/command.go index 374e6611bd5747..04976121cf65b0 100644 --- a/cmd/cluster-agent-cloudfoundry/subcommands/run/command.go +++ b/cmd/cluster-agent-cloudfoundry/subcommands/run/command.go @@ -28,6 +28,7 @@ import ( "github.com/DataDog/datadog-agent/comp/core" "github.com/DataDog/datadog-agent/comp/core/config" "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/comp/core/workloadmeta" "github.com/DataDog/datadog-agent/comp/core/workloadmeta/collectors" "github.com/DataDog/datadog-agent/comp/forwarder" @@ -58,7 +59,8 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { return fxutil.OneShot(run, fx.Supply(globalParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewClusterAgentParams(globalParams.ConfFilePath, config.WithConfigLoadSecrets(true)), + ConfigParams: config.NewClusterAgentParams(globalParams.ConfFilePath), + SecretParams: secrets.NewEnabledParams(), LogParams: log.ForDaemon(command.LoggerName, "log_file", path.DefaultDCALogFile), }), core.Bundle, @@ -84,7 +86,7 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { return []*cobra.Command{startCmd} } -func run(log log.Component, demultiplexer demultiplexer.Component, wmeta workloadmeta.Component) error { +func run(log log.Component, demultiplexer demultiplexer.Component, wmeta workloadmeta.Component, secretResolver secrets.Component) error { mainCtx, mainCtxCancel := context.WithCancel(context.Background()) defer mainCtxCancel() // Calling cancel twice is safe @@ -131,7 +133,7 @@ func run(log log.Component, demultiplexer demultiplexer.Component, wmeta workloa // create and setup the Autoconfig instance // The Autoconfig instance setup happens in the workloadmeta start hook // create and setup the Collector and others. - common.LoadComponents(mainCtx, demultiplexer, pkgconfig.Datadog.GetString("confd_path")) + common.LoadComponents(mainCtx, demultiplexer, secretResolver, pkgconfig.Datadog.GetString("confd_path")) // Set up check collector common.AC.AddScheduler("check", collector.InitCheckScheduler(common.Coll, demultiplexer), true) diff --git a/cmd/cluster-agent/subcommands/diagnose/command.go b/cmd/cluster-agent/subcommands/diagnose/command.go index 3a8821c136f4e8..e58c5c17a123ca 100644 --- a/cmd/cluster-agent/subcommands/diagnose/command.go +++ b/cmd/cluster-agent/subcommands/diagnose/command.go @@ -19,6 +19,7 @@ import ( "github.com/DataDog/datadog-agent/comp/core" "github.com/DataDog/datadog-agent/comp/core/config" "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/diagnose" "github.com/DataDog/datadog-agent/pkg/diagnose/diagnosis" "github.com/DataDog/datadog-agent/pkg/util/fxutil" @@ -33,7 +34,8 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { return fxutil.OneShot(run, fx.Supply(core.BundleParams{ - ConfigParams: config.NewClusterAgentParams(globalParams.ConfFilePath, config.WithConfigLoadSecrets(true)), + ConfigParams: config.NewClusterAgentParams(globalParams.ConfFilePath), + SecretParams: secrets.NewEnabledParams(), LogParams: log.ForOneShot(command.LoggerName, "off", true), // no need to show regular logs }), core.Bundle, diff --git a/cmd/cluster-agent/subcommands/metamap/command.go b/cmd/cluster-agent/subcommands/metamap/command.go index 9d7a3f69c60af5..15375b4a80f72a 100644 --- a/cmd/cluster-agent/subcommands/metamap/command.go +++ b/cmd/cluster-agent/subcommands/metamap/command.go @@ -18,6 +18,7 @@ import ( "github.com/DataDog/datadog-agent/comp/core" "github.com/DataDog/datadog-agent/comp/core/config" "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/api/util" pkgconfig "github.com/DataDog/datadog-agent/pkg/config" "github.com/DataDog/datadog-agent/pkg/status/render" @@ -44,7 +45,8 @@ as well as which services are serving the pods. Or the deployment name for the p return fxutil.OneShot(run, fx.Supply(cliParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewClusterAgentParams(globalParams.ConfFilePath, config.WithConfigLoadSecrets(true)), + ConfigParams: config.NewClusterAgentParams(globalParams.ConfFilePath), + SecretParams: secrets.NewEnabledParams(), LogParams: log.ForOneShot(command.LoggerName, command.DefaultLogLevel, true), }), core.Bundle, diff --git a/cmd/cluster-agent/subcommands/start/command.go b/cmd/cluster-agent/subcommands/start/command.go index d78fff1a63ed6f..626ea0d3de38b8 100644 --- a/cmd/cluster-agent/subcommands/start/command.go +++ b/cmd/cluster-agent/subcommands/start/command.go @@ -29,6 +29,7 @@ import ( "github.com/DataDog/datadog-agent/comp/core" "github.com/DataDog/datadog-agent/comp/core/config" "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/comp/core/telemetry" "github.com/DataDog/datadog-agent/comp/core/workloadmeta" "github.com/DataDog/datadog-agent/comp/core/workloadmeta/collectors" @@ -80,7 +81,8 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { return fxutil.OneShot(start, fx.Supply(globalParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewClusterAgentParams(globalParams.ConfFilePath, config.WithConfigLoadSecrets(true)), + ConfigParams: config.NewClusterAgentParams(globalParams.ConfFilePath), + SecretParams: secrets.NewEnabledParams(), LogParams: log.ForDaemon(command.LoggerName, "log_file", path.DefaultDCALogFile), }), core.Bundle, @@ -110,7 +112,7 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { return []*cobra.Command{startCmd} } -func start(log log.Component, config config.Component, telemetry telemetry.Component, demultiplexer demultiplexer.Component, wmeta workloadmeta.Component) error { +func start(log log.Component, config config.Component, telemetry telemetry.Component, demultiplexer demultiplexer.Component, wmeta workloadmeta.Component, secretResolver secrets.Component) error { stopCh := make(chan struct{}) mainCtx, mainCtxCancel := context.WithCancel(context.Background()) @@ -256,7 +258,7 @@ func start(log log.Component, config config.Component, telemetry telemetry.Compo // create and setup the Autoconfig instance // The Autoconfig instance setup happens in the workloadmeta start hook // create and setup the Collector and others. - common.LoadComponents(mainCtx, demultiplexer, pkgconfig.Datadog.GetString("confd_path")) + common.LoadComponents(mainCtx, demultiplexer, secretResolver, pkgconfig.Datadog.GetString("confd_path")) // Set up check collector common.AC.AddScheduler("check", collector.InitCheckScheduler(common.Coll, demultiplexer), true) diff --git a/cmd/cluster-agent/subcommands/status/command.go b/cmd/cluster-agent/subcommands/status/command.go index 71da99cd8e7ebd..8d8460c56b9d61 100644 --- a/cmd/cluster-agent/subcommands/status/command.go +++ b/cmd/cluster-agent/subcommands/status/command.go @@ -21,6 +21,7 @@ import ( "github.com/DataDog/datadog-agent/comp/core" "github.com/DataDog/datadog-agent/comp/core/config" "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/api/util" pkgconfig "github.com/DataDog/datadog-agent/pkg/config" "github.com/DataDog/datadog-agent/pkg/status/render" @@ -44,7 +45,8 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { return fxutil.OneShot(run, fx.Supply(cliParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewClusterAgentParams(globalParams.ConfFilePath, config.WithConfigLoadSecrets(true)), + ConfigParams: config.NewClusterAgentParams(globalParams.ConfFilePath), + SecretParams: secrets.NewEnabledParams(), LogParams: log.ForOneShot(command.LoggerName, command.DefaultLogLevel, true), }), core.Bundle, diff --git a/cmd/dogstatsd/subcommands/start/command.go b/cmd/dogstatsd/subcommands/start/command.go index 115f8d363f561e..b16bb3b61711f9 100644 --- a/cmd/dogstatsd/subcommands/start/command.go +++ b/cmd/dogstatsd/subcommands/start/command.go @@ -21,6 +21,8 @@ import ( "github.com/DataDog/datadog-agent/comp/core/config" "github.com/DataDog/datadog-agent/comp/core/log" logComponent "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" + "github.com/DataDog/datadog-agent/comp/core/secrets/secretsimpl" "github.com/DataDog/datadog-agent/comp/core/workloadmeta" "github.com/DataDog/datadog-agent/comp/core/workloadmeta/collectors" "github.com/DataDog/datadog-agent/comp/dogstatsd" @@ -98,10 +100,10 @@ func RunDogstatsdFct(cliParams *CLIParams, defaultConfPath string, defaultLogFil fx.Supply(config.NewParams( defaultConfPath, config.WithConfFilePath(cliParams.confPath), - config.WithConfigLoadSecrets(true), config.WithConfigMissingOK(true), config.WithConfigName("dogstatsd")), ), + fx.Supply(secrets.NewEnabledParams()), fx.Supply(logComponent.ForDaemon(string(loggerName), "log_file", params.DefaultLogFile)), config.Module, logComponent.Module, @@ -125,6 +127,7 @@ func RunDogstatsdFct(cliParams *CLIParams, defaultConfPath string, defaultLogFil }), workloadmeta.OptionalModule, demultiplexer.Module, + secretsimpl.Module, // injecting the shared Serializer to FX until we migrate it to a prpoper component. This allows other // already migrated components to request it. fx.Provide(func(demuxInstance demultiplexer.Component) serializer.MetricSerializer { diff --git a/cmd/otel-agent/main.go b/cmd/otel-agent/main.go index 3e3ac05fc4beb1..8fa2a0bacbddb0 100644 --- a/cmd/otel-agent/main.go +++ b/cmd/otel-agent/main.go @@ -21,6 +21,7 @@ import ( "github.com/DataDog/datadog-agent/comp/core" "github.com/DataDog/datadog-agent/comp/core/config" corelog "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/comp/forwarder" "github.com/DataDog/datadog-agent/comp/forwarder/defaultforwarder" "github.com/DataDog/datadog-agent/comp/logs" @@ -64,7 +65,8 @@ func main() { logs.Bundle, fx.Supply( core.BundleParams{ - ConfigParams: config.NewAgentParamsWithSecrets(*cfgPath), + ConfigParams: config.NewAgentParams(*cfgPath), + SecretParams: secrets.NewEnabledParams(), LogParams: corelog.ForOneShot(loggerName, "debug", true), }, ), diff --git a/cmd/process-agent/command/command.go b/cmd/process-agent/command/command.go index cab3a42c208e1a..1847e65c4231e8 100644 --- a/cmd/process-agent/command/command.go +++ b/cmd/process-agent/command/command.go @@ -16,6 +16,7 @@ import ( "github.com/DataDog/datadog-agent/comp/core" configComponent "github.com/DataDog/datadog-agent/comp/core/config" logComponent "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/comp/core/sysprobeconfig/sysprobeconfigimpl" "github.com/DataDog/datadog-agent/pkg/config" "github.com/DataDog/datadog-agent/pkg/util/filesystem" @@ -142,7 +143,8 @@ func SetHostMountEnv(logger logComponent.Component) { func GetCoreBundleParamsForOneShot(globalParams *GlobalParams) core.BundleParams { return core.BundleParams{ - ConfigParams: configComponent.NewAgentParamsWithSecrets(globalParams.ConfFilePath), + ConfigParams: configComponent.NewAgentParams(globalParams.ConfFilePath), + SecretParams: secrets.NewEnabledParams(), SysprobeConfigParams: sysprobeconfigimpl.NewParams(sysprobeconfigimpl.WithSysProbeConfFilePath(globalParams.SysProbeConfFilePath)), LogParams: logComponent.ForOneShot(string(LoggerName), "info", true), } diff --git a/cmd/process-agent/main_common.go b/cmd/process-agent/main_common.go index 9f7ca826e39ac7..98b8033b2d3268 100644 --- a/cmd/process-agent/main_common.go +++ b/cmd/process-agent/main_common.go @@ -21,6 +21,7 @@ import ( "github.com/DataDog/datadog-agent/comp/core" "github.com/DataDog/datadog-agent/comp/core/config" logComponent "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/comp/core/sysprobeconfig" "github.com/DataDog/datadog-agent/comp/core/sysprobeconfig/sysprobeconfigimpl" "github.com/DataDog/datadog-agent/comp/core/workloadmeta" @@ -116,7 +117,8 @@ func runApp(ctx context.Context, globalParams *command.GlobalParams) error { SysprobeConfigParams: sysprobeconfigimpl.NewParams( sysprobeconfigimpl.WithSysProbeConfFilePath(globalParams.SysProbeConfFilePath), ), - ConfigParams: config.NewAgentParamsWithSecrets(globalParams.ConfFilePath), + ConfigParams: config.NewAgentParams(globalParams.ConfFilePath), + SecretParams: secrets.NewEnabledParams(), LogParams: command.DaemonLogParams, }, ), diff --git a/cmd/py-launcher/py-launcher.go b/cmd/py-launcher/py-launcher.go index 3ceb21e203b6f5..5a1ae237c200be 100644 --- a/cmd/py-launcher/py-launcher.go +++ b/cmd/py-launcher/py-launcher.go @@ -46,7 +46,7 @@ func main() { if *conf != "" { config.Datadog.SetConfigFile(*conf) - _, confErr := config.Load() + _, confErr := config.LoadWithoutSecret() if confErr != nil { fmt.Printf("unable to parse Datadog config file, running with env variables: %s\n", confErr) } diff --git a/cmd/secrethelper/providers/file.go b/cmd/secrethelper/providers/file.go index 06a71627b6e996..3640fa3242e4ce 100644 --- a/cmd/secrethelper/providers/file.go +++ b/cmd/secrethelper/providers/file.go @@ -3,8 +3,6 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2016-present Datadog, Inc. -//go:build secrets - // Package providers defines default secrets providers package providers @@ -15,7 +13,7 @@ import ( "path/filepath" "strings" - s "github.com/DataDog/datadog-agent/pkg/secrets" + "github.com/DataDog/datadog-agent/comp/core/secrets" ) const ( @@ -23,13 +21,13 @@ const ( ) // ReadSecretFile reads the given secret file -func ReadSecretFile(path string) s.Secret { +func ReadSecretFile(path string) secrets.SecretVal { fi, err := os.Lstat(path) if err != nil { if os.IsNotExist(err) { - return s.Secret{Value: "", ErrorMsg: "secret does not exist"} + return secrets.SecretVal{Value: "", ErrorMsg: "secret does not exist"} } - return s.Secret{Value: "", ErrorMsg: err.Error()} + return secrets.SecretVal{Value: "", ErrorMsg: err.Error()} } // In kubernetes when kubelet mounts the secret|configmap key as a file, it @@ -39,14 +37,14 @@ func ReadSecretFile(path string) s.Secret { // sanity check. target, err := os.Readlink(path) if err != nil { - return s.Secret{Value: "", ErrorMsg: fmt.Sprintf("failed to read symlink target: %v", err)} + return secrets.SecretVal{Value: "", ErrorMsg: fmt.Sprintf("failed to read symlink target: %v", err)} } dir := filepath.Dir(path) if !filepath.IsAbs(target) { target, err = filepath.Abs(filepath.Join(dir, target)) if err != nil { - return s.Secret{Value: "", ErrorMsg: fmt.Sprintf("failed to resolve symlink absolute path: %v", err)} + return secrets.SecretVal{Value: "", ErrorMsg: fmt.Sprintf("failed to resolve symlink absolute path: %v", err)} } } @@ -54,31 +52,31 @@ func ReadSecretFile(path string) s.Secret { dirAbs, err := filepath.Abs(dir) if err != nil { - return s.Secret{Value: "", ErrorMsg: fmt.Sprintf("failed to resolve absolute path of directory: %v", err)} + return secrets.SecretVal{Value: "", ErrorMsg: fmt.Sprintf("failed to resolve absolute path of directory: %v", err)} } if !strings.HasPrefix(targetDir+"/", dirAbs+"/") { - return s.Secret{Value: "", ErrorMsg: fmt.Sprintf("not following symlink %q outside of %q", target, dir)} + return secrets.SecretVal{Value: "", ErrorMsg: fmt.Sprintf("not following symlink %q outside of %q", target, dir)} } } fi, err = os.Stat(path) if err != nil { - return s.Secret{Value: "", ErrorMsg: err.Error()} + return secrets.SecretVal{Value: "", ErrorMsg: err.Error()} } if fi.Size() > maxSecretFileSize { - return s.Secret{Value: "", ErrorMsg: "secret exceeds max allowed size"} + return secrets.SecretVal{Value: "", ErrorMsg: "secret exceeds max allowed size"} } file, err := os.Open(path) if err != nil { - return s.Secret{Value: "", ErrorMsg: err.Error()} + return secrets.SecretVal{Value: "", ErrorMsg: err.Error()} } bytes, err := io.ReadAll(file) if err != nil { - return s.Secret{Value: "", ErrorMsg: err.Error()} + return secrets.SecretVal{Value: "", ErrorMsg: err.Error()} } - return s.Secret{Value: string(bytes), ErrorMsg: ""} + return secrets.SecretVal{Value: string(bytes), ErrorMsg: ""} } diff --git a/cmd/secrethelper/providers/file_test.go b/cmd/secrethelper/providers/file_test.go index f80b7ab8776cb6..e94acbf3c84944 100644 --- a/cmd/secrethelper/providers/file_test.go +++ b/cmd/secrethelper/providers/file_test.go @@ -3,8 +3,6 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2016-present Datadog, Inc. -//go:build secrets - package providers import ( diff --git a/cmd/secrethelper/providers/k8s_secret.go b/cmd/secrethelper/providers/k8s_secret.go index aedb6484a61bc4..670e1adf6d3053 100644 --- a/cmd/secrethelper/providers/k8s_secret.go +++ b/cmd/secrethelper/providers/k8s_secret.go @@ -3,8 +3,6 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2016-present Datadog, Inc. -//go:build secrets - package providers import ( @@ -15,28 +13,28 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" - s "github.com/DataDog/datadog-agent/pkg/secrets" + "github.com/DataDog/datadog-agent/comp/core/secrets" ) // ReadKubernetesSecret reads a secrets store in k8s -func ReadKubernetesSecret(kubeClient kubernetes.Interface, path string) s.Secret { +func ReadKubernetesSecret(kubeClient kubernetes.Interface, path string) secrets.SecretVal { splitName := strings.Split(path, "/") if len(splitName) != 3 { - return s.Secret{ErrorMsg: "invalid format. Use: \"namespace/name/key\""} + return secrets.SecretVal{ErrorMsg: "invalid format. Use: \"namespace/name/key\""} } namespace, name, key := splitName[0], splitName[1], splitName[2] secret, err := kubeClient.CoreV1().Secrets(namespace).Get(context.TODO(), name, metav1.GetOptions{}) if err != nil { - return s.Secret{ErrorMsg: err.Error()} + return secrets.SecretVal{ErrorMsg: err.Error()} } value, ok := secret.Data[key] if !ok { - return s.Secret{ErrorMsg: fmt.Sprintf("key %s not found in secret %s/%s", key, namespace, name)} + return secrets.SecretVal{ErrorMsg: fmt.Sprintf("key %s not found in secret %s/%s", key, namespace, name)} } - return s.Secret{Value: string(value)} + return secrets.SecretVal{Value: string(value)} } diff --git a/cmd/secrethelper/providers/k8s_secret_test.go b/cmd/secrethelper/providers/k8s_secret_test.go index 9ad31b90a63b91..5dddb83e878f0f 100644 --- a/cmd/secrethelper/providers/k8s_secret_test.go +++ b/cmd/secrethelper/providers/k8s_secret_test.go @@ -3,8 +3,6 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2016-present Datadog, Inc. -//go:build secrets - package providers import ( diff --git a/cmd/secrethelper/secret_helper.go b/cmd/secrethelper/secret_helper.go index 43975044599957..173a655b35fc54 100644 --- a/cmd/secrethelper/secret_helper.go +++ b/cmd/secrethelper/secret_helper.go @@ -3,8 +3,6 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2016-present Datadog, Inc. -//go:build secrets - // Package secrethelper implements the secrethelper subcommand. // // This subcommand is shared between multiple agent binaries. @@ -41,7 +39,7 @@ import ( "k8s.io/client-go/kubernetes" "github.com/DataDog/datadog-agent/cmd/secrethelper/providers" - s "github.com/DataDog/datadog-agent/pkg/secrets" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/util/fxutil" "github.com/DataDog/datadog-agent/pkg/util/kubernetes/apiserver" ) @@ -131,7 +129,7 @@ func parseInputSecrets(r io.Reader) ([]string, error) { } version := splitVersion(request.Version) - compatVersion := splitVersion(s.PayloadVersion) + compatVersion := splitVersion(secrets.PayloadVersion) if version[0] != compatVersion[0] { return nil, fmt.Errorf("incompatible protocol version %q", request.Version) } @@ -143,7 +141,7 @@ func parseInputSecrets(r io.Reader) ([]string, error) { return request.Secrets, nil } -func writeFetchedSecrets(w io.Writer, fetchedSecrets map[string]s.Secret) error { +func writeFetchedSecrets(w io.Writer, fetchedSecrets map[string]secrets.SecretVal) error { out, err := json.Marshal(fetchedSecrets) if err != nil { return err @@ -153,23 +151,23 @@ func writeFetchedSecrets(w io.Writer, fetchedSecrets map[string]s.Secret) error return err } -func readSecretsFromFile(secrets []string, dir string) map[string]s.Secret { - res := make(map[string]s.Secret) +func readSecretsFromFile(secretsList []string, dir string) map[string]secrets.SecretVal { + res := make(map[string]secrets.SecretVal) - for _, secretID := range secrets { + for _, secretID := range secretsList { res[secretID] = providers.ReadSecretFile(filepath.Join(dir, secretID)) } return res } -func readSecretsUsingPrefixes(secrets []string, rootPath string, newKubeClientFunc NewKubeClient) map[string]s.Secret { - res := make(map[string]s.Secret) +func readSecretsUsingPrefixes(secretsList []string, rootPath string, newKubeClientFunc NewKubeClient) map[string]secrets.SecretVal { + res := make(map[string]secrets.SecretVal) - for _, secretID := range secrets { + for _, secretID := range secretsList { prefix, id, err := parseSecretWithPrefix(secretID, rootPath) if err != nil { - res[secretID] = s.Secret{Value: "", ErrorMsg: err.Error()} + res[secretID] = secrets.SecretVal{Value: "", ErrorMsg: err.Error()} continue } @@ -179,12 +177,12 @@ func readSecretsUsingPrefixes(secrets []string, rootPath string, newKubeClientFu case k8sSecretPrefix: kubeClient, err := newKubeClientFunc(10 * time.Second) if err != nil { - res[secretID] = s.Secret{Value: "", ErrorMsg: err.Error()} + res[secretID] = secrets.SecretVal{Value: "", ErrorMsg: err.Error()} } else { res[secretID] = providers.ReadKubernetesSecret(kubeClient, id) } default: - res[secretID] = s.Secret{Value: "", ErrorMsg: fmt.Sprintf("provider not supported: %s", prefix)} + res[secretID] = secrets.SecretVal{Value: "", ErrorMsg: fmt.Sprintf("provider not supported: %s", prefix)} } } diff --git a/cmd/secrethelper/secret_helper_test.go b/cmd/secrethelper/secret_helper_test.go index 5bd2bf8c87f5d1..f903f27fea64c8 100644 --- a/cmd/secrethelper/secret_helper_test.go +++ b/cmd/secrethelper/secret_helper_test.go @@ -3,8 +3,6 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2016-present Datadog, Inc. -//go:build secrets - package secrethelper import ( diff --git a/cmd/serverless-init/main.go b/cmd/serverless-init/main.go index 4931d84bc6e7f7..6f8f79d282e293 100644 --- a/cmd/serverless-init/main.go +++ b/cmd/serverless-init/main.go @@ -87,7 +87,7 @@ func setup() (cloudservice.CloudService, *log.Config, *trace.ServerlessTraceAgen // The datadog-agent requires Load to be called or it could // panic down the line. - _, err := config.Load() + _, err := config.LoadWithoutSecret() if err != nil { logger.Debugf("Error loading config: %v\n", err) } diff --git a/cmd/serverless/main.go b/cmd/serverless/main.go index 672ab365c031e3..f74b3350fb318c 100644 --- a/cmd/serverless/main.go +++ b/cmd/serverless/main.go @@ -195,7 +195,7 @@ func runAgent(stopCh chan struct{}) (serverlessDaemon *daemon.Daemon, err error) } config.Datadog.SetConfigFile(datadogConfigPath) // Load datadog.yaml file into the config, so that metricAgent can pick these configurations - if _, err := config.Load(); err != nil { + if _, err := config.LoadWithoutSecret(); err != nil { log.Errorf("Error happened when loading configuration from datadog.yaml for metric agent: %s", err) } logChannel := make(chan *logConfig.ChannelMessage) diff --git a/cmd/system-probe/config/config.go b/cmd/system-probe/config/config.go index e3d2e8f84b4198..0580e64fb7707d 100644 --- a/cmd/system-probe/config/config.go +++ b/cmd/system-probe/config/config.go @@ -15,8 +15,10 @@ import ( "github.com/DataDog/viper" + "github.com/DataDog/datadog-agent/comp/core/secrets" aconfig "github.com/DataDog/datadog-agent/pkg/config" "github.com/DataDog/datadog-agent/pkg/config/model" + "github.com/DataDog/datadog-agent/pkg/util/optional" ) // ModuleName is a typed alias for string, used only for module names @@ -91,7 +93,7 @@ func newSysprobeConfig(configPath string) (*Config, error) { aconfig.SystemProbe.AddConfigPath(defaultConfigDir) } // load the configuration - _, err := aconfig.LoadCustom(aconfig.SystemProbe, "system-probe", false, aconfig.Datadog.GetEnvVars()) + _, err := aconfig.LoadCustom(aconfig.SystemProbe, "system-probe", optional.NewNoneOption[secrets.Component](), aconfig.Datadog.GetEnvVars()) if err != nil { var e viper.ConfigFileNotFoundError if errors.As(err, &e) || errors.Is(err, os.ErrNotExist) { @@ -199,7 +201,7 @@ func SetupOptionalDatadogConfigWithDir(configDir, configFile string) error { aconfig.Datadog.SetConfigFile(configFile) } // load the configuration - _, err := aconfig.LoadDatadogCustom(aconfig.Datadog, "datadog.yaml", false, aconfig.SystemProbe.GetEnvVars()) + _, err := aconfig.LoadDatadogCustom(aconfig.Datadog, "datadog.yaml", optional.NewNoneOption[secrets.Component](), aconfig.SystemProbe.GetEnvVars()) // If `!failOnMissingFile`, do not issue an error if we cannot find the default config file. var e viper.ConfigFileNotFoundError if err != nil && !errors.As(err, &e) { diff --git a/cmd/system-probe/subcommands/config/command.go b/cmd/system-probe/subcommands/config/command.go index 4df93ea4150216..4336b21bfbd230 100644 --- a/cmd/system-probe/subcommands/config/command.go +++ b/cmd/system-probe/subcommands/config/command.go @@ -45,7 +45,7 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { return fxutil.OneShot(callback, fx.Supply(cliParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewAgentParamsWithoutSecrets("", config.WithConfigMissingOK(true)), + ConfigParams: config.NewAgentParams("", config.WithConfigMissingOK(true)), SysprobeConfigParams: sysprobeconfigimpl.NewParams(sysprobeconfigimpl.WithSysProbeConfFilePath(globalParams.ConfFilePath)), LogParams: log.ForOneShot("SYS-PROBE", "off", true), }), diff --git a/cmd/system-probe/subcommands/debug/command.go b/cmd/system-probe/subcommands/debug/command.go index eec22c2572198b..f7c0af46d7a1bb 100644 --- a/cmd/system-probe/subcommands/debug/command.go +++ b/cmd/system-probe/subcommands/debug/command.go @@ -47,7 +47,7 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { return fxutil.OneShot(debugRuntime, fx.Supply(cliParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewAgentParamsWithoutSecrets("", config.WithConfigMissingOK(true)), + ConfigParams: config.NewAgentParams("", config.WithConfigMissingOK(true)), SysprobeConfigParams: sysprobeconfigimpl.NewParams(sysprobeconfigimpl.WithSysProbeConfFilePath(globalParams.ConfFilePath)), LogParams: log.ForOneShot("SYS-PROBE", "off", false), }), diff --git a/cmd/system-probe/subcommands/modrestart/command.go b/cmd/system-probe/subcommands/modrestart/command.go index 8eccf3dbbf794a..a7b6a4f53bf11e 100644 --- a/cmd/system-probe/subcommands/modrestart/command.go +++ b/cmd/system-probe/subcommands/modrestart/command.go @@ -45,7 +45,7 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { return fxutil.OneShot(moduleRestart, fx.Supply(cliParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewAgentParamsWithoutSecrets("", config.WithConfigMissingOK(true)), + ConfigParams: config.NewAgentParams("", config.WithConfigMissingOK(true)), SysprobeConfigParams: sysprobeconfigimpl.NewParams(sysprobeconfigimpl.WithSysProbeConfFilePath(globalParams.ConfFilePath)), LogParams: log.ForOneShot("SYS-PROBE", "off", false), }), diff --git a/cmd/system-probe/subcommands/run/command.go b/cmd/system-probe/subcommands/run/command.go index b5704cc4389e01..65411135354d2e 100644 --- a/cmd/system-probe/subcommands/run/command.go +++ b/cmd/system-probe/subcommands/run/command.go @@ -29,6 +29,8 @@ import ( "github.com/DataDog/datadog-agent/cmd/system-probe/utils" "github.com/DataDog/datadog-agent/comp/core/config" "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" + "github.com/DataDog/datadog-agent/comp/core/secrets/secretsimpl" "github.com/DataDog/datadog-agent/comp/core/sysprobeconfig" "github.com/DataDog/datadog-agent/comp/core/sysprobeconfig/sysprobeconfigimpl" "github.com/DataDog/datadog-agent/comp/core/telemetry" @@ -70,13 +72,15 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { return fxutil.OneShot(run, fx.Supply(cliParams), - fx.Supply(config.NewAgentParamsWithoutSecrets("", config.WithConfigMissingOK(true))), + fx.Supply(config.NewAgentParams("", config.WithConfigMissingOK(true))), fx.Supply(sysprobeconfigimpl.NewParams(sysprobeconfigimpl.WithSysProbeConfFilePath(globalParams.ConfFilePath))), + fx.Supply(secrets.NewDisabledParams()), fx.Supply(log.ForDaemon("SYS-PROBE", "log_file", common.DefaultLogFile)), config.Module, telemetry.Module, sysprobeconfigimpl.Module, rcclient.Module, + secretsimpl.Module, // use system-probe config instead of agent config for logging fx.Provide(func(lc fx.Lifecycle, params log.Params, sysprobeconfig sysprobeconfig.Component) (log.Component, error) { return log.NewLogger(lc, params, sysprobeconfig) @@ -183,7 +187,7 @@ func StartSystemProbeWithDefaults(ctxChan <-chan context.Context) (<-chan error, return nil }, // no config file path specification in this situation - fx.Supply(config.NewAgentParamsWithoutSecrets("", config.WithConfigMissingOK(true))), + fx.Supply(config.NewAgentParams("", config.WithConfigMissingOK(true))), fx.Supply(sysprobeconfigimpl.NewParams(sysprobeconfigimpl.WithSysProbeConfFilePath(""))), fx.Supply(log.ForDaemon("SYS-PROBE", "log_file", common.DefaultLogFile)), rcclient.Module, diff --git a/cmd/trace-agent/subcommands/info/command.go b/cmd/trace-agent/subcommands/info/command.go index bd7ac353acec68..085c0f5f80022b 100644 --- a/cmd/trace-agent/subcommands/info/command.go +++ b/cmd/trace-agent/subcommands/info/command.go @@ -14,6 +14,8 @@ import ( "github.com/DataDog/datadog-agent/cmd/trace-agent/subcommands" coreconfig "github.com/DataDog/datadog-agent/comp/core/config" + "github.com/DataDog/datadog-agent/comp/core/secrets" + "github.com/DataDog/datadog-agent/comp/core/secrets/secretsimpl" "github.com/DataDog/datadog-agent/comp/trace/config" "github.com/DataDog/datadog-agent/pkg/trace/info" "github.com/DataDog/datadog-agent/pkg/util/fxutil" @@ -36,8 +38,10 @@ func MakeCommand(globalParamsGetter func() *subcommands.GlobalParams) *cobra.Com func runTraceAgentInfoFct(params *subcommands.GlobalParams, fct interface{}) error { return fxutil.OneShot(fct, config.Module, - fx.Supply(coreconfig.NewAgentParamsWithSecrets(params.ConfPath)), + fx.Supply(coreconfig.NewAgentParams(params.ConfPath)), + fx.Supply(secrets.NewEnabledParams()), coreconfig.Module, + secretsimpl.Module, // TODO: (component) // fx.Supply(log.ForOneShot(params.LoggerName, "off", true)), // log.Module, diff --git a/cmd/trace-agent/subcommands/run/command.go b/cmd/trace-agent/subcommands/run/command.go index 9801e4b2b1a50d..274e9151d3b198 100644 --- a/cmd/trace-agent/subcommands/run/command.go +++ b/cmd/trace-agent/subcommands/run/command.go @@ -16,6 +16,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/trace-agent/subcommands" coreconfig "github.com/DataDog/datadog-agent/comp/core/config" corelog "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/comp/core/workloadmeta" "github.com/DataDog/datadog-agent/comp/core/workloadmeta/collectors" "github.com/DataDog/datadog-agent/comp/trace" @@ -62,7 +63,8 @@ func runFx(ctx context.Context, cliParams *RunParams, defaultConfPath string) er // ctx is required to be supplied from here, as Windows needs to inject its own context // to allow the agent to work as a service. fx.Provide(func() context.Context { return ctx }), // fx.Supply(ctx) fails with a missing type error. - fx.Supply(coreconfig.NewAgentParamsWithSecrets(cliParams.ConfPath)), + fx.Supply(coreconfig.NewAgentParams(cliParams.ConfPath)), + fx.Supply(secrets.NewEnabledParams()), coreconfig.Module, fx.Provide(func() corelog.Params { p := corelog.ForDaemon("TRACE", "apm_config.log_file", path.DefaultLogFile) diff --git a/comp/README.md b/comp/README.md index 44f2cadd748f30..2eb68e24950410 100644 --- a/comp/README.md +++ b/comp/README.md @@ -60,6 +60,10 @@ Package hostname exposes hostname.Get() as a component. Package log implements a component to handle logging internal to the agent. +### [comp/core/secrets](https://pkg.go.dev/github.com/DataDog/dd-agent-comp-experiments/comp/core/secrets) + +Package secrets decodes secret values by invoking the configured executable command + ### [comp/core/sysprobeconfig](https://pkg.go.dev/github.com/DataDog/dd-agent-comp-experiments/comp/core/sysprobeconfig) *Datadog Team*: ebpf-platform diff --git a/comp/core/bundle.go b/comp/core/bundle.go index e699e1a3d7ff5a..b10b303fdd1418 100644 --- a/comp/core/bundle.go +++ b/comp/core/bundle.go @@ -18,6 +18,8 @@ import ( "github.com/DataDog/datadog-agent/comp/core/config" "github.com/DataDog/datadog-agent/comp/core/hostname/hostnameimpl" "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" + "github.com/DataDog/datadog-agent/comp/core/secrets/secretsimpl" "github.com/DataDog/datadog-agent/comp/core/sysprobeconfig/sysprobeconfigimpl" "github.com/DataDog/datadog-agent/comp/core/telemetry" "github.com/DataDog/datadog-agent/pkg/util/fxutil" @@ -33,6 +35,8 @@ var Bundle = fxutil.Bundle( fx.Provide(func(params BundleParams) log.Params { return params.LogParams }), log.Module, fx.Provide(func(params BundleParams) sysprobeconfigimpl.Params { return params.SysprobeConfigParams }), + secretsimpl.Module, + fx.Provide(func(params BundleParams) secrets.Params { return params.SecretParams }), sysprobeconfigimpl.Module, telemetry.Module, hostnameimpl.Module, diff --git a/comp/core/bundle_params.go b/comp/core/bundle_params.go index d036ad9ff35ba1..701cdad9afba6f 100644 --- a/comp/core/bundle_params.go +++ b/comp/core/bundle_params.go @@ -8,6 +8,7 @@ package core import ( "github.com/DataDog/datadog-agent/comp/core/config" "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/comp/core/sysprobeconfig/sysprobeconfigimpl" ) @@ -19,6 +20,7 @@ import ( // must be called. type BundleParams struct { ConfigParams + SecretParams SysprobeConfigParams LogParams } @@ -26,6 +28,9 @@ type BundleParams struct { // ConfigParams defines the parameters of the config component type ConfigParams = config.Params +// SecretParams defines the parameters of the secrets component +type SecretParams = secrets.Params + // LogParams defines the parameters of the log component type LogParams = log.Params diff --git a/comp/core/config/config.go b/comp/core/config/config.go index bd7ca64bf4b712..9d61044f3a7efa 100644 --- a/comp/core/config/config.go +++ b/comp/core/config/config.go @@ -11,6 +11,7 @@ import ( "go.uber.org/fx" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/config" ) @@ -27,24 +28,32 @@ type cfg struct { warnings *config.Warnings } +// configDependencies is an interface that mimics the fx-oriented dependencies struct +// TODO: investigate whether this interrface is worth keeping, otherwise delete it and just use dependencies type configDependencies interface { getParams() *Params + getSecretResolver() secrets.Component } type dependencies struct { fx.In Params Params + Secret secrets.Component } func (d dependencies) getParams() *Params { return &d.Params } +func (d dependencies) getSecretResolver() secrets.Component { + return d.Secret +} + // NewServerlessConfig initializes a config component from the given config file // TODO: serverless must be eventually migrated to fx, this workaround will then become obsolete - ts should not be created directly in this fashion. func NewServerlessConfig(path string) (Component, error) { - options := []func(*Params){WithConfigName("serverless"), WithConfigLoadSecrets(true)} + options := []func(*Params){WithConfigName("serverless")} _, err := os.Stat(path) if os.IsNotExist(err) && diff --git a/comp/core/config/config_mock.go b/comp/core/config/config_mock.go index a812ca3437d263..5e2e36465e9c71 100644 --- a/comp/core/config/config_mock.go +++ b/comp/core/config/config_mock.go @@ -14,6 +14,7 @@ import ( "go.uber.org/fx" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/config" "github.com/DataDog/datadog-agent/pkg/config/env" ) @@ -29,6 +30,10 @@ func (m mockDependencies) getParams() *Params { return &p } +func (m mockDependencies) getSecretResolver() secrets.Component { + return nil +} + // newMock exported mock builder to allow modifying mocks that might be // supplied in tests and used for dep injection. func newMock(deps mockDependencies, t testing.TB) (Component, error) { diff --git a/comp/core/config/config_test.go b/comp/core/config/config_test.go index bd3262a8826427..6a67e8d62d470b 100644 --- a/comp/core/config/config_test.go +++ b/comp/core/config/config_test.go @@ -14,6 +14,8 @@ import ( "github.com/stretchr/testify/require" + "github.com/DataDog/datadog-agent/comp/core/secrets" + "github.com/DataDog/datadog-agent/comp/core/secrets/secretsimpl" "github.com/DataDog/datadog-agent/pkg/config/model" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -33,6 +35,7 @@ func TestRealConfig(t *testing.T) { WithConfigMissingOK(true), WithConfFilePath(dir), )), + fx.Provide(func() secrets.Component { return secretsimpl.NewMockSecretResolver() }), Module, )) require.Equal(t, "https://example.com", config.GetString("dd_url")) diff --git a/comp/core/config/params.go b/comp/core/config/params.go index f2edd2556531db..2ec66cd852517d 100644 --- a/comp/core/config/params.go +++ b/comp/core/config/params.go @@ -25,10 +25,6 @@ type Params struct { // SecurityAgentConfigFilePaths or from ConfFilePath. configLoadSecurityAgent bool - // ConfigLoadSecrets determines whether secrets in the configuration file - // should be evaluated. This is typically false for one-shot commands. - configLoadSecrets bool - // configMissingOK determines whether it is a fatal error if the config // file does not exist. configMissingOK bool @@ -53,20 +49,10 @@ func NewParams(defaultConfPath string, options ...func(*Params)) Params { return params } -// NewAgentParamsWithSecrets creates a new instance of Params using secrets for the Agent. -func NewAgentParamsWithSecrets(confFilePath string, options ...func(*Params)) Params { - return newAgentParams(confFilePath, true, options...) -} - -// NewAgentParamsWithoutSecrets creates a new instance of Params without using secrets for the Agent. -func NewAgentParamsWithoutSecrets(confFilePath string, options ...func(*Params)) Params { - return newAgentParams(confFilePath, false, options...) -} - -func newAgentParams(confFilePath string, configLoadSecrets bool, options ...func(*Params)) Params { +// NewAgentParams creates a new instance of Params for the Agent. +func NewAgentParams(confFilePath string, options ...func(*Params)) Params { params := NewParams(DefaultConfPath, options...) params.ConfFilePath = confFilePath - params.configLoadSecrets = configLoadSecrets return params } @@ -80,8 +66,6 @@ func NewSecurityAgentParams(securityAgentConfigFilePaths []string, options ...fu params.securityAgentConfigFilePaths = securityAgentConfigFilePaths[1:] // Default: security-agent.yaml } params.configLoadSecurityAgent = true - - params.configLoadSecrets = true params.configMissingOK = false return params } @@ -136,21 +120,8 @@ func WithConfFilePath(confFilePath string) func(*Params) { } } -// WithConfigLoadSecrets returns an option which sets configLoadSecrets -func WithConfigLoadSecrets(configLoadSecrets bool) func(*Params) { - return func(b *Params) { - b.configLoadSecrets = configLoadSecrets - } -} - // These functions are used in unit tests. -// ConfigLoadSecrets determines whether secrets in the configuration file -// should be evaluated. This is typically false for one-shot commands. -func (p Params) ConfigLoadSecrets() bool { - return p.configLoadSecrets -} - // ConfigMissingOK determines whether it is a fatal error if the config // file does not exist. func (p Params) ConfigMissingOK() bool { diff --git a/comp/core/config/params_test.go b/comp/core/config/params_test.go index 10bd069ddc8d58..b80ab5ef4df9ae 100644 --- a/comp/core/config/params_test.go +++ b/comp/core/config/params_test.go @@ -49,7 +49,6 @@ func TestNewSecurityAgentParams(t *testing.T) { require.Equal(t, true, configComponentParams.configLoadSecurityAgent, "configLoadSecurityAgent values not matching") require.Equal(t, path.DefaultConfPath, configComponentParams.defaultConfPath, "defaultConfPath values not matching") - require.Equal(t, true, configComponentParams.configLoadSecrets, "configLoadSecrets values not matching") require.Equal(t, false, configComponentParams.configMissingOK, "configMissingOK values not matching") } } diff --git a/comp/core/config/setup.go b/comp/core/config/setup.go index be723d1c3ff66e..6b95b25baf9597 100644 --- a/comp/core/config/setup.go +++ b/comp/core/config/setup.go @@ -23,7 +23,6 @@ func setupConfig(deps configDependencies) (*config.Warnings, error) { confFilePath := p.ConfFilePath configName := p.configName - withoutSecrets := !p.configLoadSecrets failOnMissingFile := !p.configMissingOK defaultConfPath := p.defaultConfPath @@ -48,12 +47,13 @@ func setupConfig(deps configDependencies) (*config.Warnings, error) { // load the configuration var err error var warnings *config.Warnings - - if withoutSecrets { + resolver := deps.getSecretResolver() + if resolver == nil || !resolver.IsEnabled() { warnings, err = config.LoadWithoutSecret() } else { - warnings, err = config.Load() + warnings, err = config.LoadWithSecret(resolver) } + // If `!failOnMissingFile`, do not issue an error if we cannot find the default config file. var e viper.ConfigFileNotFoundError if err != nil && (failOnMissingFile || !errors.As(err, &e) || confFilePath != "") { diff --git a/comp/core/secrets/component.go b/comp/core/secrets/component.go new file mode 100644 index 00000000000000..28d928429b8dc7 --- /dev/null +++ b/comp/core/secrets/component.go @@ -0,0 +1,25 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2016-present Datadog, Inc. + +// Package secrets decodes secret values by invoking the configured executable command +package secrets + +import ( + "io" +) + +// team: agent-shared-components + +// Component is the component type. +type Component interface { + // Configure the executable command that is used for decoding secrets + Configure(command string, arguments []string, timeout, maxSize int, groupExecPerm, removeLinebreak bool) + // Get debug information and write it to the parameter + GetDebugInfo(w io.Writer) + // Whether this component is enabled, if disabled other methods will only log and error and return + IsEnabled() bool + // Decrypt the given handle and return the corresponding secret value + Decrypt(data []byte, origin string) ([]byte, error) +} diff --git a/pkg/secrets/docs.go b/comp/core/secrets/docs.go similarity index 100% rename from pkg/secrets/docs.go rename to comp/core/secrets/docs.go diff --git a/comp/core/secrets/params.go b/comp/core/secrets/params.go new file mode 100644 index 00000000000000..94da25fd574f66 --- /dev/null +++ b/comp/core/secrets/params.go @@ -0,0 +1,25 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2018-present Datadog, Inc. + +package secrets + +// Params contains parameters for secrets, specifically whether the component is enabled +type Params struct { + Enabled bool +} + +// NewEnabledParams constructs params for an enabled component +func NewEnabledParams() Params { + return Params{ + Enabled: true, + } +} + +// NewDisabledParams constructs params for a disabled component +func NewDisabledParams() Params { + return Params{ + Enabled: false, + } +} diff --git a/pkg/secrets/check_rights_nix.go b/comp/core/secrets/secretsimpl/check_rights_nix.go similarity index 98% rename from pkg/secrets/check_rights_nix.go rename to comp/core/secrets/secretsimpl/check_rights_nix.go index 4d7bff39349165..c99db2ac26fce4 100644 --- a/pkg/secrets/check_rights_nix.go +++ b/comp/core/secrets/secretsimpl/check_rights_nix.go @@ -3,9 +3,9 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2016-present Datadog, Inc. -//go:build secrets && !windows +//go:build !windows -package secrets +package secretsimpl import ( "fmt" diff --git a/pkg/secrets/check_rights_nix_test.go b/comp/core/secrets/secretsimpl/check_rights_nix_test.go similarity index 98% rename from pkg/secrets/check_rights_nix_test.go rename to comp/core/secrets/secretsimpl/check_rights_nix_test.go index 7e79313a07a59f..5a8952d8ddb735 100644 --- a/pkg/secrets/check_rights_nix_test.go +++ b/comp/core/secrets/secretsimpl/check_rights_nix_test.go @@ -3,9 +3,9 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2016-present Datadog, Inc. -//go:build secrets && !windows +//go:build !windows -package secrets +package secretsimpl import ( "os" diff --git a/pkg/secrets/check_rights_windows.go b/comp/core/secrets/secretsimpl/check_rights_windows.go similarity index 99% rename from pkg/secrets/check_rights_windows.go rename to comp/core/secrets/secretsimpl/check_rights_windows.go index 6c346eff034847..dc027e0639d440 100644 --- a/pkg/secrets/check_rights_windows.go +++ b/comp/core/secrets/secretsimpl/check_rights_windows.go @@ -3,9 +3,9 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2018-present Datadog, Inc. -//go:build secrets && windows +//go:build windows -package secrets +package secretsimpl import ( "fmt" diff --git a/pkg/secrets/check_rights_windows_test.go b/comp/core/secrets/secretsimpl/check_rights_windows_test.go similarity index 98% rename from pkg/secrets/check_rights_windows_test.go rename to comp/core/secrets/secretsimpl/check_rights_windows_test.go index 778b5134e4c2e0..2b2f752833d57e 100644 --- a/pkg/secrets/check_rights_windows_test.go +++ b/comp/core/secrets/secretsimpl/check_rights_windows_test.go @@ -3,9 +3,9 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2018-present Datadog, Inc. -//go:build secrets && windows +//go:build windows -package secrets +package secretsimpl import ( "os" diff --git a/pkg/secrets/exec_nix.go b/comp/core/secrets/secretsimpl/exec_nix.go similarity index 91% rename from pkg/secrets/exec_nix.go rename to comp/core/secrets/secretsimpl/exec_nix.go index 79008cb9d44ef5..d3d893f067e041 100644 --- a/pkg/secrets/exec_nix.go +++ b/comp/core/secrets/secretsimpl/exec_nix.go @@ -3,9 +3,9 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2016-present Datadog, Inc. -//go:build secrets && !windows +//go:build !windows -package secrets +package secretsimpl import ( "context" diff --git a/pkg/secrets/exec_windows.go b/comp/core/secrets/secretsimpl/exec_windows.go similarity index 98% rename from pkg/secrets/exec_windows.go rename to comp/core/secrets/secretsimpl/exec_windows.go index 5cc4c7aa4cd184..2d37d05f7c4cab 100644 --- a/pkg/secrets/exec_windows.go +++ b/comp/core/secrets/secretsimpl/exec_windows.go @@ -3,9 +3,9 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2018-present Datadog, Inc. -//go:build secrets && windows +//go:build windows -package secrets +package secretsimpl import ( "context" diff --git a/pkg/secrets/fetch_secret.go b/comp/core/secrets/secretsimpl/fetch_secret.go similarity index 73% rename from pkg/secrets/fetch_secret.go rename to comp/core/secrets/secretsimpl/fetch_secret.go index 441b7c1a441354..6787055f335987 100644 --- a/pkg/secrets/fetch_secret.go +++ b/comp/core/secrets/secretsimpl/fetch_secret.go @@ -3,9 +3,7 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2016-present Datadog, Inc. -//go:build secrets - -package secrets +package secretsimpl import ( "bytes" @@ -18,13 +16,11 @@ import ( "strings" "time" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/telemetry" "github.com/DataDog/datadog-agent/pkg/util/log" ) -// PayloadVersion defines the current payload version sent to a secret backend -const PayloadVersion = "1.0" - var ( tlmSecretBackendElapsed = telemetry.NewGauge("secret_backend", "elapsed_ms", []string{"command", "exit_code"}, "Elapsed time of secret backend invocation") ) @@ -41,18 +37,30 @@ func (b *limitBuffer) Write(p []byte) (n int, err error) { return b.buf.Write(p) } -func execCommand(inputPayload string) ([]byte, error) { +func (r *secretResolver) execCommand(inputPayload string) ([]byte, error) { + if r.commandHookFunc != nil { + return r.commandHookFunc(inputPayload) + } + commandTimeout := r.backendTimeout + if commandTimeout == 0 { + commandTimeout = SecretBackendTimeoutDefault + } + responseMaxSize := r.responseMaxSize + if responseMaxSize == 0 { + responseMaxSize = SecretBackendOutputMaxSizeDefault + } + ctx, cancel := context.WithTimeout(context.Background(), - time.Duration(secretBackendTimeout)*time.Second) + time.Duration(commandTimeout)*time.Second) defer cancel() - cmd, done, err := commandContext(ctx, secretBackendCommand, secretBackendArguments...) + cmd, done, err := commandContext(ctx, r.backendCommand, r.backendArguments...) if err != nil { return nil, err } defer done() - if err := checkRights(cmd.Path, secretBackendCommandAllowGroupExec); err != nil { + if err := checkRights(cmd.Path, r.commandAllowGroupExec); err != nil { return nil, err } @@ -60,11 +68,11 @@ func execCommand(inputPayload string) ([]byte, error) { stdout := limitBuffer{ buf: &bytes.Buffer{}, - max: secretBackendOutputMaxSize, + max: responseMaxSize, } stderr := limitBuffer{ buf: &bytes.Buffer{}, - max: secretBackendOutputMaxSize, + max: responseMaxSize, } cmd.Stdout = &stdout cmd.Stderr = &stderr @@ -78,7 +86,7 @@ func execCommand(inputPayload string) ([]byte, error) { start := time.Now() err = cmd.Run() elapsed := time.Since(start) - log.Debugf("%s | secret_backend_command '%s' completed in %s", time.Now().String(), secretBackendCommand, elapsed) + log.Debugf("%s | secret_backend_command '%s' completed in %s", time.Now().String(), r.backendCommand, elapsed) // We always log stderr to allow a secret_backend_command to logs info in the agent log file. This is useful to // troubleshoot secret_backend_command in a containerized environment. @@ -92,46 +100,37 @@ func execCommand(inputPayload string) ([]byte, error) { } else if ctx.Err() == context.DeadlineExceeded { exitCode = "timeout" } - tlmSecretBackendElapsed.Add(float64(elapsed.Milliseconds()), secretBackendCommand, exitCode) + tlmSecretBackendElapsed.Add(float64(elapsed.Milliseconds()), r.backendCommand, exitCode) if ctx.Err() == context.DeadlineExceeded { - return nil, fmt.Errorf("error while running '%s': command timeout", secretBackendCommand) + return nil, fmt.Errorf("error while running '%s': command timeout", r.backendCommand) } - return nil, fmt.Errorf("error while running '%s': %s", secretBackendCommand, err) + return nil, fmt.Errorf("error while running '%s': %s", r.backendCommand, err) } log.Debugf("secret_backend_command stderr: %s", stderr.buf.String()) - tlmSecretBackendElapsed.Add(float64(elapsed.Milliseconds()), secretBackendCommand, "0") + tlmSecretBackendElapsed.Add(float64(elapsed.Milliseconds()), r.backendCommand, "0") return stdout.buf.Bytes(), nil } -// Secret defines the structure for secrets in JSON output -type Secret struct { - Value string `json:"value,omitempty"` - ErrorMsg string `json:"error,omitempty"` -} - -// for testing purpose -var runCommand = execCommand - // fetchSecret receives a list of secrets name to fetch, exec a custom // executable to fetch the actual secrets and returns them. -func fetchSecret(secretsHandle []string) (map[string]string, error) { +func (r *secretResolver) fetchSecret(secretsHandle []string) (map[string]string, error) { payload := map[string]interface{}{ - "version": PayloadVersion, + "version": secrets.PayloadVersion, "secrets": secretsHandle, } jsonPayload, err := json.Marshal(payload) if err != nil { return nil, fmt.Errorf("could not serialize secrets IDs to fetch password: %s", err) } - output, err := runCommand(string(jsonPayload)) + output, err := r.execCommand(string(jsonPayload)) if err != nil { return nil, err } - secrets := map[string]Secret{} + secrets := map[string]secrets.SecretVal{} err = json.Unmarshal(output, &secrets) if err != nil { return nil, fmt.Errorf("could not unmarshal 'secret_backend_command' output: %s", err) @@ -148,7 +147,7 @@ func fetchSecret(secretsHandle []string) (map[string]string, error) { return nil, fmt.Errorf("an error occurred while decrypting '%s': %s", sec, v.ErrorMsg) } - if removeTrailingLinebreak { + if r.removeTrailingLinebreak { v.Value = strings.TrimRight(v.Value, "\r\n") } @@ -157,7 +156,7 @@ func fetchSecret(secretsHandle []string) (map[string]string, error) { } // add it to the cache - secretCache[sec] = v.Value + r.cache[sec] = v.Value res[sec] = v.Value } return res, nil diff --git a/pkg/secrets/fetch_secret_test.go b/comp/core/secrets/secretsimpl/fetch_secret_test.go similarity index 61% rename from pkg/secrets/fetch_secret_test.go rename to comp/core/secrets/secretsimpl/fetch_secret_test.go index 32cbb2a297a441..68f8187dd7ae81 100644 --- a/pkg/secrets/fetch_secret_test.go +++ b/comp/core/secrets/secretsimpl/fetch_secret_test.go @@ -3,9 +3,7 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2016-present Datadog, Inc. -//go:build secrets - -package secrets +package secretsimpl import ( "bytes" @@ -15,6 +13,7 @@ import ( "runtime" "testing" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -82,145 +81,136 @@ func TestLimitBuffer(t *testing.T) { } func TestExecCommandError(t *testing.T) { - inputPayload := "{\"version\": \"" + PayloadVersion + "\" , \"secrets\": [\"sec1\", \"sec2\"]}" + inputPayload := "{\"version\": \"" + secrets.PayloadVersion + "\" , \"secrets\": [\"sec1\", \"sec2\"]}" t.Run("Empty secretBackendCommand", func(t *testing.T) { - t.Cleanup(resetPackageVars) - secretBackendCommand = "" - _, err := execCommand(inputPayload) + resolver := newEnabledSecretResolver() + _, err := resolver.execCommand(inputPayload) require.NotNil(t, err) }) t.Run("timeout", func(t *testing.T) { - t.Cleanup(resetPackageVars) - secretBackendCommand = "./test/timeout/timeout" + binExtension - setCorrectRight(secretBackendCommand) - secretBackendTimeout = 1 - _, err := execCommand(inputPayload) + resolver := newEnabledSecretResolver() + resolver.backendCommand = "./test/timeout/timeout" + binExtension + setCorrectRight(resolver.backendCommand) + resolver.backendTimeout = 1 + _, err := resolver.execCommand(inputPayload) require.NotNil(t, err) require.Equal(t, "error while running './test/timeout/timeout"+binExtension+"': command timeout", err.Error()) }) t.Run("No Error", func(t *testing.T) { - t.Cleanup(resetPackageVars) - secretBackendCommand = "./test/simple/simple" + binExtension - setCorrectRight(secretBackendCommand) - resp, err := execCommand(inputPayload) + resolver := newEnabledSecretResolver() + resolver.backendCommand = "./test/simple/simple" + binExtension + setCorrectRight(resolver.backendCommand) + resp, err := resolver.execCommand(inputPayload) require.NoError(t, err) require.Equal(t, []byte("{\"handle1\":{\"value\":\"simple_password\"}}"), resp) }) t.Run("Error returned", func(t *testing.T) { - t.Cleanup(resetPackageVars) - secretBackendCommand = "./test/error/error" + binExtension - setCorrectRight(secretBackendCommand) - _, err := execCommand(inputPayload) + resolver := newEnabledSecretResolver() + resolver.backendCommand = "./test/error/error" + binExtension + setCorrectRight(resolver.backendCommand) + _, err := resolver.execCommand(inputPayload) require.NotNil(t, err) }) t.Run("argument", func(t *testing.T) { - t.Cleanup(resetPackageVars) - secretBackendCommand = "./test/argument/argument" + binExtension - setCorrectRight(secretBackendCommand) - secretBackendArguments = []string{"arg1"} - _, err := execCommand(inputPayload) + resolver := newEnabledSecretResolver() + resolver.backendCommand = "./test/argument/argument" + binExtension + setCorrectRight(resolver.backendCommand) + resolver.backendArguments = []string{"arg1"} + _, err := resolver.execCommand(inputPayload) require.NotNil(t, err) - secretBackendArguments = []string{"arg1", "arg2"} - resp, err := execCommand(inputPayload) + resolver.backendArguments = []string{"arg1", "arg2"} + resp, err := resolver.execCommand(inputPayload) require.NoError(t, err) require.Equal(t, []byte("{\"handle1\":{\"value\":\"arg_password\"}}"), resp) }) t.Run("input", func(t *testing.T) { - t.Cleanup(resetPackageVars) - secretBackendCommand = "./test/input/input" + binExtension - setCorrectRight(secretBackendCommand) - resp, err := execCommand(inputPayload) + resolver := newEnabledSecretResolver() + resolver.backendCommand = "./test/input/input" + binExtension + setCorrectRight(resolver.backendCommand) + resp, err := resolver.execCommand(inputPayload) require.NoError(t, err) require.Equal(t, []byte("{\"handle1\":{\"value\":\"input_password\"}}"), resp) }) t.Run("buffer limit", func(t *testing.T) { - t.Cleanup(resetPackageVars) - secretBackendCommand = "./test/response_too_long/response_too_long" + binExtension - setCorrectRight(secretBackendCommand) - secretBackendOutputMaxSize = 20 - _, err := execCommand(inputPayload) + resolver := newEnabledSecretResolver() + resolver.backendCommand = "./test/response_too_long/response_too_long" + binExtension + setCorrectRight(resolver.backendCommand) + resolver.responseMaxSize = 20 + _, err := resolver.execCommand(inputPayload) require.NotNil(t, err) assert.Equal(t, "error while running './test/response_too_long/response_too_long"+binExtension+"': command output was too long: exceeded 20 bytes", err.Error()) }) } -func TestFetchSecretExecError(t *testing.T) { - t.Cleanup(resetPackageVars) - - runCommand = func(string) ([]byte, error) { return nil, fmt.Errorf("some error") } - _, err := fetchSecret([]string{"handle1", "handle2"}) +func TestFetchSecretExeceError(t *testing.T) { + resolver := newEnabledSecretResolver() + resolver.commandHookFunc = func(string) ([]byte, error) { return nil, fmt.Errorf("some error") } + _, err := resolver.fetchSecret([]string{"handle1", "handle2"}) assert.NotNil(t, err) } func TestFetchSecretUnmarshalError(t *testing.T) { - t.Cleanup(resetPackageVars) - - runCommand = func(string) ([]byte, error) { return []byte("{"), nil } - _, err := fetchSecret([]string{"handle1", "handle2"}) + resolver := newEnabledSecretResolver() + resolver.commandHookFunc = func(string) ([]byte, error) { return []byte("{"), nil } + _, err := resolver.fetchSecret([]string{"handle1", "handle2"}) assert.NotNil(t, err) } func TestFetchSecretMissingSecret(t *testing.T) { - t.Cleanup(resetPackageVars) - secrets := []string{"handle1", "handle2"} - - runCommand = func(string) ([]byte, error) { return []byte("{}"), nil } - _, err := fetchSecret(secrets) + resolver := newEnabledSecretResolver() + resolver.commandHookFunc = func(string) ([]byte, error) { return []byte("{}"), nil } + _, err := resolver.fetchSecret(secrets) assert.NotNil(t, err) assert.Equal(t, "secret handle 'handle1' was not decrypted by the secret_backend_command", err.Error()) } func TestFetchSecretErrorForHandle(t *testing.T) { - t.Cleanup(resetPackageVars) - - runCommand = func(string) ([]byte, error) { + resolver := newEnabledSecretResolver() + resolver.commandHookFunc = func(string) ([]byte, error) { return []byte("{\"handle1\":{\"value\": null, \"error\": \"some error\"}}"), nil } - _, err := fetchSecret([]string{"handle1"}) + _, err := resolver.fetchSecret([]string{"handle1"}) assert.NotNil(t, err) assert.Equal(t, "an error occurred while decrypting 'handle1': some error", err.Error()) } func TestFetchSecretEmptyValue(t *testing.T) { - t.Cleanup(resetPackageVars) - - runCommand = func(string) ([]byte, error) { + resolver := newEnabledSecretResolver() + resolver.commandHookFunc = func(string) ([]byte, error) { return []byte("{\"handle1\":{\"value\": null}}"), nil } - _, err := fetchSecret([]string{"handle1"}) + _, err := resolver.fetchSecret([]string{"handle1"}) assert.NotNil(t, err) assert.Equal(t, "decrypted secret for 'handle1' is empty", err.Error()) - runCommand = func(string) ([]byte, error) { + resolver.commandHookFunc = func(string) ([]byte, error) { return []byte("{\"handle1\":{\"value\": \"\"}}"), nil } - _, err = fetchSecret([]string{"handle1"}) + _, err = resolver.fetchSecret([]string{"handle1"}) assert.NotNil(t, err) assert.Equal(t, "decrypted secret for 'handle1' is empty", err.Error()) } func TestFetchSecret(t *testing.T) { - t.Cleanup(resetPackageVars) - secrets := []string{"handle1", "handle2"} + resolver := newEnabledSecretResolver() // some dummy value to check the cache is not purge - secretCache["test"] = "yes" - - runCommand = func(string) ([]byte, error) { + resolver.cache["test"] = "yes" + resolver.commandHookFunc = func(string) ([]byte, error) { res := []byte("{\"handle1\":{\"value\":\"p1\"},") res = append(res, []byte("\"handle2\":{\"value\":\"p2\"},")...) res = append(res, []byte("\"handle3\":{\"value\":\"p3\"}}")...) return res, nil } - resp, err := fetchSecret(secrets) + resp, err := resolver.fetchSecret(secrets) require.NoError(t, err) assert.Equal(t, map[string]string{ "handle1": "p1", @@ -230,18 +220,17 @@ func TestFetchSecret(t *testing.T) { "test": "yes", "handle1": "p1", "handle2": "p2", - }, secretCache) + }, resolver.cache) } func TestFetchSecretRemoveTrailingLineBreak(t *testing.T) { - t.Cleanup(resetPackageVars) - removeTrailingLinebreak = true - - runCommand = func(string) ([]byte, error) { + resolver := newEnabledSecretResolver() + resolver.commandHookFunc = func(string) ([]byte, error) { return []byte("{\"handle1\":{\"value\":\"some data\\r\\n\"}}"), nil } + resolver.removeTrailingLinebreak = true secrets := []string{"handle1"} - resp, err := fetchSecret(secrets) + resp, err := resolver.fetchSecret(secrets) require.NoError(t, err) assert.Equal(t, map[string]string{"handle1": "some data"}, resp) } diff --git a/pkg/secrets/info.tmpl b/comp/core/secrets/secretsimpl/info.tmpl similarity index 100% rename from pkg/secrets/info.tmpl rename to comp/core/secrets/secretsimpl/info.tmpl diff --git a/pkg/secrets/info_nix.go b/comp/core/secrets/secretsimpl/info_nix.go similarity index 79% rename from pkg/secrets/info_nix.go rename to comp/core/secrets/secretsimpl/info_nix.go index ac396aa3edcfb7..3ab467ac5585b1 100644 --- a/pkg/secrets/info_nix.go +++ b/comp/core/secrets/secretsimpl/info_nix.go @@ -3,9 +3,9 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2016-present Datadog, Inc. -//go:build secrets && !windows +//go:build !windows -package secrets +package secretsimpl import ( _ "embed" @@ -24,10 +24,10 @@ type permissionsDetails struct { Group string } -func getExecutablePermissions() (interface{}, error) { +func getExecutablePermissions(secret *secretResolver) (interface{}, error) { var stat syscall.Stat_t - if err := syscall.Stat(secretBackendCommand, &stat); err != nil { - return nil, fmt.Errorf("Could not stat %s: %s", secretBackendCommand, err) + if err := syscall.Stat(secret.backendCommand, &stat); err != nil { + return nil, fmt.Errorf("Could not stat %s: %s", secret.backendCommand, err) } details := permissionsDetails{ diff --git a/pkg/secrets/info_nix.tmpl b/comp/core/secrets/secretsimpl/info_nix.tmpl similarity index 100% rename from pkg/secrets/info_nix.tmpl rename to comp/core/secrets/secretsimpl/info_nix.tmpl diff --git a/pkg/secrets/info_nix_test.go b/comp/core/secrets/secretsimpl/info_nix_test.go similarity index 73% rename from pkg/secrets/info_nix_test.go rename to comp/core/secrets/secretsimpl/info_nix_test.go index d78380ed92275f..aae8a06a274043 100644 --- a/pkg/secrets/info_nix_test.go +++ b/comp/core/secrets/secretsimpl/info_nix_test.go @@ -3,9 +3,9 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2016-present Datadog, Inc. -//go:build secrets && !windows +//go:build !windows -package secrets +package secretsimpl import ( "bytes" @@ -27,22 +27,21 @@ instances: ) func TestGetExecutablePermissionsError(t *testing.T) { - secretBackendCommand = "some_command" - t.Cleanup(resetPackageVars) + resolver := newEnabledSecretResolver() + resolver.backendCommand = "some_command" - _, err := getExecutablePermissions() + _, err := getExecutablePermissions(resolver) assert.Error(t, err, "getExecutablePermissions should fail when secretBackendCommand file does not exists") } -func setupSecretCommmand(t *testing.T) (string, string) { +func setupSecretCommand(t *testing.T, resolver *secretResolver) (string, string) { dir := t.TempDir() - t.Cleanup(resetPackageVars) - secretBackendCommand = filepath.Join(dir, "executable") - f, err := os.Create(secretBackendCommand) + resolver.backendCommand = filepath.Join(dir, "executable") + f, err := os.Create(resolver.backendCommand) require.NoError(t, err) f.Close() - os.Chmod(secretBackendCommand, 0700) + os.Chmod(resolver.backendCommand, 0700) u, err := user.Current() require.NoError(t, err) @@ -55,9 +54,10 @@ func setupSecretCommmand(t *testing.T) (string, string) { } func TestGetExecutablePermissionsSuccess(t *testing.T) { - currentUser, currentGroup := setupSecretCommmand(t) + resolver := newEnabledSecretResolver() + currentUser, currentGroup := setupSecretCommand(t, resolver) - res, err := getExecutablePermissions() + res, err := getExecutablePermissions(resolver) require.NoError(t, err) require.IsType(t, permissionsDetails{}, res) details := res.(permissionsDetails) @@ -67,25 +67,26 @@ func TestGetExecutablePermissionsSuccess(t *testing.T) { } func TestDebugInfo(t *testing.T) { - currentUser, currentGroup := setupSecretCommmand(t) + resolver := newEnabledSecretResolver() + currentUser, currentGroup := setupSecretCommand(t, resolver) - runCommand = func(string) ([]byte, error) { + resolver.commandHookFunc = func(string) ([]byte, error) { res := []byte("{\"pass1\":{\"value\":\"password1\"},") res = append(res, []byte("\"pass2\":{\"value\":\"password2\"},")...) res = append(res, []byte("\"pass3\":{\"value\":\"password3\"}}")...) return res, nil } - _, err := Decrypt(testConf, "test") + _, err := resolver.Decrypt(testConf, "test") require.NoError(t, err) - _, err = Decrypt(testConfInfo, "test2") + _, err = resolver.Decrypt(testConfInfo, "test2") require.NoError(t, err) var buffer bytes.Buffer - GetDebugInfo(&buffer) + resolver.GetDebugInfo(&buffer) expectedResult := `=== Checking executable permissions === -Executable path: ` + secretBackendCommand + ` +Executable path: ` + resolver.backendCommand + ` Executable permissions: OK, the executable has the correct permissions Permissions Detail: @@ -110,23 +111,23 @@ Secrets handle decrypted: } func TestDebugInfoError(t *testing.T) { - secretBackendCommand = "some_command" - t.Cleanup(resetPackageVars) + resolver := newEnabledSecretResolver() + resolver.backendCommand = "some_command" - runCommand = func(string) ([]byte, error) { + resolver.commandHookFunc = func(string) ([]byte, error) { res := []byte("{\"pass1\":{\"value\":\"password1\"},") res = append(res, []byte("\"pass2\":{\"value\":\"password2\"},")...) res = append(res, []byte("\"pass3\":{\"value\":\"password3\"}}")...) return res, nil } - _, err := Decrypt(testConf, "test") + _, err := resolver.Decrypt(testConf, "test") require.NoError(t, err) - _, err = Decrypt(testConfInfo, "test2") + _, err = resolver.Decrypt(testConfInfo, "test2") require.NoError(t, err) var buffer bytes.Buffer - GetDebugInfo(&buffer) + resolver.GetDebugInfo(&buffer) expectedResult := `=== Checking executable permissions === Executable path: some_command diff --git a/pkg/secrets/info_win.tmpl b/comp/core/secrets/secretsimpl/info_win.tmpl similarity index 100% rename from pkg/secrets/info_win.tmpl rename to comp/core/secrets/secretsimpl/info_win.tmpl diff --git a/pkg/secrets/info_windows.go b/comp/core/secrets/secretsimpl/info_windows.go similarity index 96% rename from pkg/secrets/info_windows.go rename to comp/core/secrets/secretsimpl/info_windows.go index c2c7d57b056c14..bda448b39fe36b 100644 --- a/pkg/secrets/info_windows.go +++ b/comp/core/secrets/secretsimpl/info_windows.go @@ -3,9 +3,9 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2016-present Datadog, Inc. -//go:build secrets && windows +//go:build windows -package secrets +package secretsimpl import ( "bytes" diff --git a/pkg/secrets/info_windows_test.go b/comp/core/secrets/secretsimpl/info_windows_test.go similarity index 97% rename from pkg/secrets/info_windows_test.go rename to comp/core/secrets/secretsimpl/info_windows_test.go index 926f6c834cfd47..63200960e14ae8 100644 --- a/pkg/secrets/info_windows_test.go +++ b/comp/core/secrets/secretsimpl/info_windows_test.go @@ -3,9 +3,9 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2016-present Datadog, Inc. -//go:build secrets && windows +//go:build windows -package secrets +package secretsimpl import ( "fmt" diff --git a/pkg/secrets/secrets.go b/comp/core/secrets/secretsimpl/secrets.go similarity index 58% rename from pkg/secrets/secrets.go rename to comp/core/secrets/secretsimpl/secrets.go index a9608e2b6f20b5..358df4e5afd137 100644 --- a/pkg/secrets/secrets.go +++ b/comp/core/secrets/secretsimpl/secrets.go @@ -3,45 +3,72 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2016-present Datadog, Inc. -//go:build secrets - -package secrets +// Package secretsimpl is the implementation for the secrets component +package secretsimpl import ( + "bufio" + "bytes" _ "embed" "fmt" "io" "sort" "strings" + "sync" "text/template" + "go.uber.org/fx" yaml "gopkg.in/yaml.v2" + flaretypes "github.com/DataDog/datadog-agent/comp/core/flare/types" + "github.com/DataDog/datadog-agent/comp/core/secrets" + "github.com/DataDog/datadog-agent/pkg/util/fxutil" "github.com/DataDog/datadog-agent/pkg/util/log" "github.com/DataDog/datadog-agent/pkg/util/scrubber" ) -type handleToContext map[string][]secretContext +type provides struct { + fx.Out -var ( - // testing purpose - secretFetcher = fetchSecret - scrubberAddReplacer = scrubber.AddStrippedKeys + Comp secrets.Component + FlareProvider flaretypes.Provider +} - secretCache map[string]string - // list of handles and where they were found - secretOrigin handleToContext +type dependencies struct { + fx.In - secretBackendCommand string - secretBackendArguments []string - secretBackendTimeout = SecretBackendTimeoutDefault - secretBackendCommandAllowGroupExec bool - removeTrailingLinebreak bool + Params secrets.Params +} - // SecretBackendOutputMaxSize defines max size of the JSON output from a secrets reader backend - secretBackendOutputMaxSize = SecretBackendOutputMaxSizeDefault +// Module defines the fx options for this component. +var Module = fxutil.Component( + fx.Provide(newSecretResolverProvider), ) +type handleToContext map[string][]secretContext + +type secretResolver struct { + enabled bool + cache map[string]string + // list of handles and where they were found + origin handleToContext + + backendCommand string + backendArguments []string + backendTimeout int + commandAllowGroupExec bool + removeTrailingLinebreak bool + // responseMaxSize defines max size of the JSON output from a secrets reader backend + responseMaxSize int + + // can be overridden for testing purposes + commandHookFunc func(string) ([]byte, error) + fetchHookFunc func([]string) (map[string]string, error) + scrubHookFunc func([]string) +} + +var _ secrets.Component = (*secretResolver)(nil) + //go:embed info.tmpl var secretInfoTmpl string @@ -53,14 +80,72 @@ type secretContext struct { yamlPath string } -func init() { - secretCache = make(map[string]string) - secretOrigin = make(handleToContext) +// TODO: Hack to maintain a singleton reference to the secrets Component +// +// Only needed temporarily, since the secrets.Component is needed for the diagnose functionality. +// It is very difficult right now to modify diagnose because it would require modifying many +// function signatures, which would only increase future maintenance. Once diagnose is better +// integrated with Components, we should be able to remove this hack. +// +// Other components should not copy this pattern, it is only meant to be used temporarily. +var mu sync.Mutex +var instance *secretResolver + +func newEnabledSecretResolver() *secretResolver { + return &secretResolver{ + cache: make(map[string]string), + origin: make(handleToContext), + enabled: true, + } } -func registerSecretOrigin(handle string, origin string, yamlPath []string) { +func newSecretResolverProvider(deps dependencies) provides { + resolver := newEnabledSecretResolver() + resolver.enabled = deps.Params.Enabled + + { + mu.Lock() + defer mu.Unlock() + if instance == nil { + instance = resolver + } + } + + return provides{ + Comp: resolver, + FlareProvider: flaretypes.NewProvider(resolver.fillFlare), + } +} + +func (r *secretResolver) IsEnabled() bool { + return r.enabled +} + +// GetInstance returns the singleton instance of the secret.Component +func GetInstance() secrets.Component { + mu.Lock() + defer mu.Unlock() + if instance == nil { + deps := dependencies{Params: secrets.Params{Enabled: true}} + p := newSecretResolverProvider(deps) + instance = p.Comp.(*secretResolver) + } + return instance +} + +// fillFlare add the inventory payload to flares. +func (r *secretResolver) fillFlare(fb flaretypes.FlareBuilder) error { + var buffer bytes.Buffer + writer := bufio.NewWriter(&buffer) + r.GetDebugInfo(writer) + writer.Flush() + fb.AddFile("secrets.log", buffer.Bytes()) + return nil +} + +func (r *secretResolver) registerSecretOrigin(handle string, origin string, yamlPath []string) { path := strings.Join(yamlPath, "/") - for _, info := range secretOrigin[handle] { + for _, info := range r.origin[handle] { if info.origin == origin && info.yamlPath == path { // The secret was used twice in the same configuration under the same key: nothing to do return @@ -69,28 +154,36 @@ func registerSecretOrigin(handle string, origin string, yamlPath []string) { if len(yamlPath) != 0 { lastElem := yamlPath[len(yamlPath)-1:] - scrubberAddReplacer(lastElem) + if r.scrubHookFunc != nil { + r.scrubHookFunc(lastElem) + } else { + scrubber.AddStrippedKeys(lastElem) + } } - secretOrigin[handle] = append( - secretOrigin[handle], + r.origin[handle] = append( + r.origin[handle], secretContext{ origin: origin, yamlPath: path, }) } -// Init initializes the command and other options of the secrets package. Since -// this package is used by the 'config' package to decrypt itself we can't -// directly use it. -func Init(command string, arguments []string, timeout int, maxSize int, groupExecPerm bool, removeLinebreak bool) { - secretBackendCommand = command - secretBackendArguments = arguments - secretBackendTimeout = timeout - secretBackendOutputMaxSize = maxSize - secretBackendCommandAllowGroupExec = groupExecPerm - removeTrailingLinebreak = removeLinebreak - if secretBackendCommandAllowGroupExec { +// Configure initializes the executable command and other options of the secrets component +func (r *secretResolver) Configure(command string, arguments []string, timeout, maxSize int, groupExecPerm, removeLinebreak bool) { + if !r.enabled { + log.Errorf("Agent secrets is disabled by caller") + return + } + r.backendCommand = command + r.backendArguments = arguments + r.backendTimeout = timeout + if maxSize != 0 { + r.responseMaxSize = maxSize + } + r.commandAllowGroupExec = groupExecPerm + r.removeTrailingLinebreak = removeLinebreak + if r.commandAllowGroupExec { log.Warnf("Agent configuration relax permissions constraint on the secret backend cmd, Group can read and exec") } } @@ -175,8 +268,13 @@ func isEnc(str string) (bool, string) { // Decrypt replaces all encrypted secrets in data by executing // "secret_backend_command" once if all secrets aren't present in the cache. -func Decrypt(data []byte, origin string) ([]byte, error) { - if data == nil || secretBackendCommand == "" { +func (r *secretResolver) Decrypt(data []byte, origin string) ([]byte, error) { + if !r.enabled { + e := fmt.Errorf("Agent secrets is disabled by caller") + log.Error(e) + return nil, e + } + if data == nil || r.backendCommand == "" { return data, nil } @@ -196,10 +294,10 @@ func Decrypt(data []byte, origin string) ([]byte, error) { if ok, handle := isEnc(str); ok { haveSecret = true // Check if we already know this secret - if secret, ok := secretCache[handle]; ok { + if secret, ok := r.cache[handle]; ok { log.Debugf("Secret '%s' was retrieved from cache", handle) // keep track of place where a handle was found - registerSecretOrigin(handle, origin, yamlPath) + r.registerSecretOrigin(handle, origin, yamlPath) return secret, nil } newHandles = append(newHandles, handle) @@ -217,7 +315,13 @@ func Decrypt(data []byte, origin string) ([]byte, error) { // check if any new secrets need to be fetch if len(newHandles) != 0 { - secrets, err := secretFetcher(newHandles) + var secrets map[string]string + var err error + if r.fetchHookFunc != nil { + secrets, err = r.fetchHookFunc(newHandles) + } else { + secrets, err = r.fetchSecret(newHandles) + } if err != nil { return nil, err } @@ -231,7 +335,7 @@ func Decrypt(data []byte, origin string) ([]byte, error) { if secret, ok := secrets[handle]; ok { log.Debugf("Secret '%s' was retrieved from executable", handle) // keep track of place where a handle was found - registerSecretOrigin(handle, origin, yamlPath) + r.registerSecretOrigin(handle, origin, yamlPath) return secret, nil } // This should never happen since fetchSecret will return an error @@ -261,8 +365,12 @@ type secretInfo struct { } // GetDebugInfo exposes debug informations about secrets to be included in a flare -func GetDebugInfo(w io.Writer) { - if secretBackendCommand == "" { +func (r *secretResolver) GetDebugInfo(w io.Writer) { + if !r.enabled { + log.Errorf("Agent secrets is disabled by caller") + return + } + if r.backendCommand == "" { fmt.Fprintf(w, "No secret_backend_command set: secrets feature is not enabled") return } @@ -280,16 +388,16 @@ func GetDebugInfo(w io.Writer) { return } - err = checkRights(secretBackendCommand, secretBackendCommandAllowGroupExec) + err = checkRights(r.backendCommand, r.commandAllowGroupExec) permissions := "OK, the executable has the correct permissions" if err != nil { permissions = fmt.Sprintf("error: %s", err) } - details, err := getExecutablePermissions() + details, err := getExecutablePermissions(r) info := secretInfo{ - Executable: secretBackendCommand, + Executable: r.backendCommand, ExecutablePermissions: permissions, ExecutablePermissionsDetails: details, Handles: map[string][][]string{}, @@ -300,13 +408,13 @@ func GetDebugInfo(w io.Writer) { // we sort handles so the output is consistent and testable orderedHandles := []string{} - for handle := range secretOrigin { + for handle := range r.origin { orderedHandles = append(orderedHandles, handle) } sort.Strings(orderedHandles) for _, handle := range orderedHandles { - contexts := secretOrigin[handle] + contexts := r.origin[handle] details := [][]string{} for _, context := range contexts { details = append(details, []string{context.origin, context.yamlPath}) diff --git a/pkg/secrets/secrets_default.go b/comp/core/secrets/secretsimpl/secrets_default.go similarity index 87% rename from pkg/secrets/secrets_default.go rename to comp/core/secrets/secretsimpl/secrets_default.go index a6c777676290e8..96e4199b3523ab 100644 --- a/pkg/secrets/secrets_default.go +++ b/comp/core/secrets/secretsimpl/secrets_default.go @@ -3,10 +3,10 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2016-present Datadog, Inc. -package secrets +package secretsimpl // SecretBackendTimeoutDefault is the default value of the secret_backend_timeout config. const SecretBackendTimeoutDefault = 30 // SecretBackendOutputMaxSizeDefault defines the default value of the max size of the JSON output from a secrets reader backend -var SecretBackendOutputMaxSizeDefault = 1024 * 1024 +const SecretBackendOutputMaxSizeDefault = 1024 * 1024 diff --git a/comp/core/secrets/secretsimpl/secrets_mock.go b/comp/core/secrets/secretsimpl/secrets_mock.go new file mode 100644 index 00000000000000..4e2bcd7c7862b4 --- /dev/null +++ b/comp/core/secrets/secretsimpl/secrets_mock.go @@ -0,0 +1,60 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2016-present Datadog, Inc. + +//go:build test + +package secretsimpl + +import ( + "io" + "regexp" + + "github.com/DataDog/datadog-agent/comp/core/secrets" + "github.com/DataDog/datadog-agent/pkg/util/fxutil" + "go.uber.org/fx" +) + +// MockSecretResolver is a mock of the secret Component useful for testing +type MockSecretResolver struct { + resolve map[string]string +} + +var _ secrets.Component = (*MockSecretResolver)(nil) + +// Configure is not implemented +func (m *MockSecretResolver) Configure(_ string, _ []string, _, _ int, _, _ bool) {} + +// GetDebugInfo is not implemented +func (m *MockSecretResolver) GetDebugInfo(_ io.Writer) {} + +// IsEnabled always returns true +func (m *MockSecretResolver) IsEnabled() bool { + return true +} + +// Inject adds data to be decrypted, by returning the value for the given key +func (m *MockSecretResolver) Inject(key, value string) { + m.resolve[key] = value +} + +// Decrypt returns the secret value based upon the injected data +func (m *MockSecretResolver) Decrypt(data []byte, _ string) ([]byte, error) { + re := regexp.MustCompile(`ENC\[(.*?)\]`) + result := re.ReplaceAllStringFunc(string(data), func(in string) string { + key := in[4 : len(in)-1] + return m.resolve[key] + }) + return []byte(result), nil +} + +// NewMockSecretResolver constructs a MockSecretResolver +func NewMockSecretResolver() *MockSecretResolver { + return &MockSecretResolver{resolve: make(map[string]string)} +} + +// MockModule is a module containing the mock, useful for testing +var MockModule = fxutil.Component( + fx.Provide(NewMockSecretResolver), +) diff --git a/pkg/secrets/secrets_test.go b/comp/core/secrets/secretsimpl/secrets_test.go similarity index 88% rename from pkg/secrets/secrets_test.go rename to comp/core/secrets/secretsimpl/secrets_test.go index 0d27442300ba8b..81e37cd7cd829b 100644 --- a/pkg/secrets/secrets_test.go +++ b/comp/core/secrets/secretsimpl/secrets_test.go @@ -3,9 +3,7 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2016-present Datadog, Inc. -//go:build secrets - -package secrets +package secretsimpl import ( "fmt" @@ -15,8 +13,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" yaml "gopkg.in/yaml.v2" - - "github.com/DataDog/datadog-agent/pkg/util/scrubber" ) var ( @@ -133,18 +129,6 @@ some: } ) -func resetPackageVars() { - secretBackendCommand = "" - secretBackendArguments = []string{} - secretCache = map[string]string{} - secretOrigin = make(handleToContext) - secretFetcher = fetchSecret - secretBackendTimeout = SecretBackendTimeoutDefault - scrubberAddReplacer = scrubber.AddStrippedKeys - removeTrailingLinebreak = false - secretBackendOutputMaxSize = SecretBackendOutputMaxSizeDefault -} - func TestIsEnc(t *testing.T) { enc, secret := isEnc("") assert.False(t, enc) @@ -232,26 +216,26 @@ func TestWalkerComplex(t *testing.T) { } func TestDecryptNoCommand(t *testing.T) { - defer resetPackageVars() - secretFetcher = func(secrets []string) (map[string]string, error) { + resolver := newEnabledSecretResolver() + resolver.fetchHookFunc = func(secrets []string) (map[string]string, error) { return nil, fmt.Errorf("some error") } // since we didn't set any command this should return without any error - resConf, err := Decrypt(testConf, "test") + resConf, err := resolver.Decrypt(testConf, "test") require.NoError(t, err) assert.Equal(t, testConf, resConf) } func TestDecryptSecretError(t *testing.T) { - secretBackendCommand = "some_command" - defer resetPackageVars() + resolver := newEnabledSecretResolver() + resolver.backendCommand = "some_command" - secretFetcher = func(secrets []string) (map[string]string, error) { + resolver.fetchHookFunc = func(secrets []string) (map[string]string, error) { return nil, fmt.Errorf("some error") } - _, err := Decrypt(testConf, "test") + _, err := resolver.Decrypt(testConf, "test") require.NotNil(t, err) } @@ -374,21 +358,21 @@ func TestDecrypt(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { currentTest = t - t.Cleanup(resetPackageVars) - secretBackendCommand = "some_command" + resolver := newEnabledSecretResolver() + resolver.backendCommand = "some_command" if tc.secretCache != nil { - secretCache = tc.secretCache + resolver.cache = tc.secretCache } - secretFetcher = tc.secretFetchCB + resolver.fetchHookFunc = tc.secretFetchCB scrubbedKey := []string{} - scrubberAddReplacer = func(k []string) { scrubbedKey = append(scrubbedKey, k[0]) } + resolver.scrubHookFunc = func(k []string) { scrubbedKey = append(scrubbedKey, k[0]) } - newConf, err := Decrypt(tc.testConf, "test") + newConf, err := resolver.Decrypt(tc.testConf, "test") require.NoError(t, err) assert.Equal(t, tc.decryptedConf, string(newConf)) - assert.Equal(t, tc.expectedSecretOrigin, secretOrigin) + assert.Equal(t, tc.expectedSecretOrigin, resolver.origin) assert.Equal(t, tc.expectedScrubbedKey, scrubbedKey) }) } diff --git a/pkg/secrets/test/argument/argument.go b/comp/core/secrets/secretsimpl/test/argument/argument.go similarity index 100% rename from pkg/secrets/test/argument/argument.go rename to comp/core/secrets/secretsimpl/test/argument/argument.go diff --git a/pkg/secrets/test/error/error.go b/comp/core/secrets/secretsimpl/test/error/error.go similarity index 100% rename from pkg/secrets/test/error/error.go rename to comp/core/secrets/secretsimpl/test/error/error.go diff --git a/pkg/secrets/test/input/input.go b/comp/core/secrets/secretsimpl/test/input/input.go similarity index 100% rename from pkg/secrets/test/input/input.go rename to comp/core/secrets/secretsimpl/test/input/input.go diff --git a/pkg/secrets/test/response_too_long/response_too_long.go b/comp/core/secrets/secretsimpl/test/response_too_long/response_too_long.go similarity index 100% rename from pkg/secrets/test/response_too_long/response_too_long.go rename to comp/core/secrets/secretsimpl/test/response_too_long/response_too_long.go diff --git a/pkg/secrets/test/setAcl.ps1 b/comp/core/secrets/secretsimpl/test/setAcl.ps1 similarity index 100% rename from pkg/secrets/test/setAcl.ps1 rename to comp/core/secrets/secretsimpl/test/setAcl.ps1 diff --git a/pkg/secrets/test/simple/simple.go b/comp/core/secrets/secretsimpl/test/simple/simple.go similarity index 100% rename from pkg/secrets/test/simple/simple.go rename to comp/core/secrets/secretsimpl/test/simple/simple.go diff --git a/pkg/secrets/test/timeout/timeout.go b/comp/core/secrets/secretsimpl/test/timeout/timeout.go similarity index 100% rename from pkg/secrets/test/timeout/timeout.go rename to comp/core/secrets/secretsimpl/test/timeout/timeout.go diff --git a/comp/core/secrets/type.go b/comp/core/secrets/type.go new file mode 100644 index 00000000000000..72f07c8389b722 --- /dev/null +++ b/comp/core/secrets/type.go @@ -0,0 +1,15 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2018-present Datadog, Inc. + +package secrets + +// SecretVal defines the structure for secrets in JSON output +type SecretVal struct { + Value string `json:"value,omitempty"` + ErrorMsg string `json:"error,omitempty"` +} + +// PayloadVersion defines the current payload version sent to a secret backend +const PayloadVersion = "1.0" diff --git a/comp/languagedetection/bundle_test.go b/comp/languagedetection/bundle_test.go index 5091f80d9d07b8..308fc83cc296d9 100644 --- a/comp/languagedetection/bundle_test.go +++ b/comp/languagedetection/bundle_test.go @@ -10,6 +10,8 @@ import ( "github.com/DataDog/datadog-agent/comp/core/config" "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" + "github.com/DataDog/datadog-agent/comp/core/secrets/secretsimpl" "github.com/DataDog/datadog-agent/comp/core/telemetry" "github.com/DataDog/datadog-agent/comp/core/workloadmeta" "github.com/DataDog/datadog-agent/comp/languagedetection/client" @@ -25,6 +27,8 @@ func TestBundleDependencies(t *testing.T) { fx.Supply(config.Params{}), telemetry.Module, log.Module, + fx.Provide(func() secrets.Component { return secretsimpl.NewMockSecretResolver() }), + secretsimpl.MockModule, fx.Supply(log.Params{}), workloadmeta.Module, fx.Supply(workloadmeta.NewParams()), diff --git a/comp/trace/bundle.go b/comp/trace/bundle.go index cc9451e8e49b79..eb9d2f4232097f 100644 --- a/comp/trace/bundle.go +++ b/comp/trace/bundle.go @@ -12,6 +12,7 @@ package trace import ( + "github.com/DataDog/datadog-agent/comp/core/secrets/secretsimpl" "github.com/DataDog/datadog-agent/comp/trace/agent" "github.com/DataDog/datadog-agent/comp/trace/config" "github.com/DataDog/datadog-agent/pkg/util/fxutil" @@ -23,4 +24,5 @@ import ( var Bundle = fxutil.Bundle( config.Module, agent.Module, + secretsimpl.Module, ) diff --git a/comp/trace/bundle_test.go b/comp/trace/bundle_test.go index 5a6d3890700d9a..331de93b1dbfdb 100644 --- a/comp/trace/bundle_test.go +++ b/comp/trace/bundle_test.go @@ -14,6 +14,8 @@ import ( "go.uber.org/fx" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" + "github.com/DataDog/datadog-agent/comp/core/secrets/secretsimpl" "github.com/DataDog/datadog-agent/comp/core/workloadmeta" "github.com/DataDog/datadog-agent/comp/trace/agent" "github.com/DataDog/datadog-agent/comp/trace/config" @@ -32,6 +34,8 @@ func TestBundleDependencies(t *testing.T) { fx.Supply(workloadmeta.NewParams()), workloadmeta.Module, fx.Provide(func(cfg config.Component) telemetry.TelemetryCollector { return telemetry.NewCollector(cfg.Object()) }), + secretsimpl.MockModule, + fx.Provide(secrets.NewDisabledParams), fx.Supply(&agent.Params{}), ) } diff --git a/pkg/autodiscovery/autoconfig.go b/pkg/autodiscovery/autoconfig.go index c2664953078f48..526eddf95df184 100644 --- a/pkg/autodiscovery/autoconfig.go +++ b/pkg/autodiscovery/autoconfig.go @@ -13,6 +13,7 @@ import ( "go.uber.org/atomic" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/autodiscovery/integration" "github.com/DataDog/datadog-agent/pkg/autodiscovery/listeners" "github.com/DataDog/datadog-agent/pkg/autodiscovery/providers" @@ -64,8 +65,8 @@ func (l *listenerCandidate) try() (listeners.ServiceListener, error) { } // NewAutoConfig creates an AutoConfig instance and starts it. -func NewAutoConfig(scheduler *scheduler.MetaScheduler) *AutoConfig { - ac := NewAutoConfigNoStart(scheduler) +func NewAutoConfig(scheduler *scheduler.MetaScheduler, secretResolver secrets.Component) *AutoConfig { + ac := NewAutoConfigNoStart(scheduler, secretResolver) // We need to listen to the service channels before anything is sent to them go ac.serviceListening() @@ -74,8 +75,8 @@ func NewAutoConfig(scheduler *scheduler.MetaScheduler) *AutoConfig { } // NewAutoConfigNoStart creates an AutoConfig instance. -func NewAutoConfigNoStart(scheduler *scheduler.MetaScheduler) *AutoConfig { - cfgMgr := newReconcilingConfigManager() +func NewAutoConfigNoStart(scheduler *scheduler.MetaScheduler, secretResolver secrets.Component) *AutoConfig { + cfgMgr := newReconcilingConfigManager(secretResolver) ac := &AutoConfig{ configPollers: make([]*configPoller, 0, 9), listenerCandidates: make(map[string]*listenerCandidate), diff --git a/pkg/autodiscovery/autoconfig_test.go b/pkg/autodiscovery/autoconfig_test.go index d1ae6153512cd0..9c6f404eb2a36a 100644 --- a/pkg/autodiscovery/autoconfig_test.go +++ b/pkg/autodiscovery/autoconfig_test.go @@ -167,7 +167,8 @@ func (suite *AutoConfigTestSuite) SetupTest() { } func (suite *AutoConfigTestSuite) TestAddConfigProvider() { - ac := NewAutoConfig(scheduler.NewMetaScheduler()) + mockResolver := MockSecretResolver{suite.T(), nil} + ac := NewAutoConfig(scheduler.NewMetaScheduler(), &mockResolver) assert.Len(suite.T(), ac.configPollers, 0) mp := &MockProvider{} ac.AddConfigProvider(mp, false, 0) @@ -183,7 +184,8 @@ func (suite *AutoConfigTestSuite) TestAddConfigProvider() { } func (suite *AutoConfigTestSuite) TestAddListener() { - ac := NewAutoConfig(scheduler.NewMetaScheduler()) + mockResolver := MockSecretResolver{suite.T(), nil} + ac := NewAutoConfig(scheduler.NewMetaScheduler(), &mockResolver) assert.Len(suite.T(), ac.listeners, 0) ml := &MockListener{} @@ -220,7 +222,8 @@ func (suite *AutoConfigTestSuite) TestDiffConfigs() { } func (suite *AutoConfigTestSuite) TestStop() { - ac := NewAutoConfig(scheduler.NewMetaScheduler()) + mockResolver := MockSecretResolver{suite.T(), nil} + ac := NewAutoConfig(scheduler.NewMetaScheduler(), &mockResolver) ml := &MockListener{} listeners.Register("mock", ml.fakeFactory) @@ -266,13 +269,14 @@ func (suite *AutoConfigTestSuite) TestListenerRetry() { } listeners.Register("retry", retryFactory.make) + mockResolver := MockSecretResolver{suite.T(), nil} configs := []config.Listeners{ {Name: "noerr"}, {Name: "fail"}, {Name: "retry"}, {Name: "invalid"}, } - ac := NewAutoConfig(scheduler.NewMetaScheduler()) + ac := NewAutoConfig(scheduler.NewMetaScheduler(), &mockResolver) assert.Nil(suite.T(), ac.listenerRetryStop) ac.AddListeners(configs) @@ -337,7 +341,8 @@ func TestResolveTemplate(t *testing.T) { sch := &MockScheduler{scheduled: make(map[string]integration.Config)} msch.Register("mock", sch, false) - ac := NewAutoConfig(msch) + mockResolver := MockSecretResolver{t, nil} + ac := NewAutoConfig(msch, &mockResolver) tpl := integration.Config{ Name: "cpu", ADIdentifiers: []string{"redis"}, @@ -370,8 +375,9 @@ func countLoadedConfigs(ac *AutoConfig) int { func TestRemoveTemplate(t *testing.T) { ctx := context.Background() - ac := NewAutoConfig(scheduler.NewMetaScheduler()) + mockResolver := MockSecretResolver{t, nil} + ac := NewAutoConfig(scheduler.NewMetaScheduler(), &mockResolver) // Add static config c := integration.Config{ Name: "memory", @@ -408,7 +414,7 @@ func TestGetLoadedConfigNotInitialized(t *testing.T) { func TestDecryptConfig(t *testing.T) { ctx := context.Background() - mockDecrypt := MockSecretDecrypt{t, []mockSecretScenario{ + mockResolver := MockSecretResolver{t, []mockSecretScenario{ { expectedData: []byte{}, expectedOrigin: "cpu", @@ -422,9 +428,8 @@ func TestDecryptConfig(t *testing.T) { returnedError: nil, }, }} - defer mockDecrypt.install()() - ac := NewAutoConfig(scheduler.NewMetaScheduler()) + ac := NewAutoConfig(scheduler.NewMetaScheduler(), &mockResolver) ac.processNewService(ctx, &dummyService{ID: "abcd", ADIdentifiers: []string{"redis"}}) tpl := integration.Config{ @@ -447,13 +452,13 @@ func TestDecryptConfig(t *testing.T) { } assert.Equal(t, resolved, changes.Schedule[0]) - assert.True(t, mockDecrypt.haveAllScenariosBeenCalled()) + assert.True(t, mockResolver.haveAllScenariosBeenCalled()) } func TestProcessClusterCheckConfigWithSecrets(t *testing.T) { configName := "testConfig" - mockDecrypt := MockSecretDecrypt{t, []mockSecretScenario{ + mockResolver := MockSecretResolver{t, []mockSecretScenario{ { expectedData: []byte("foo: ENC[bar]"), expectedOrigin: configName, @@ -467,9 +472,7 @@ func TestProcessClusterCheckConfigWithSecrets(t *testing.T) { returnedError: nil, }, }} - defer mockDecrypt.install()() - - ac := NewAutoConfig(scheduler.NewMetaScheduler()) + ac := NewAutoConfig(scheduler.NewMetaScheduler(), &mockResolver) tpl := integration.Config{ Provider: names.ClusterChecks, diff --git a/pkg/autodiscovery/configmgr.go b/pkg/autodiscovery/configmgr.go index e3f0a1f20afa70..73db530ae7a7a3 100644 --- a/pkg/autodiscovery/configmgr.go +++ b/pkg/autodiscovery/configmgr.go @@ -10,6 +10,7 @@ import ( "fmt" "sync" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/autodiscovery/configresolver" "github.com/DataDog/datadog-agent/pkg/autodiscovery/integration" "github.com/DataDog/datadog-agent/pkg/autodiscovery/listeners" @@ -96,12 +97,14 @@ type reconcilingConfigManager struct { // configs. The returned integration.ConfigChanges from interface // methods correspond exactly to changes in this map. scheduledConfigs map[string]integration.Config + + secretResolver secrets.Component } var _ configManager = &reconcilingConfigManager{} // newReconcilingConfigManager creates a new, empty reconcilingConfigManager. -func newReconcilingConfigManager() configManager { +func newReconcilingConfigManager(secretResolver secrets.Component) configManager { return &reconcilingConfigManager{ activeConfigs: map[string]integration.Config{}, activeServices: map[string]serviceAndADIDs{}, @@ -109,6 +112,7 @@ func newReconcilingConfigManager() configManager { servicesByADID: newMultimap(), serviceResolutions: map[string]map[string]string{}, scheduledConfigs: map[string]integration.Config{}, + secretResolver: secretResolver, } } @@ -207,7 +211,7 @@ func (cm *reconcilingConfigManager) processNewConfig(config integration.Config) } } else { // Secrets always need to be resolved (done in reconcileService if template) - decryptedConfig, err := decryptConfig(config) + decryptedConfig, err := decryptConfig(config, cm.secretResolver) if err != nil { log.Errorf("Unable to resolve secrets for config '%s', dropping check configuration, err: %s", config.Name, err.Error()) } @@ -266,7 +270,7 @@ func (cm *reconcilingConfigManager) processDelConfigs(configs []integration.Conf } else { // Secrets need to be resolved before being unscheduled as otherwise // the computed hashes can be different from the ones computed at schedule time. - config, err := decryptConfig(config) + config, err := decryptConfig(config, cm.secretResolver) if err != nil { log.Errorf("Unable to resolve secrets for config '%s', check may not be unscheduled properly, err: %s", config.Name, err.Error()) } @@ -367,7 +371,7 @@ func (cm *reconcilingConfigManager) resolveTemplateForService(tpl integration.Co errorStats.setResolveWarning(tpl.Name, msg) return tpl, false } - resolvedConfig, err := decryptConfig(config) + resolvedConfig, err := decryptConfig(config, cm.secretResolver) if err != nil { msg := fmt.Sprintf("error decrypting secrets in config %s for service %s: %v", config.Name, svc.GetServiceID(), err) errorStats.setResolveWarning(tpl.Name, msg) diff --git a/pkg/autodiscovery/configmgr_test.go b/pkg/autodiscovery/configmgr_test.go index 9c737fd9924bc2..100aec2b99e9e1 100644 --- a/pkg/autodiscovery/configmgr_test.go +++ b/pkg/autodiscovery/configmgr_test.go @@ -138,7 +138,7 @@ func (suite *ConfigManagerSuite) TestNewNonTemplateScheduled() { // A new, non-template config with secrets is scheduled immediately and unscheduled when // deleted func (suite *ConfigManagerSuite) TestNewNonTemplateWithSecretsScheduled() { - mockDecrypt := MockSecretDecrypt{suite.T(), []mockSecretScenario{ + mockResolver := MockSecretResolver{suite.T(), []mockSecretScenario{ { expectedData: []byte("foo: ENC[bar]"), expectedOrigin: nonTemplateConfigWithSecrets.Name, @@ -152,7 +152,9 @@ func (suite *ConfigManagerSuite) TestNewNonTemplateWithSecretsScheduled() { returnedError: nil, }, }} - defer mockDecrypt.install()() + // assign mock secretResolver to the configManager + cm := suite.cm.(*reconcilingConfigManager) + cm.secretResolver = &mockResolver inputNewConfig := deepcopy.Copy(nonTemplateConfigWithSecrets).(integration.Config) changes, changedIDs := suite.cm.processNewConfig(inputNewConfig) @@ -162,6 +164,7 @@ func (suite *ConfigManagerSuite) TestNewNonTemplateWithSecretsScheduled() { assertConfigsMatch(suite.T(), changes.Schedule, matchName(nonTemplateConfigWithSecrets.Name)) assertConfigsMatch(suite.T(), changes.Unschedule) // Verify content is actually decoded + require.True(suite.T(), strings.Contains(string(changes.Schedule[0].Instances[0]), "barDecoded")) newConfigDigest := changes.Schedule[0].Digest() @@ -174,7 +177,7 @@ func (suite *ConfigManagerSuite) TestNewNonTemplateWithSecretsScheduled() { } func (suite *ConfigManagerSuite) TestNewClusterCheckWithSecretsScheduled() { - mockDecrypt := MockSecretDecrypt{suite.T(), []mockSecretScenario{ + mockResolver := MockSecretResolver{suite.T(), []mockSecretScenario{ { expectedData: []byte("foo: ENC[bar]"), expectedOrigin: clusterCheckConfigWithSecrets.Name, @@ -188,7 +191,9 @@ func (suite *ConfigManagerSuite) TestNewClusterCheckWithSecretsScheduled() { returnedError: nil, }, }} - defer mockDecrypt.install()() + // assign mock secretResolver to the configManager + cm := suite.cm.(*reconcilingConfigManager) + cm.secretResolver = &mockResolver inputNewConfig := deepcopy.Copy(clusterCheckConfigWithSecrets).(integration.Config) changes, changedIDs := suite.cm.processNewConfig(inputNewConfig) @@ -535,7 +540,10 @@ func (suite *ReconcilingConfigManagerSuite) TestServiceTemplateFiltering() { } func TestReconcilingConfigManagement(t *testing.T) { + mockResolver := MockSecretResolver{} suite.Run(t, &ReconcilingConfigManagerSuite{ - ConfigManagerSuite{factory: newReconcilingConfigManager}, + ConfigManagerSuite{factory: func() configManager { + return newReconcilingConfigManager(&mockResolver) + }}, }) } diff --git a/pkg/autodiscovery/secrets.go b/pkg/autodiscovery/secrets.go index 744ef7d5951348..3f6735f1079224 100644 --- a/pkg/autodiscovery/secrets.go +++ b/pkg/autodiscovery/secrets.go @@ -8,16 +8,13 @@ package autodiscovery import ( "fmt" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/autodiscovery/integration" "github.com/DataDog/datadog-agent/pkg/config" - "github.com/DataDog/datadog-agent/pkg/secrets" "github.com/DataDog/datadog-agent/pkg/util/log" ) -// secretsDecrypt allows tests to intercept calls to secrets.Decrypt. -var secretsDecrypt = secrets.Decrypt - -func decryptConfig(conf integration.Config) (integration.Config, error) { +func decryptConfig(conf integration.Config, secretResolver secrets.Component) (integration.Config, error) { if config.Datadog.GetBool("secret_backend_skip_checks") { log.Tracef("'secret_backend_skip_checks' is enabled, not decrypting configuration %q", conf.Name) return conf, nil @@ -26,7 +23,7 @@ func decryptConfig(conf integration.Config) (integration.Config, error) { var err error // init_config - conf.InitConfig, err = secretsDecrypt(conf.InitConfig, conf.Name) + conf.InitConfig, err = secretResolver.Decrypt(conf.InitConfig, conf.Name) if err != nil { return conf, fmt.Errorf("error while decrypting secrets in 'init_config': %s", err) } @@ -35,7 +32,7 @@ func decryptConfig(conf integration.Config) (integration.Config, error) { // we cannot update in place as, being a slice, it would modify the input config as well instances := make([]integration.Data, 0, len(conf.Instances)) for _, inputInstance := range conf.Instances { - decryptedInstance, err := secretsDecrypt(inputInstance, conf.Name) + decryptedInstance, err := secretResolver.Decrypt(inputInstance, conf.Name) if err != nil { return conf, fmt.Errorf("error while decrypting secrets in an instance: %s", err) } @@ -44,13 +41,13 @@ func decryptConfig(conf integration.Config) (integration.Config, error) { conf.Instances = instances // metrics - conf.MetricConfig, err = secretsDecrypt(conf.MetricConfig, conf.Name) + conf.MetricConfig, err = secretResolver.Decrypt(conf.MetricConfig, conf.Name) if err != nil { return conf, fmt.Errorf("error while decrypting secrets in 'metrics': %s", err) } // logs - conf.LogsConfig, err = secretsDecrypt(conf.LogsConfig, conf.Name) + conf.LogsConfig, err = secretResolver.Decrypt(conf.LogsConfig, conf.Name) if err != nil { return conf, fmt.Errorf("error while decrypting secrets 'logs': %s", err) } diff --git a/pkg/autodiscovery/secrets_test.go b/pkg/autodiscovery/secrets_test.go index f1204733330b1c..0554b94ca76874 100644 --- a/pkg/autodiscovery/secrets_test.go +++ b/pkg/autodiscovery/secrets_test.go @@ -8,11 +8,13 @@ package autodiscovery import ( "bytes" "fmt" + "io" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/autodiscovery/integration" "github.com/DataDog/datadog-agent/pkg/config" ) @@ -25,25 +27,36 @@ type mockSecretScenario struct { called int } -type MockSecretDecrypt struct { +type MockSecretResolver struct { t *testing.T scenarios []mockSecretScenario } -func (m *MockSecretDecrypt) getDecryptFunc() func([]byte, string) ([]byte, error) { - return func(data []byte, origin string) ([]byte, error) { - for n, scenario := range m.scenarios { - if bytes.Equal(data, scenario.expectedData) && origin == scenario.expectedOrigin { - m.scenarios[n].called++ - return scenario.returnedData, scenario.returnedError - } +var _ secrets.Component = (*MockSecretResolver)(nil) + +func (m *MockSecretResolver) Configure(_ string, _ []string, _, _ int, _, _ bool) {} + +func (m *MockSecretResolver) GetDebugInfo(_ io.Writer) {} + +func (m *MockSecretResolver) IsEnabled() bool { + return true +} + +func (m *MockSecretResolver) Decrypt(data []byte, origin string) ([]byte, error) { + if m.scenarios == nil { + return data, nil + } + for n, scenario := range m.scenarios { + if bytes.Equal(data, scenario.expectedData) && origin == scenario.expectedOrigin { + m.scenarios[n].called++ + return scenario.returnedData, scenario.returnedError } - m.t.Errorf("Decrypt called with unexpected arguments: data=%s, origin=%s", data, origin) - return nil, fmt.Errorf("Decrypt called with unexpected arguments: data=%s, origin=%s", data, origin) } + m.t.Errorf("Decrypt called with unexpected arguments: data=%s, origin=%s", string(data), origin) + return nil, fmt.Errorf("Decrypt called with unexpected arguments: data=%s, origin=%s", string(data), origin) } -func (m *MockSecretDecrypt) haveAllScenariosBeenCalled() bool { +func (m *MockSecretResolver) haveAllScenariosBeenCalled() bool { for _, scenario := range m.scenarios { if scenario.called == 0 { fmt.Printf("%#v\n", m.scenarios) @@ -53,7 +66,7 @@ func (m *MockSecretDecrypt) haveAllScenariosBeenCalled() bool { return true } -func (m *MockSecretDecrypt) haveAllScenariosNotCalled() bool { +func (m *MockSecretResolver) haveAllScenariosNotCalled() bool { for _, scenario := range m.scenarios { if scenario.called != 0 { return false @@ -62,13 +75,6 @@ func (m *MockSecretDecrypt) haveAllScenariosNotCalled() bool { return true } -// Install this secret decryptor, and return a function to uninstall it -func (m *MockSecretDecrypt) install() func() { - originalSecretsDecrypt := secretsDecrypt - secretsDecrypt = m.getDecryptFunc() - return func() { secretsDecrypt = originalSecretsDecrypt } -} - var sharedTpl = integration.Config{ Name: "cpu", ADIdentifiers: []string{"redis"}, @@ -110,10 +116,9 @@ var makeSharedScenarios = func() []mockSecretScenario { } func TestSecretDecrypt(t *testing.T) { - mockDecrypt := MockSecretDecrypt{t, makeSharedScenarios()} - defer mockDecrypt.install()() + mockDecrypt := &MockSecretResolver{t, makeSharedScenarios()} - newConfig, err := decryptConfig(sharedTpl) + newConfig, err := decryptConfig(sharedTpl, mockDecrypt) require.NoError(t, err) assert.NotEqual(t, newConfig.Instances, sharedTpl.Instances) @@ -122,14 +127,13 @@ func TestSecretDecrypt(t *testing.T) { } func TestSkipSecretDecrypt(t *testing.T) { - mockDecrypt := MockSecretDecrypt{t, makeSharedScenarios()} - defer mockDecrypt.install()() + mockDecrypt := &MockSecretResolver{t, makeSharedScenarios()} cfg := config.Mock(t) cfg.SetWithoutSource("secret_backend_skip_checks", true) defer cfg.SetWithoutSource("secret_backend_skip_checks", false) - c, err := decryptConfig(sharedTpl) + c, err := decryptConfig(sharedTpl, mockDecrypt) require.NoError(t, err) assert.Equal(t, sharedTpl.Instances, c.Instances) diff --git a/pkg/cli/standalone/jmx.go b/pkg/cli/standalone/jmx.go index 025e73e68f0ace..89e2bb32c6f5c8 100644 --- a/pkg/cli/standalone/jmx.go +++ b/pkg/cli/standalone/jmx.go @@ -58,7 +58,7 @@ func ExecJmxListWithRateMetricsJSON(selectedChecks []string, logLevel string, co // The common utils, including AutoConfig, must have already been initialized. func execJmxCommand(command string, selectedChecks []string, reporter jmxfetch.JMXReporter, output func(...interface{}), logLevel string, configs []integration.Config, wmeta workloadmeta.Component, senderManager sender.DiagnoseSenderManager) error { // start the cmd HTTP server - if err := api.StartServer(nil, nil, nil, nil, nil, wmeta, optional.NewNoneOption[logsAgent.Component](), senderManager, nil, nil, nil); err != nil { + if err := api.StartServer(nil, nil, nil, nil, nil, wmeta, optional.NewNoneOption[logsAgent.Component](), senderManager, nil, nil, nil, nil); err != nil { return fmt.Errorf("Error while starting api server, exiting: %v", err) } diff --git a/pkg/cli/subcommands/check/command.go b/pkg/cli/subcommands/check/command.go index 96868406879a5b..6c04426d2dbc57 100644 --- a/pkg/cli/subcommands/check/command.go +++ b/pkg/cli/subcommands/check/command.go @@ -30,6 +30,7 @@ import ( "github.com/DataDog/datadog-agent/comp/core" "github.com/DataDog/datadog-agent/comp/core/config" "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/comp/core/sysprobeconfig/sysprobeconfigimpl" "github.com/DataDog/datadog-agent/comp/core/workloadmeta" "github.com/DataDog/datadog-agent/comp/forwarder" @@ -121,7 +122,8 @@ func MakeCommand(globalParamsGetter func() GlobalParams) *cobra.Command { return fxutil.OneShot(run, fx.Supply(cliParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewAgentParamsWithSecrets(globalParams.ConfFilePath, config.WithConfigName(globalParams.ConfigName)), + ConfigParams: config.NewAgentParams(globalParams.ConfFilePath, config.WithConfigName(globalParams.ConfigName)), + SecretParams: secrets.NewEnabledParams(), SysprobeConfigParams: sysprobeconfigimpl.NewParams(sysprobeconfigimpl.WithSysProbeConfFilePath(globalParams.SysProbeConfFilePath)), LogParams: log.ForOneShot(globalParams.LoggerName, "off", true)}), core.Bundle, @@ -181,7 +183,7 @@ func MakeCommand(globalParamsGetter func() GlobalParams) *cobra.Command { return cmd } -func run(config config.Component, cliParams *cliParams, demultiplexer demultiplexer.Component, wmeta workloadmeta.Component) error { +func run(config config.Component, cliParams *cliParams, demultiplexer demultiplexer.Component, wmeta workloadmeta.Component, secretResolver secrets.Component) error { previousIntegrationTracing := false previousIntegrationTracingExhaustive := false if cliParams.generateIntegrationTraces { @@ -203,7 +205,7 @@ func run(config config.Component, cliParams *cliParams, demultiplexer demultiple return nil } - common.LoadComponents(context.Background(), demultiplexer, pkgconfig.Datadog.GetString("confd_path")) + common.LoadComponents(context.Background(), demultiplexer, secretResolver, pkgconfig.Datadog.GetString("confd_path")) common.AC.LoadAndRun(context.Background()) // Create the CheckScheduler, but do not attach it to diff --git a/pkg/cli/subcommands/check/command_test.go b/pkg/cli/subcommands/check/command_test.go index 6be7e7e86db24d..9a23ba21071d4b 100644 --- a/pkg/cli/subcommands/check/command_test.go +++ b/pkg/cli/subcommands/check/command_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -27,10 +28,10 @@ func TestCommand(t *testing.T) { // this command has a lot of options, so just test a few []string{"check", "cleopatra", "--delay", "1", "--flare"}, run, - func(cliParams *cliParams, coreParams core.BundleParams) { + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { require.Equal(t, []string{"cleopatra"}, cliParams.args) require.Equal(t, 1, cliParams.checkDelay) require.True(t, cliParams.saveFlare) - require.Equal(t, true, coreParams.ConfigLoadSecrets()) + require.Equal(t, true, secretParams.Enabled) }) } diff --git a/pkg/cli/subcommands/clusterchecks/command.go b/pkg/cli/subcommands/clusterchecks/command.go index e54e205d339e05..21bedb0188c3b1 100644 --- a/pkg/cli/subcommands/clusterchecks/command.go +++ b/pkg/cli/subcommands/clusterchecks/command.go @@ -18,6 +18,7 @@ import ( "github.com/DataDog/datadog-agent/comp/core" "github.com/DataDog/datadog-agent/comp/core/config" "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/api/util" "github.com/DataDog/datadog-agent/pkg/clusteragent/clusterchecks/types" pkgconfig "github.com/DataDog/datadog-agent/pkg/config" @@ -89,7 +90,8 @@ func MakeCommand(globalParamsGetter func() GlobalParams) *cobra.Command { func bundleParams(globalParams GlobalParams) core.BundleParams { return core.BundleParams{ - ConfigParams: config.NewClusterAgentParams(globalParams.ConfFilePath, config.WithConfigLoadSecrets(true)), + ConfigParams: config.NewClusterAgentParams(globalParams.ConfFilePath), + SecretParams: secrets.NewEnabledParams(), LogParams: log.ForOneShot(loggerName, defaultLogLevel, true), } } diff --git a/pkg/cli/subcommands/config/command.go b/pkg/cli/subcommands/config/command.go index 97703a880315a0..d03ae1cdef6665 100644 --- a/pkg/cli/subcommands/config/command.go +++ b/pkg/cli/subcommands/config/command.go @@ -55,7 +55,7 @@ func MakeCommand(globalParamsGetter func() GlobalParams) *cobra.Command { return fxutil.OneShot(callback, fx.Supply(cliParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewAgentParamsWithoutSecrets(globalParams.ConfFilePath, config.WithConfigName(globalParams.ConfigName)), + ConfigParams: config.NewAgentParams(globalParams.ConfFilePath, config.WithConfigName(globalParams.ConfigName)), LogParams: log.ForOneShot(globalParams.LoggerName, "off", true)}), core.Bundle, ) diff --git a/pkg/cli/subcommands/config/command_test.go b/pkg/cli/subcommands/config/command_test.go index 1c8807e5583380..c000ad184486e3 100644 --- a/pkg/cli/subcommands/config/command_test.go +++ b/pkg/cli/subcommands/config/command_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -26,9 +27,9 @@ func TestConfigCommand(t *testing.T) { commands, []string{"config"}, showRuntimeConfiguration, - func(cliParams *cliParams, coreParams core.BundleParams) { + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { require.Equal(t, []string{}, cliParams.args) - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + require.Equal(t, false, secretParams.Enabled) }) } @@ -43,9 +44,9 @@ func TestConfigListRuntimeCommand(t *testing.T) { commands, []string{"config", "list-runtime"}, listRuntimeConfigurableValue, - func(cliParams *cliParams, coreParams core.BundleParams) { + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { require.Equal(t, []string{}, cliParams.args) - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + require.Equal(t, false, secretParams.Enabled) }) } @@ -60,9 +61,9 @@ func TestConfigSetCommand(t *testing.T) { commands, []string{"config", "set", "foo", "bar"}, setConfigValue, - func(cliParams *cliParams, coreParams core.BundleParams) { + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { require.Equal(t, []string{"foo", "bar"}, cliParams.args) - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + require.Equal(t, false, secretParams.Enabled) }) } @@ -77,8 +78,8 @@ func TestConfigGetCommand(t *testing.T) { commands, []string{"config", "get", "foo"}, getConfigValue, - func(cliParams *cliParams, coreParams core.BundleParams) { + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { require.Equal(t, []string{"foo"}, cliParams.args) - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + require.Equal(t, false, secretParams.Enabled) }) } diff --git a/pkg/cli/subcommands/dcaflare/command.go b/pkg/cli/subcommands/dcaflare/command.go index 763b432cf21a41..1bdc1666727d24 100644 --- a/pkg/cli/subcommands/dcaflare/command.go +++ b/pkg/cli/subcommands/dcaflare/command.go @@ -22,6 +22,7 @@ import ( "github.com/DataDog/datadog-agent/comp/core/config" "github.com/DataDog/datadog-agent/comp/core/flare/helpers" "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/api/util" pkgconfig "github.com/DataDog/datadog-agent/pkg/config" "github.com/DataDog/datadog-agent/pkg/config/settings" @@ -83,7 +84,8 @@ func MakeCommand(globalParamsGetter func() GlobalParams) *cobra.Command { return fxutil.OneShot(run, fx.Supply(cliParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewClusterAgentParams(globalParams.ConfFilePath, config.WithConfigLoadSecrets(true)), + ConfigParams: config.NewClusterAgentParams(globalParams.ConfFilePath), + SecretParams: secrets.NewEnabledParams(), LogParams: log.ForOneShot(LoggerName, DefaultLogLevel, true), }), core.Bundle, diff --git a/pkg/cli/subcommands/health/command.go b/pkg/cli/subcommands/health/command.go index 39cdbb088a032f..015554daec89f1 100644 --- a/pkg/cli/subcommands/health/command.go +++ b/pkg/cli/subcommands/health/command.go @@ -56,7 +56,7 @@ func MakeCommand(globalParamsGetter func() GlobalParams) *cobra.Command { return fxutil.OneShot(requestHealth, fx.Supply(cliParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewAgentParamsWithoutSecrets(globalParams.ConfFilePath, config.WithConfigName(globalParams.ConfigName)), + ConfigParams: config.NewAgentParams(globalParams.ConfFilePath, config.WithConfigName(globalParams.ConfigName)), LogParams: log.ForOneShot(globalParams.LoggerName, "off", true)}), core.Bundle, ) diff --git a/pkg/cli/subcommands/health/command_test.go b/pkg/cli/subcommands/health/command_test.go index b55c8d36858f5b..1a72d77e0577bc 100644 --- a/pkg/cli/subcommands/health/command_test.go +++ b/pkg/cli/subcommands/health/command_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -26,7 +27,7 @@ func TestCommand(t *testing.T) { commands, []string{"health"}, requestHealth, - func(coreParams core.BundleParams) { - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + func(coreParams core.BundleParams, secretParams secrets.Params) { + require.Equal(t, false, secretParams.Enabled) }) } diff --git a/pkg/cli/subcommands/taggerlist/command.go b/pkg/cli/subcommands/taggerlist/command.go index 7edc4b694939bc..74b487d199a1d3 100644 --- a/pkg/cli/subcommands/taggerlist/command.go +++ b/pkg/cli/subcommands/taggerlist/command.go @@ -55,7 +55,7 @@ func MakeCommand(globalParamsGetter func() GlobalParams) *cobra.Command { return fxutil.OneShot(taggerList, fx.Supply(cliParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewAgentParamsWithoutSecrets( + ConfigParams: config.NewAgentParams( globalParams.ConfFilePath, config.WithConfigName(globalParams.ConfigName), ), diff --git a/pkg/cli/subcommands/taggerlist/command_test.go b/pkg/cli/subcommands/taggerlist/command_test.go index 510c78f06a4bc7..a1a85a6adc3eed 100644 --- a/pkg/cli/subcommands/taggerlist/command_test.go +++ b/pkg/cli/subcommands/taggerlist/command_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -26,7 +27,7 @@ func TestCommand(t *testing.T) { commands, []string{"tagger-list"}, taggerList, - func(cliParams *cliParams, coreParams core.BundleParams) { - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { + require.Equal(t, false, secretParams.Enabled) }) } diff --git a/pkg/cli/subcommands/workloadlist/command.go b/pkg/cli/subcommands/workloadlist/command.go index b5d8dd47d49040..7eb495a4b647f9 100644 --- a/pkg/cli/subcommands/workloadlist/command.go +++ b/pkg/cli/subcommands/workloadlist/command.go @@ -58,7 +58,7 @@ func MakeCommand(globalParamsGetter func() GlobalParams) *cobra.Command { return fxutil.OneShot(workloadList, fx.Supply(cliParams), fx.Supply(core.BundleParams{ - ConfigParams: config.NewAgentParamsWithoutSecrets( + ConfigParams: config.NewAgentParams( globalParams.ConfFilePath, config.WithConfigName(globalParams.ConfigName), ), diff --git a/pkg/cli/subcommands/workloadlist/command_test.go b/pkg/cli/subcommands/workloadlist/command_test.go index 0e51845c4a9d14..8d348172a14ad2 100644 --- a/pkg/cli/subcommands/workloadlist/command_test.go +++ b/pkg/cli/subcommands/workloadlist/command_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/DataDog/datadog-agent/comp/core" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/util/fxutil" ) @@ -26,8 +27,8 @@ func TestCommand(t *testing.T) { commands, []string{"workload-list", "-v"}, workloadList, - func(cliParams *cliParams, coreParams core.BundleParams) { + func(cliParams *cliParams, coreParams core.BundleParams, secretParams secrets.Params) { require.Equal(t, true, cliParams.verboseList) - require.Equal(t, false, coreParams.ConfigLoadSecrets()) + require.Equal(t, false, secretParams.Enabled) }) } diff --git a/pkg/config/config.go b/pkg/config/config.go index 4bcf113419d981..7906a2b0c5172b 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -23,11 +23,13 @@ import ( "gopkg.in/yaml.v2" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/autodiscovery/common/types" "github.com/DataDog/datadog-agent/pkg/collector/check/defaults" pkgconfigenv "github.com/DataDog/datadog-agent/pkg/config/env" pkgconfigmodel "github.com/DataDog/datadog-agent/pkg/config/model" - "github.com/DataDog/datadog-agent/pkg/secrets" + "github.com/DataDog/datadog-agent/pkg/util/optional" + "github.com/DataDog/datadog-agent/pkg/util/hostname/validate" "github.com/DataDog/datadog-agent/pkg/util/log" ) @@ -368,8 +370,8 @@ func InitConfig(config Config) { // secrets backend config.BindEnvAndSetDefault("secret_backend_command", "") config.BindEnvAndSetDefault("secret_backend_arguments", []string{}) - config.BindEnvAndSetDefault("secret_backend_output_max_size", secrets.SecretBackendOutputMaxSizeDefault) - config.BindEnvAndSetDefault("secret_backend_timeout", secrets.SecretBackendTimeoutDefault) + config.BindEnvAndSetDefault("secret_backend_output_max_size", 0) + config.BindEnvAndSetDefault("secret_backend_timeout", 0) config.BindEnvAndSetDefault("secret_backend_command_allow_group_exec_perm", false) config.BindEnvAndSetDefault("secret_backend_skip_checks", false) config.BindEnvAndSetDefault("secret_backend_remove_trailing_line_break", false) @@ -1383,14 +1385,14 @@ func LoadProxyFromEnv(config Config) { } } -// Load reads configs files and initializes the config module -func Load() (*Warnings, error) { - return LoadDatadogCustom(Datadog, "datadog.yaml", true, SystemProbe.GetEnvVars()) -} - // LoadWithoutSecret reads configs files, initializes the config module without decrypting any secrets func LoadWithoutSecret() (*Warnings, error) { - return LoadDatadogCustom(Datadog, "datadog.yaml", false, SystemProbe.GetEnvVars()) + return LoadDatadogCustom(Datadog, "datadog.yaml", optional.NewNoneOption[secrets.Component](), SystemProbe.GetEnvVars()) +} + +// LoadWithSecret reads config files and initializes config with decrypted secrets +func LoadWithSecret(secretResolver secrets.Component) (*Warnings, error) { + return LoadDatadogCustom(Datadog, "datadog.yaml", optional.NewOption[secrets.Component](secretResolver), SystemProbe.GetEnvVars()) } // Merge will merge additional configuration into an existing configuration @@ -1546,7 +1548,7 @@ func checkConflictingOptions(config Config) error { } // LoadDatadogCustom loads the datadog config in the given config -func LoadDatadogCustom(config Config, origin string, loadSecret bool, additionalKnownEnvVars []string) (*Warnings, error) { +func LoadDatadogCustom(config Config, origin string, secretResolver optional.Option[secrets.Component], additionalKnownEnvVars []string) (*Warnings, error) { // Feature detection running in a defer func as it always need to run (whether config load has been successful or not) // Because some Agents (e.g. trace-agent) will run even if config file does not exist defer func() { @@ -1556,7 +1558,7 @@ func LoadDatadogCustom(config Config, origin string, loadSecret bool, additional pkgconfigmodel.ApplyOverrideFuncs(config) }() - warnings, err := LoadCustom(config, origin, loadSecret, additionalKnownEnvVars) + warnings, err := LoadCustom(config, origin, secretResolver, additionalKnownEnvVars) if err != nil { if errors.Is(err, os.ErrPermission) { log.Warnf("Error loading config: %v (check config file permissions for dd-agent user)", err) @@ -1591,7 +1593,7 @@ func LoadDatadogCustom(config Config, origin string, loadSecret bool, additional } // LoadCustom reads config into the provided config object -func LoadCustom(config Config, origin string, loadSecret bool, additionalKnownEnvVars []string) (*Warnings, error) { +func LoadCustom(config Config, origin string, secretResolver optional.Option[secrets.Component], additionalKnownEnvVars []string) (*Warnings, error) { warnings := Warnings{} if err := config.ReadInConfig(); err != nil { @@ -1620,8 +1622,9 @@ func LoadCustom(config Config, origin string, loadSecret bool, additionalKnownEn // We resolve proxy setting before secrets. This allows setting secrets through DD_PROXY_* env variables LoadProxyFromEnv(config) - if loadSecret { - if err := ResolveSecrets(config, origin); err != nil { + if secretResolver.IsSet() { + resolver, _ := secretResolver.Get() + if err := ResolveSecrets(config, resolver, origin); err != nil { return &warnings, err } } @@ -1761,10 +1764,10 @@ func setupFipsLogsConfig(config Config, configPrefix string, url string) { // ResolveSecrets merges all the secret values from origin into config. Secret values // are identified by a value of the form "ENC[key]" where key is the secret key. // See: https://github.com/DataDog/datadog-agent/blob/main/docs/agent/secrets.md -func ResolveSecrets(config Config, origin string) error { +func ResolveSecrets(config Config, secretResolver secrets.Component, origin string) error { // We have to init the secrets package before we can use it to decrypt // anything. - secrets.Init( + secretResolver.Configure( config.GetString("secret_backend_command"), config.GetStringSlice("secret_backend_arguments"), config.GetInt("secret_backend_timeout"), @@ -1783,7 +1786,7 @@ func ResolveSecrets(config Config, origin string) error { return fmt.Errorf("unable to marshal configuration to YAML to decrypt secrets: %v", err) } - finalYamlConf, err := secrets.Decrypt(yamlConf, origin) + finalYamlConf, err := secretResolver.Decrypt(yamlConf, origin) if err != nil { return fmt.Errorf("unable to decrypt secret from datadog.yaml: %v", err) } diff --git a/pkg/config/config_secret_test.go b/pkg/config/config_secret_test.go index c40ef9754fd72b..e178d662f36fa5 100644 --- a/pkg/config/config_secret_test.go +++ b/pkg/config/config_secret_test.go @@ -3,8 +3,6 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2016-present Datadog, Inc. -//go:build secrets - package config import ( @@ -12,7 +10,9 @@ import ( "path/filepath" "testing" - "github.com/DataDog/datadog-agent/pkg/secrets" + "github.com/DataDog/datadog-agent/comp/core/secrets" + "github.com/DataDog/datadog-agent/comp/core/secrets/secretsimpl" + "github.com/DataDog/datadog-agent/pkg/util/optional" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -20,18 +20,18 @@ import ( func TestProxyWithSecret(t *testing.T) { type testCase struct { name string - setup func(t *testing.T, config Config) + setup func(t *testing.T, config Config, resolver *secretsimpl.MockSecretResolver) tests func(t *testing.T, config Config) } cases := []testCase{ { - name: "secrets fron configuration for proxy", - setup: func(t *testing.T, config Config) { - secrets.InjectSecrets(t, "http_handle", "http_url") - secrets.InjectSecrets(t, "https_handle", "https_url") - secrets.InjectSecrets(t, "no_proxy_1_handle", "no_proxy_1") - secrets.InjectSecrets(t, "no_proxy_2_handle", "no_proxy_2") + name: "secrets from configuration for proxy", + setup: func(t *testing.T, config Config, resolver *secretsimpl.MockSecretResolver) { + resolver.Inject("http_handle", "http_url") + resolver.Inject("https_handle", "https_url") + resolver.Inject("no_proxy_1_handle", "no_proxy_1") + resolver.Inject("no_proxy_2_handle", "no_proxy_2") config.SetWithoutSource("secret_backend_command", "some_command") config.SetWithoutSource("proxy.http", "ENC[http_handle]") @@ -50,11 +50,11 @@ func TestProxyWithSecret(t *testing.T) { }, { name: "secrets fron DD env vars for proxy", - setup: func(t *testing.T, config Config) { - secrets.InjectSecrets(t, "http_handle", "http_url") - secrets.InjectSecrets(t, "https_handle", "https_url") - secrets.InjectSecrets(t, "no_proxy_1_handle", "no_proxy_1") - secrets.InjectSecrets(t, "no_proxy_2_handle", "no_proxy_2") + setup: func(t *testing.T, config Config, resolver *secretsimpl.MockSecretResolver) { + resolver.Inject("http_handle", "http_url") + resolver.Inject("https_handle", "https_url") + resolver.Inject("no_proxy_1_handle", "no_proxy_1") + resolver.Inject("no_proxy_2_handle", "no_proxy_2") config.SetWithoutSource("secret_backend_command", "some_command") t.Setenv("DD_PROXY_HTTP", "ENC[http_handle]") @@ -73,11 +73,11 @@ func TestProxyWithSecret(t *testing.T) { }, { name: "secrets fron UNIX env vars for proxy", - setup: func(t *testing.T, config Config) { - secrets.InjectSecrets(t, "http_handle", "http_url") - secrets.InjectSecrets(t, "https_handle", "https_url") - secrets.InjectSecrets(t, "no_proxy_1_handle", "no_proxy_1") - secrets.InjectSecrets(t, "no_proxy_2_handle", "no_proxy_2") + setup: func(t *testing.T, config Config, resolver *secretsimpl.MockSecretResolver) { + resolver.Inject("http_handle", "http_url") + resolver.Inject("https_handle", "https_url") + resolver.Inject("no_proxy_1_handle", "no_proxy_1") + resolver.Inject("no_proxy_2_handle", "no_proxy_2") config.SetWithoutSource("secret_backend_command", "some_command") t.Setenv("HTTP_PROXY", "ENC[http_handle]") @@ -112,11 +112,12 @@ func TestProxyWithSecret(t *testing.T) { os.WriteFile(configPath, nil, 0600) config.SetConfigFile(configPath) + resolver := secretsimpl.NewMockSecretResolver() if c.setup != nil { - c.setup(t, config) + c.setup(t, config, resolver) } - _, err := LoadCustom(config, "unit_test", true, nil) + _, err := LoadCustom(config, "unit_test", optional.NewOption[secrets.Component](resolver), nil) require.NoError(t, err) c.tests(t, config) diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 00e3a0c928627e..a8621a1a3836df 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -17,8 +17,11 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/DataDog/datadog-agent/comp/core/secrets" + "github.com/DataDog/datadog-agent/comp/core/secrets/secretsimpl" "github.com/DataDog/datadog-agent/pkg/autodiscovery/common/types" "github.com/DataDog/datadog-agent/pkg/config/model" + "github.com/DataDog/datadog-agent/pkg/util/optional" ) func unsetEnvForTest(t *testing.T, env string) { @@ -429,11 +432,12 @@ func TestProxy(t *testing.T) { os.WriteFile(configPath, nil, 0600) config.SetConfigFile(configPath) + resolver := secretsimpl.NewMockSecretResolver() if c.setup != nil { c.setup(t, config) } - _, err := LoadCustom(config, "unit_test", true, nil) + _, err := LoadCustom(config, "unit_test", optional.NewOption[secrets.Component](resolver), nil) require.NoError(t, err) c.tests(t, config) @@ -1058,7 +1062,7 @@ func TestProxyLoadedFromEnvVars(t *testing.T) { t.Setenv("DD_PROXY_HTTPS", proxyHTTPS) Datadog = conf - Load() + LoadWithoutSecret() proxyHTTPConfig := conf.GetString("proxy.http") proxyHTTPSConfig := conf.GetString("proxy.https") @@ -1079,7 +1083,7 @@ func TestProxyLoadedFromConfigFile(t *testing.T) { conf.AddConfigPath(tempDir) Datadog = conf - Load() + LoadWithoutSecret() proxyHTTPConfig := conf.GetString("proxy.http") proxyHTTPSConfig := conf.GetString("proxy.https") @@ -1105,7 +1109,7 @@ func TestProxyLoadedFromConfigFileAndEnvVars(t *testing.T) { conf.AddConfigPath(tempDir) Datadog = conf - Load() + LoadWithoutSecret() proxyHTTPConfig := conf.GetString("proxy.http") proxyHTTPSConfig := conf.GetString("proxy.https") diff --git a/pkg/config/system_probe.go b/pkg/config/system_probe.go index 2daad63e16673f..6f8927f6e59443 100644 --- a/pkg/config/system_probe.go +++ b/pkg/config/system_probe.go @@ -13,7 +13,6 @@ import ( "strings" "time" - "github.com/DataDog/datadog-agent/pkg/secrets" "github.com/DataDog/datadog-agent/pkg/util/log" ) @@ -97,8 +96,8 @@ func InitSystemProbeConfig(cfg Config) { // secrets backend cfg.BindEnvAndSetDefault("secret_backend_command", "") cfg.BindEnvAndSetDefault("secret_backend_arguments", []string{}) - cfg.BindEnvAndSetDefault("secret_backend_output_max_size", secrets.SecretBackendOutputMaxSizeDefault) - cfg.BindEnvAndSetDefault("secret_backend_timeout", secrets.SecretBackendTimeoutDefault) + cfg.BindEnvAndSetDefault("secret_backend_output_max_size", 0) + cfg.BindEnvAndSetDefault("secret_backend_timeout", 0) cfg.BindEnvAndSetDefault("secret_backend_command_allow_group_exec_perm", false) cfg.BindEnvAndSetDefault("secret_backend_skip_checks", false) diff --git a/pkg/config/utils/endpoints_test.go b/pkg/config/utils/endpoints_test.go index 6fc664f44d33c2..0860a94c4465a3 100644 --- a/pkg/config/utils/endpoints_test.go +++ b/pkg/config/utils/endpoints_test.go @@ -8,7 +8,9 @@ package utils import ( "testing" + "github.com/DataDog/datadog-agent/comp/core/secrets" "github.com/DataDog/datadog-agent/pkg/config" + "github.com/DataDog/datadog-agent/pkg/util/optional" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -21,7 +23,7 @@ func TestSecretBackendWithMultipleEndpoints(t *testing.T) { conf := config.SetupConf() conf.SetConfigFile("./tests/datadog_secrets.yaml") // load the configuration - _, err := config.LoadDatadogCustom(conf, "datadog_secrets.yaml", true, nil) + _, err := config.LoadDatadogCustom(conf, "datadog_secrets.yaml", optional.NewNoneOption[secrets.Component](), nil) assert.NoError(t, err) expectedKeysPerDomain := map[string][]string{ diff --git a/pkg/diagnose/check.go b/pkg/diagnose/check.go index 88a57f6386c72e..c63cfad2e4518a 100644 --- a/pkg/diagnose/check.go +++ b/pkg/diagnose/check.go @@ -11,6 +11,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/common" "github.com/DataDog/datadog-agent/comp/aggregator/diagnosesendermanager" + "github.com/DataDog/datadog-agent/comp/core/secrets/secretsimpl" "github.com/DataDog/datadog-agent/pkg/aggregator/sender" "github.com/DataDog/datadog-agent/pkg/collector" "github.com/DataDog/datadog-agent/pkg/collector/check" @@ -97,8 +98,18 @@ func diagnoseChecksInCLIProcess(diagCfg diagnosis.Config, senderManager diagnose } } + // TODO: Hack to retrieve a singleton reference to the secrets Component + // + // Only needed temporarily, since the secrets.Component is needed for the diagnose functionality. + // It is very difficult right now to modify diagnose because it would require modifying many + // function signatures, which would only increase future maintenance. Once diagnose is better + // integrated with Components, we should be able to remove this hack. + // + // Other components should not copy this pattern, it is only meant to be used temporarily. + secretResolver := secretsimpl.GetInstance() + // Initializing the aggregator with a flush interval of 0 (to disable the flush goroutines) - common.LoadComponents(context.Background(), senderManagerInstance, pkgconfig.Datadog.GetString("confd_path")) + common.LoadComponents(context.Background(), senderManagerInstance, secretResolver, pkgconfig.Datadog.GetString("confd_path")) common.AC.LoadAndRun(context.Background()) // Create the CheckScheduler, but do not attach it to diff --git a/pkg/flare/archive.go b/pkg/flare/archive.go index 30213d0d01f430..07eb8639f08f48 100644 --- a/pkg/flare/archive.go +++ b/pkg/flare/archive.go @@ -30,7 +30,6 @@ import ( "github.com/DataDog/datadog-agent/pkg/diagnose" "github.com/DataDog/datadog-agent/pkg/diagnose/diagnosis" "github.com/DataDog/datadog-agent/pkg/metadata/inventories" - "github.com/DataDog/datadog-agent/pkg/secrets" "github.com/DataDog/datadog-agent/pkg/status" "github.com/DataDog/datadog-agent/pkg/status/health" "github.com/DataDog/datadog-agent/pkg/util/installinfo" @@ -89,7 +88,6 @@ func CompleteFlare(fb flaretypes.FlareBuilder, senderManager sender.DiagnoseSend fb.AddFileFromFunc("runtime_config_dump.yaml", func() ([]byte, error) { return yaml.Marshal(config.Datadog.AllSettings()) }) fb.AddFileFromFunc("system_probe_runtime_config_dump.yaml", func() ([]byte, error) { return yaml.Marshal(config.SystemProbe.AllSettings()) }) fb.AddFileFromFunc("diagnose.log", getDiagnoses(fb.IsLocal(), senderManager)) - fb.AddFileFromFunc("secrets.log", getSecrets) fb.AddFileFromFunc("envvars.log", getEnvVars) fb.AddFileFromFunc("metadata_inventories.json", inventories.GetLastPayload) fb.AddFileFromFunc("health.yaml", getHealth) @@ -239,15 +237,6 @@ func getConfigFiles(fb flaretypes.FlareBuilder, confSearchPaths map[string]strin } } -func getSecrets() ([]byte, error) { - fct := func(writer io.Writer) error { - secrets.GetDebugInfo(writer) - return nil - } - - return functionOutputToBytes(fct), nil -} - func getProcessChecks(fb flaretypes.FlareBuilder, getAddressPort func() (url string, err error)) { addressPort, err := getAddressPort() if err != nil { diff --git a/pkg/flare/archive_security_test.go b/pkg/flare/archive_security_test.go index d6a2fcf47daaf2..f5bd1158215643 100644 --- a/pkg/flare/archive_security_test.go +++ b/pkg/flare/archive_security_test.go @@ -20,7 +20,7 @@ import ( ) func TestCreateSecurityAgentArchive(t *testing.T) { - common.SetupConfigWithWarnings("./test", "") + common.SetupConfigForTest("./test") mockConfig := config.Mock(t) mockConfig.SetWithoutSource("compliance_config.dir", "./test/compliance.d") logFilePath := "./test/logs/agent.log" diff --git a/pkg/flare/archive_test.go b/pkg/flare/archive_test.go index 7673bb9115804b..cb1e311857856a 100644 --- a/pkg/flare/archive_test.go +++ b/pkg/flare/archive_test.go @@ -43,7 +43,7 @@ func TestGoRoutines(t *testing.T) { } func TestIncludeSystemProbeConfig(t *testing.T) { - common.SetupConfigWithWarnings("./test/datadog-agent.yaml", "") + common.SetupConfigForTest("./test/datadog-agent.yaml") // create system-probe.yaml file because it's in .gitignore _, err := os.Create("./test/system-probe.yaml") require.NoError(t, err, "couldn't create system-probe.yaml") @@ -57,7 +57,7 @@ func TestIncludeSystemProbeConfig(t *testing.T) { } func TestIncludeConfigFiles(t *testing.T) { - common.SetupConfigWithWarnings("./test", "") + common.SetupConfigForTest("./test") mock := flarehelpers.NewFlareBuilderMock(t, false) getConfigFiles(mock.Fb, searchPaths{"": "./test/confd"}) @@ -68,7 +68,7 @@ func TestIncludeConfigFiles(t *testing.T) { } func TestIncludeConfigFilesWithPrefix(t *testing.T) { - common.SetupConfigWithWarnings("./test", "") + common.SetupConfigForTest("./test") mock := flarehelpers.NewFlareBuilderMock(t, false) getConfigFiles(mock.Fb, searchPaths{"prefix": "./test/confd"}) diff --git a/pkg/logs/internal/util/adlistener/ad_test.go b/pkg/logs/internal/util/adlistener/ad_test.go index 159745afae9ad9..a5243bc752c7d3 100644 --- a/pkg/logs/internal/util/adlistener/ad_test.go +++ b/pkg/logs/internal/util/adlistener/ad_test.go @@ -15,7 +15,7 @@ import ( func TestListenersGetScheduleCalls(t *testing.T) { adsched := scheduler.NewMetaScheduler() - ac := autodiscovery.NewAutoConfigNoStart(adsched) + ac := autodiscovery.NewAutoConfigNoStart(adsched, nil) got1 := make(chan struct{}, 1) l1 := NewADListener("l1", ac, func(configs []integration.Config) { diff --git a/pkg/logs/schedulers/cca/scheduler_test.go b/pkg/logs/schedulers/cca/scheduler_test.go index 94f9feec904778..89dbca36a1b5e5 100644 --- a/pkg/logs/schedulers/cca/scheduler_test.go +++ b/pkg/logs/schedulers/cca/scheduler_test.go @@ -18,7 +18,7 @@ import ( ) func setup() (scheduler *Scheduler, ac *autodiscovery.AutoConfig, spy *schedulers.MockSourceManager) { - ac = autodiscovery.NewAutoConfigNoStart(nil) + ac = autodiscovery.NewAutoConfigNoStart(nil, nil) scheduler = New(ac).(*Scheduler) spy = &schedulers.MockSourceManager{} return diff --git a/pkg/network/nettop/main.go b/pkg/network/nettop/main.go index 501b50a23aa423..2cfad39043e1cd 100644 --- a/pkg/network/nettop/main.go +++ b/pkg/network/nettop/main.go @@ -29,7 +29,7 @@ func main() { } config.Datadog.SetConfigFile(*cfgpath) - if _, err := config.Load(); err != nil { + if _, err := config.LoadWithoutSecret(); err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) os.Exit(1) } diff --git a/pkg/secrets/no_secrets.go b/pkg/secrets/no_secrets.go deleted file mode 100644 index 85534e33943ece..00000000000000 --- a/pkg/secrets/no_secrets.go +++ /dev/null @@ -1,29 +0,0 @@ -// Unless explicitly stated otherwise all files in this repository are licensed -// under the Apache License Version 2.0. -// This product includes software developed at Datadog (https://www.datadoghq.com/). -// Copyright 2016-present Datadog, Inc. - -//go:build !secrets - -// Placeholder for the secrets package when compiled without it - -package secrets - -import ( - "fmt" - "io" -) - -// Init placeholder when compiled without the 'secrets' build tag -func Init(command string, arguments []string, timeout int, maxSize int, groupExecPerm bool, removeTrailingLineBreak bool) { -} - -// Decrypt encrypted secrets are not available on windows -func Decrypt(data []byte, origin string) ([]byte, error) { - return data, nil -} - -// GetDebugInfo exposes debug informations about secrets to be included in a flare -func GetDebugInfo(w io.Writer) { - fmt.Fprintf(w, "Secret feature is not available in this version of the agent") -} diff --git a/pkg/secrets/secrets_mock.go b/pkg/secrets/secrets_mock.go deleted file mode 100644 index e185da1b35d93e..00000000000000 --- a/pkg/secrets/secrets_mock.go +++ /dev/null @@ -1,20 +0,0 @@ -// Unless explicitly stated otherwise all files in this repository are licensed -// under the Apache License Version 2.0. -// This product includes software developed at Datadog (https://www.datadoghq.com/). -// Copyright 2016-present Datadog, Inc. - -//go:build secrets && test - -package secrets - -import ( - "testing" -) - -// InjectSecrets inject a value for an handle into the secrets cache. This allows to use secrets in tests. -func InjectSecrets(t *testing.T, handle string, value string) { - secretCache[handle] = value - t.Cleanup(func() { - delete(secretCache, handle) - }) -} diff --git a/pkg/serverless/metrics/metric_test.go b/pkg/serverless/metrics/metric_test.go index f5e7e98da3feb4..e7bcd6fd172900 100644 --- a/pkg/serverless/metrics/metric_test.go +++ b/pkg/serverless/metrics/metric_test.go @@ -35,7 +35,7 @@ func TestMain(m *testing.M) { } func TestStartDoesNotBlock(t *testing.T) { - config.Load() + config.LoadWithoutSecret() metricAgent := &ServerlessMetricAgent{ SketchesBucketOffset: time.Second * 10, } diff --git a/tasks/build_tags.py b/tasks/build_tags.py index 8ed18e6cff45bc..fd5582e1d9fe93 100644 --- a/tasks/build_tags.py +++ b/tasks/build_tags.py @@ -38,7 +38,6 @@ "podman", "process", "python", - "secrets", "serverless", "systemd", "trivy", @@ -70,7 +69,6 @@ "podman", "process", "python", - "secrets", "systemd", "trivy", "zk", @@ -96,13 +94,13 @@ ) # CLUSTER_AGENT_TAGS lists the tags needed when building the cluster-agent -CLUSTER_AGENT_TAGS = {"clusterchecks", "kubeapiserver", "orchestrator", "secrets", "zlib", "ec2", "gce"} +CLUSTER_AGENT_TAGS = {"clusterchecks", "kubeapiserver", "orchestrator", "zlib", "ec2", "gce"} # CLUSTER_AGENT_CLOUDFOUNDRY_TAGS lists the tags needed when building the cloudfoundry cluster-agent -CLUSTER_AGENT_CLOUDFOUNDRY_TAGS = {"clusterchecks", "secrets"} +CLUSTER_AGENT_CLOUDFOUNDRY_TAGS = {"clusterchecks"} # DOGSTATSD_TAGS lists the tags needed when building dogstatsd -DOGSTATSD_TAGS = {"containerd", "docker", "kubelet", "podman", "secrets", "zlib"} +DOGSTATSD_TAGS = {"containerd", "docker", "kubelet", "podman", "zlib"} # IOT_AGENT_TAGS lists the tags needed when building the IoT agent IOT_AGENT_TAGS = {"jetson", "otlp", "systemd", "zlib"} @@ -118,7 +116,7 @@ ) # SECURITY_AGENT_TAGS lists the tags necessary to build the security agent -SECURITY_AGENT_TAGS = {"netcgo", "secrets", "docker", "containerd", "kubeapiserver", "kubelet", "podman", "zlib", "ec2"} +SECURITY_AGENT_TAGS = {"netcgo", "docker", "containerd", "kubeapiserver", "kubelet", "podman", "zlib", "ec2"} # SERVERLESS_TAGS lists the tags necessary to build serverless SERVERLESS_TAGS = {"serverless", "otlp"} @@ -127,7 +125,7 @@ SYSTEM_PROBE_TAGS = AGENT_TAGS.union({"clusterchecks", "linux_bpf", "npm"}).difference({"python", "systemd"}) # TRACE_AGENT_TAGS lists the tags that have to be added when the trace-agent -TRACE_AGENT_TAGS = {"docker", "containerd", "kubeapiserver", "kubelet", "otlp", "netcgo", "podman", "secrets"} +TRACE_AGENT_TAGS = {"docker", "containerd", "kubeapiserver", "kubelet", "otlp", "netcgo", "podman"} # TRACE_AGENT_HEROKU_TAGS lists the tags necessary to build the trace-agent for Heroku TRACE_AGENT_HEROKU_TAGS = TRACE_AGENT_TAGS.difference(