diff --git a/cmd/agent/subcommands/flare/command.go b/cmd/agent/subcommands/flare/command.go index 853e1f8e73014..fb6f295c7b7b0 100644 --- a/cmd/agent/subcommands/flare/command.go +++ b/cmd/agent/subcommands/flare/command.go @@ -22,6 +22,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/common" commonpath "github.com/DataDog/datadog-agent/cmd/agent/common/path" "github.com/DataDog/datadog-agent/comp/aggregator/diagnosesendermanager/diagnosesendermanagerimpl" + authtokenimpl "github.com/DataDog/datadog-agent/comp/api/authtoken/fetchonlyimpl" "github.com/DataDog/datadog-agent/comp/collector/collector" "github.com/DataDog/datadog-agent/comp/core" "github.com/DataDog/datadog-agent/comp/core/config" @@ -120,6 +121,7 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { hostimpl.Module(), inventoryhostimpl.Module(), resourcesimpl.Module(), + authtokenimpl.Module(), // inventoryagent require a serializer. Since we're not actually sending the payload to // the backend a nil will work. fx.Provide(func() serializer.MetricSerializer { diff --git a/cmd/agent/subcommands/jmx/command.go b/cmd/agent/subcommands/jmx/command.go index 681e32ed8cc42..76d879fa239b1 100644 --- a/cmd/agent/subcommands/jmx/command.go +++ b/cmd/agent/subcommands/jmx/command.go @@ -26,6 +26,7 @@ import ( "github.com/DataDog/datadog-agent/comp/aggregator/diagnosesendermanager" "github.com/DataDog/datadog-agent/comp/aggregator/diagnosesendermanager/diagnosesendermanagerimpl" internalAPI "github.com/DataDog/datadog-agent/comp/api/api" + authtokenimpl "github.com/DataDog/datadog-agent/comp/api/authtoken/createandfetchimpl" "github.com/DataDog/datadog-agent/comp/collector/collector" "github.com/DataDog/datadog-agent/comp/api/api/apiimpl" @@ -130,6 +131,7 @@ func Commands(globalParams *command.GlobalParams) []*cobra.Command { }), workloadmeta.Module(), apiimpl.Module(), + authtokenimpl.Module(), // TODO(components): this is a temporary hack as the StartServer() method of the API package was previously called with nil arguments // This highlights the fact that the API Server created by JMX (through ExecJmx... function) should be different from the ones created // in others commands such as run. diff --git a/cmd/agent/subcommands/run/command.go b/cmd/agent/subcommands/run/command.go index a3da54ceff97c..b0da4d42ca8a1 100644 --- a/cmd/agent/subcommands/run/command.go +++ b/cmd/agent/subcommands/run/command.go @@ -39,6 +39,7 @@ import ( "github.com/DataDog/datadog-agent/comp/aggregator/demultiplexer/demultiplexerimpl" internalAPI "github.com/DataDog/datadog-agent/comp/api/api" "github.com/DataDog/datadog-agent/comp/api/api/apiimpl" + authtokenimpl "github.com/DataDog/datadog-agent/comp/api/authtoken/createandfetchimpl" "github.com/DataDog/datadog-agent/comp/collector/collector" "github.com/DataDog/datadog-agent/comp/collector/collector/collectorimpl" "github.com/DataDog/datadog-agent/comp/core" @@ -329,6 +330,7 @@ func getSharedFxOption() fx.Option { processagentStatusImpl.Module(), dogstatsdStatusimpl.Module(), statusimpl.Module(), + authtokenimpl.Module(), apiimpl.Module(), dogstatsd.Bundle(), diff --git a/cmd/dogstatsd/subcommands/start/command.go b/cmd/dogstatsd/subcommands/start/command.go index a13f1594317bd..e6aa500dbbf6d 100644 --- a/cmd/dogstatsd/subcommands/start/command.go +++ b/cmd/dogstatsd/subcommands/start/command.go @@ -20,6 +20,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/common" "github.com/DataDog/datadog-agent/comp/aggregator/demultiplexer" "github.com/DataDog/datadog-agent/comp/aggregator/demultiplexer/demultiplexerimpl" + authtokenimpl "github.com/DataDog/datadog-agent/comp/api/authtoken/fetchonlyimpl" "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" @@ -162,6 +163,7 @@ func RunDogstatsdFct(cliParams *CLIParams, defaultConfPath string, defaultLogFil resourcesimpl.Module(), hostimpl.Module(), inventoryagentimpl.Module(), + authtokenimpl.Module(), // sysprobeconfig is optionally required by inventoryagent sysprobeconfig.NoneModule(), inventoryhostimpl.Module(), diff --git a/cmd/systray/command/command.go b/cmd/systray/command/command.go index 12c68df507ddc..fbb6e4bd324df 100644 --- a/cmd/systray/command/command.go +++ b/cmd/systray/command/command.go @@ -20,6 +20,7 @@ import ( "github.com/DataDog/datadog-agent/cmd/agent/common/path" "github.com/DataDog/datadog-agent/comp/aggregator/diagnosesendermanager/diagnosesendermanagerimpl" + authtokenimpl "github.com/DataDog/datadog-agent/comp/api/authtoken/fetchonlyimpl" "github.com/DataDog/datadog-agent/comp/collector/collector" "github.com/DataDog/datadog-agent/comp/core" "github.com/DataDog/datadog-agent/comp/core/config" @@ -104,6 +105,7 @@ func MakeCommand() *cobra.Command { flare.Module(), fx.Supply(optional.NewNoneOption[collector.Component]()), diagnosesendermanagerimpl.Module(), + authtokenimpl.Module(), // We need inventoryagent to fill the status page generated by the flare. inventoryagentimpl.Module(), // inventoryagent require a serializer. Since we're not actually sending the payload to diff --git a/comp/README.md b/comp/README.md index 1e2fde02ae4bc..0dca6de56bf2a 100644 --- a/comp/README.md +++ b/comp/README.md @@ -28,6 +28,12 @@ Package api implements the "api" bundle, Package api implements the internal Agent API which exposes endpoints such as config, flare or status +### [comp/api/authtoken](https://pkg.go.dev/github.com/DataDog/datadog-agent/comp/api/authtoken) + +Package authtoken implements the creation and access to the auth_token used to communicate between Agent processes. +This component offers two implementations: one to create and fetch the auth_token and another that doesn't create the +auth_token file but can fetch it it's available. + ## [comp/apm/etwtracer](https://pkg.go.dev/github.com/DataDog/datadog-agent/comp/apm/etwtracer) (Component Bundle) *Datadog Team*: windows-agent diff --git a/comp/api/api/apiimpl/api.go b/comp/api/api/apiimpl/api.go index 25ac6755d91b8..24f523316bd06 100644 --- a/comp/api/api/apiimpl/api.go +++ b/comp/api/api/apiimpl/api.go @@ -13,6 +13,7 @@ import ( "github.com/DataDog/datadog-agent/comp/aggregator/demultiplexer" "github.com/DataDog/datadog-agent/comp/api/api" + "github.com/DataDog/datadog-agent/comp/api/authtoken" "github.com/DataDog/datadog-agent/comp/collector/collector" "github.com/DataDog/datadog-agent/comp/core/flare" "github.com/DataDog/datadog-agent/comp/core/secrets" @@ -58,6 +59,7 @@ type apiServer struct { eventPlatformReceiver eventplatformreceiver.Component rcService optional.Option[rcservice.Component] rcServiceHA optional.Option[rcserviceha.Component] + authToken authtoken.Component } type dependencies struct { @@ -78,6 +80,7 @@ type dependencies struct { EventPlatformReceiver eventplatformreceiver.Component RcService optional.Option[rcservice.Component] RcServiceHA optional.Option[rcserviceha.Component] + AuthToken authtoken.Component } var _ api.Component = (*apiServer)(nil) @@ -99,6 +102,7 @@ func newAPIServer(deps dependencies) api.Component { eventPlatformReceiver: deps.EventPlatformReceiver, rcService: deps.RcService, rcServiceHA: deps.RcServiceHA, + authToken: deps.AuthToken, } } diff --git a/comp/api/api/apiimpl/server.go b/comp/api/api/apiimpl/server.go index 8792bf67a6dda..fd4f67c4ede28 100644 --- a/comp/api/api/apiimpl/server.go +++ b/comp/api/api/apiimpl/server.go @@ -12,8 +12,6 @@ import ( "net" "net/http" - "github.com/DataDog/datadog-agent/comp/forwarder/eventplatformreceiver" - "github.com/cihub/seelog" "github.com/DataDog/datadog-agent/comp/aggregator/demultiplexer" @@ -26,6 +24,7 @@ import ( "github.com/DataDog/datadog-agent/comp/dogstatsd/replay" dogstatsdServer "github.com/DataDog/datadog-agent/comp/dogstatsd/server" dogstatsddebug "github.com/DataDog/datadog-agent/comp/dogstatsd/serverDebug" + "github.com/DataDog/datadog-agent/comp/forwarder/eventplatformreceiver" logsAgent "github.com/DataDog/datadog-agent/comp/logs/agent" "github.com/DataDog/datadog-agent/comp/metadata/host" "github.com/DataDog/datadog-agent/comp/metadata/inventoryagent" @@ -35,7 +34,6 @@ import ( "github.com/DataDog/datadog-agent/comp/remote-config/rcservice" "github.com/DataDog/datadog-agent/comp/remote-config/rcserviceha" "github.com/DataDog/datadog-agent/pkg/aggregator/sender" - "github.com/DataDog/datadog-agent/pkg/api/util" "github.com/DataDog/datadog-agent/pkg/config" "github.com/DataDog/datadog-agent/pkg/util/log" "github.com/DataDog/datadog-agent/pkg/util/optional" @@ -110,10 +108,6 @@ func StartServers( MinVersion: tls.VersionTLS12, } - if err := util.CreateAndSetAuthToken(config.Datadog); err != nil { - return err - } - // start the CMD server if err := startCMDServer( apiAddr, diff --git a/comp/api/authtoken/component.go b/comp/api/authtoken/component.go new file mode 100644 index 0000000000000..2aae4096f392d --- /dev/null +++ b/comp/api/authtoken/component.go @@ -0,0 +1,32 @@ +// 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 2023-present Datadog, Inc. + +// Package authtoken implements the creation and access to the auth_token used to communicate between Agent processes. +// This component offers two implementations: one to create and fetch the auth_token and another that doesn't create the +// auth_token file but can fetch it it's available. +package authtoken + +import ( + "github.com/DataDog/datadog-agent/pkg/util/fxutil" + "github.com/DataDog/datadog-agent/pkg/util/optional" + "go.uber.org/fx" +) + +// team: agent-shared-components + +// Component is the component type. +type Component interface { + Get() string +} + +// NoneModule return a None optional type for authtoken.Component. +// +// This helper allows code that needs a disabled Optional type for authtoken to get it. The helper is split from +// the implementation to avoid linking with the dependencies from sysprobeconfig. +func NoneModule() fxutil.Module { + return fxutil.Component(fx.Provide(func() optional.Option[Component] { + return optional.NewNoneOption[Component]() + })) +} diff --git a/comp/api/authtoken/createandfetchimpl/authtoken.go b/comp/api/authtoken/createandfetchimpl/authtoken.go new file mode 100644 index 0000000000000..609028883687f --- /dev/null +++ b/comp/api/authtoken/createandfetchimpl/authtoken.go @@ -0,0 +1,54 @@ +// 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 2023-present Datadog, Inc. + +// Package createandfetchimpl implements the creation and access to the auth_token used to communicate between Agent +// processes. +package createandfetchimpl + +import ( + "go.uber.org/fx" + + "github.com/DataDog/datadog-agent/comp/api/authtoken" + "github.com/DataDog/datadog-agent/comp/core/config" + "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/pkg/api/util" + "github.com/DataDog/datadog-agent/pkg/util/fxutil" + "github.com/DataDog/datadog-agent/pkg/util/optional" +) + +// Module defines the fx options for this component. +func Module() fxutil.Module { + return fxutil.Component( + fx.Provide(newAuthToken), + fx.Provide(func(authToken authtoken.Component) optional.Option[authtoken.Component] { + return optional.NewOption[authtoken.Component](authToken) + }), + ) +} + +type authToken struct{} + +var _ authtoken.Component = (*authToken)(nil) + +type dependencies struct { + fx.In + + Conf config.Component + Log log.Component +} + +func newAuthToken(deps dependencies) (authtoken.Component, error) { + if err := util.CreateAndSetAuthToken(deps.Conf); err != nil { + deps.Log.Error("could not create auth_token: %s", err) + return nil, err + } + + return &authToken{}, nil +} + +// Get returns the session token +func (at *authToken) Get() string { + return util.GetAuthToken() +} diff --git a/comp/api/authtoken/createandfetchimpl/authtoken_test.go b/comp/api/authtoken/createandfetchimpl/authtoken_test.go new file mode 100644 index 0000000000000..f76e394ae8374 --- /dev/null +++ b/comp/api/authtoken/createandfetchimpl/authtoken_test.go @@ -0,0 +1,45 @@ +// 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 2023-present Datadog, Inc. + +package createandfetchimpl + +import ( + "os" + "path/filepath" + "testing" + + "github.com/DataDog/datadog-agent/pkg/api/util" + "github.com/DataDog/datadog-agent/pkg/util/fxutil" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/fx" + + "github.com/DataDog/datadog-agent/comp/core/config" + "github.com/DataDog/datadog-agent/comp/core/log/logimpl" +) + +func TestGet(t *testing.T) { + dir := t.TempDir() + authPath := filepath.Join(dir, "auth_token") + overrides := map[string]any{ + "auth_token_file_path": authPath, + } + + comp, err := newAuthToken( + fxutil.Test[dependencies]( + t, + logimpl.MockModule(), + config.MockModule(), + fx.Replace(config.MockParams{Overrides: overrides}), + ), + ) + require.NoError(t, err) + + data, err := os.ReadFile(authPath) + require.NoError(t, err) + + assert.Equal(t, string(data), comp.Get()) + assert.Equal(t, util.GetAuthToken(), comp.Get()) +} diff --git a/comp/api/authtoken/fetchonlyimpl/authtoken.go b/comp/api/authtoken/fetchonlyimpl/authtoken.go new file mode 100644 index 0000000000000..7301b0054be06 --- /dev/null +++ b/comp/api/authtoken/fetchonlyimpl/authtoken.go @@ -0,0 +1,67 @@ +// 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 2023-present Datadog, Inc. + +// Package fetchonlyimpl implements the access to the auth_token used to communicate between Agent +// processes but does not create it. +package fetchonlyimpl + +import ( + "go.uber.org/fx" + + "github.com/DataDog/datadog-agent/comp/api/authtoken" + "github.com/DataDog/datadog-agent/comp/core/config" + "github.com/DataDog/datadog-agent/comp/core/log" + "github.com/DataDog/datadog-agent/pkg/api/util" + "github.com/DataDog/datadog-agent/pkg/util/fxutil" + "github.com/DataDog/datadog-agent/pkg/util/optional" +) + +// Module defines the fx options for this component. +func Module() fxutil.Module { + return fxutil.Component( + fx.Provide(newAuthToken), + fx.Provide(func(authToken authtoken.Component) optional.Option[authtoken.Component] { + return optional.NewOption[authtoken.Component](authToken) + }), + ) +} + +type authToken struct { + log log.Component + conf config.Component + + tokenLoaded bool +} + +var _ authtoken.Component = (*authToken)(nil) + +type dependencies struct { + fx.In + + Log log.Component + Conf config.Component +} + +func newAuthToken(deps dependencies) authtoken.Component { + return &authToken{ + log: deps.Log, + conf: deps.Conf, + } +} + +// Get returns the session token +func (at *authToken) Get() string { + if !at.tokenLoaded { + // We try to load the auth_token until we succeed since it might be created at some point by another + // process. + if err := util.SetAuthToken(at.conf); err != nil { + at.log.Debugf("could not load auth_token: %s", err) + return "" + } + at.tokenLoaded = true + } + + return util.GetAuthToken() +} diff --git a/comp/metadata/bundle_test.go b/comp/metadata/bundle_test.go index a8aeb5263fc75..61861f356b775 100644 --- a/comp/metadata/bundle_test.go +++ b/comp/metadata/bundle_test.go @@ -10,6 +10,7 @@ import ( "go.uber.org/fx" + authtokenimpl "github.com/DataDog/datadog-agent/comp/api/authtoken/fetchonlyimpl" "github.com/DataDog/datadog-agent/comp/collector/collector/collectorimpl" "github.com/DataDog/datadog-agent/comp/core" "github.com/DataDog/datadog-agent/comp/logs/agent" @@ -27,6 +28,7 @@ func TestBundleDependencies(t *testing.T) { fx.Provide(func() optional.Option[agent.Component] { return optional.NewNoneOption[agent.Component]() }), + authtokenimpl.Module(), ) } diff --git a/comp/metadata/inventoryagent/inventoryagentimpl/inventoryagent.go b/comp/metadata/inventoryagent/inventoryagentimpl/inventoryagent.go index b9e40f98b15c5..9d5426110afaf 100644 --- a/comp/metadata/inventoryagent/inventoryagentimpl/inventoryagent.go +++ b/comp/metadata/inventoryagent/inventoryagentimpl/inventoryagent.go @@ -17,6 +17,7 @@ import ( "go.uber.org/fx" + "github.com/DataDog/datadog-agent/comp/api/authtoken" "github.com/DataDog/datadog-agent/comp/core/config" flaretypes "github.com/DataDog/datadog-agent/comp/core/flare/types" "github.com/DataDog/datadog-agent/comp/core/log" @@ -89,6 +90,7 @@ type inventoryagent struct { m sync.Mutex data agentMetadata hostname string + authToken authtoken.Component } type dependencies struct { @@ -98,6 +100,7 @@ type dependencies struct { Config config.Component SysProbeConfig optional.Option[sysprobeconfig.Component] Serializer serializer.MetricSerializer + AuthToken authtoken.Component } type provides struct { @@ -117,6 +120,7 @@ func newInventoryAgentProvider(deps dependencies) provides { log: deps.Log, hostname: hname, data: make(agentMetadata), + authToken: deps.AuthToken, } ia.InventoryPayload = util.CreateInventoryPayload(deps.Config, deps.Log, deps.Serializer, ia.getPayload, "agent.json") @@ -189,7 +193,7 @@ func (ia *inventoryagent) getCorrectConfig(name string, conf model.Reader, confi return cfg } } else { - ia.log.Errorf("could not fetch %s process configuration: %s", name, err) + ia.log.Infof("could not fetch %s process configuration: %s", name, err) } return fallback } diff --git a/comp/metadata/inventoryagent/inventoryagentimpl/inventoryagent_test.go b/comp/metadata/inventoryagent/inventoryagentimpl/inventoryagent_test.go index 139f2f2a10f08..4ae299e2bce39 100644 --- a/comp/metadata/inventoryagent/inventoryagentimpl/inventoryagent_test.go +++ b/comp/metadata/inventoryagent/inventoryagentimpl/inventoryagent_test.go @@ -16,6 +16,7 @@ import ( "github.com/stretchr/testify/assert" + authtokenimpl "github.com/DataDog/datadog-agent/comp/api/authtoken/fetchonlyimpl" "github.com/DataDog/datadog-agent/comp/core/config" "github.com/DataDog/datadog-agent/comp/core/log/logimpl" "github.com/DataDog/datadog-agent/comp/core/sysprobeconfig" @@ -31,8 +32,8 @@ import ( "github.com/DataDog/datadog-agent/pkg/version" ) -func getTestInventoryPayload(t *testing.T, confOverrides map[string]any, sysprobeConfOverrides map[string]any) *inventoryagent { - p := newInventoryAgentProvider( +func getProvides(t *testing.T, confOverrides map[string]any, sysprobeConfOverrides map[string]any) provides { + return newInventoryAgentProvider( fxutil.Test[dependencies]( t, logimpl.MockModule(), @@ -41,8 +42,13 @@ func getTestInventoryPayload(t *testing.T, confOverrides map[string]any, sysprob sysprobeconfigimpl.MockModule(), fx.Replace(sysprobeconfigimpl.MockParams{Overrides: sysprobeConfOverrides}), fx.Provide(func() serializer.MetricSerializer { return &serializer.MockSerializer{} }), + authtokenimpl.Module(), ), ) +} + +func getTestInventoryPayload(t *testing.T, confOverrides map[string]any, sysprobeConfOverrides map[string]any) *inventoryagent { + p := getProvides(t, confOverrides, sysprobeConfOverrides) return p.Comp.(*inventoryagent) } @@ -259,17 +265,7 @@ func TestConfigRefresh(t *testing.T) { } func TestStatusHeaderProvider(t *testing.T) { - ret := newInventoryAgentProvider( - fxutil.Test[dependencies]( - t, - logimpl.MockModule(), - config.MockModule(), - fx.Replace(config.MockParams{Overrides: nil}), - sysprobeconfigimpl.MockModule(), - fx.Replace(sysprobeconfigimpl.MockParams{Overrides: nil}), - fx.Provide(func() serializer.MetricSerializer { return &serializer.MockSerializer{} }), - ), - ) + ret := getProvides(t, nil, nil) headerStatusProvider := ret.StatusHeaderProvider.Provider @@ -512,6 +508,7 @@ func TestFetchSystemProbeAgent(t *testing.T) { config.MockModule(), sysprobeconfig.NoneModule(), fx.Provide(func() serializer.MetricSerializer { return &serializer.MockSerializer{} }), + authtokenimpl.Module(), ), ) ia = p.Comp.(*inventoryagent) diff --git a/comp/metadata/inventoryagent/inventoryagentimpl/mock.go b/comp/metadata/inventoryagent/inventoryagentimpl/mock.go index f8eb4fe36473d..3206e58d8ebac 100644 --- a/comp/metadata/inventoryagent/inventoryagentimpl/mock.go +++ b/comp/metadata/inventoryagent/inventoryagentimpl/mock.go @@ -18,7 +18,7 @@ import ( // // fxutil.Test[dependencies]( // t, -// inventoryagent.MockModule(), +// inventoryagentimpl.MockModule(), // ) func MockModule() fxutil.Module { return fxutil.Component( diff --git a/pkg/cli/subcommands/check/command.go b/pkg/cli/subcommands/check/command.go index 052075b731a6a..d26d4007f3f82 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/aggregator/demultiplexer/demultiplexerimpl" internalAPI "github.com/DataDog/datadog-agent/comp/api/api" "github.com/DataDog/datadog-agent/comp/api/api/apiimpl" + authtokenimpl "github.com/DataDog/datadog-agent/comp/api/authtoken/createandfetchimpl" "github.com/DataDog/datadog-agent/comp/collector/collector" "github.com/DataDog/datadog-agent/comp/collector/collector/collectorimpl" "github.com/DataDog/datadog-agent/comp/core" @@ -160,6 +161,7 @@ func MakeCommand(globalParamsGetter func() GlobalParams) *cobra.Command { fx.Provide(defaults.DefaultParams), workloadmeta.Module(), apiimpl.Module(), + authtokenimpl.Module(), fx.Supply(context.Background()), fx.Provide(tagger.NewTaggerParamsForCoreAgent), tagger.Module(),