diff --git a/cmd/telegraf/telegraf.go b/cmd/telegraf/telegraf.go index 03fe78889f9ab..6deec42261866 100644 --- a/cmd/telegraf/telegraf.go +++ b/cmd/telegraf/telegraf.go @@ -315,6 +315,18 @@ func (t *Telegraf) runAgent(ctx context.Context, c *config.Config, reloadConfig log.Printf("W! Deprecated secretstores: %d and %d options", count[0], count[1]) } + // Compute the amount of locked memory needed for the secrets + required := 2 * c.NumberSecrets * uint64(os.Getpagesize()) + available := getLockedMemoryLimit() + if required > available { + required /= 1024 + available /= 1024 + log.Printf("I! Found %d secrets...", c.NumberSecrets) + msg := fmt.Sprintf("Insufficient lockable memory %dkb when %dkb is required.", available, required) + msg += " Please increase the limit for Telegraf in your Operating System!" + log.Printf("W! " + color.RedString(msg)) + } + ag := agent.NewAgent(c) // Notify systemd that telegraf is ready diff --git a/cmd/telegraf/telegraf_posix.go b/cmd/telegraf/telegraf_posix.go index fe11821198b88..77a4d7c6ced09 100644 --- a/cmd/telegraf/telegraf_posix.go +++ b/cmd/telegraf/telegraf_posix.go @@ -2,7 +2,12 @@ package main -import "github.com/urfave/cli/v2" +import ( + "log" + "syscall" + + "github.com/urfave/cli/v2" +) func (t *Telegraf) Run() error { stop = make(chan struct{}) @@ -12,3 +17,16 @@ func (t *Telegraf) Run() error { func cliFlags() []cli.Flag { return []cli.Flag{} } + +func getLockedMemoryLimit() uint64 { + // From https://elixir.bootlin.com/linux/latest/source/include/uapi/asm-generic/resource.h#L35 + const rLimitMemlock = 8 + + var limit syscall.Rlimit + if err := syscall.Getrlimit(rLimitMemlock, &limit); err != nil { + log.Printf("E! Cannot get limit for locked memory: %v", err) + return 0 + } + //nolint:unconvert // required for e.g. FreeBSD that has the field as int64 + return uint64(limit.Max) +} diff --git a/cmd/telegraf/telegraf_windows.go b/cmd/telegraf/telegraf_windows.go index 997ab98710c9f..f8969056546cc 100644 --- a/cmd/telegraf/telegraf_windows.go +++ b/cmd/telegraf/telegraf_windows.go @@ -10,6 +10,7 @@ import ( "github.com/kardianos/service" "github.com/urfave/cli/v2" + "golang.org/x/sys/windows" "github.com/influxdata/telegraf/logger" ) @@ -45,6 +46,16 @@ func cliFlags() []cli.Flag { } } +func getLockedMemoryLimit() uint64 { + handle := windows.CurrentProcess() + + var min, max uintptr + var flag uint32 + windows.GetProcessWorkingSetSizeEx(handle, &min, &max, &flag) + + return uint64(max) +} + func (t *Telegraf) Run() error { // Register the eventlog logging target for windows. err := logger.RegisterEventLogger(t.serviceName) diff --git a/config/config.go b/config/config.go index e67695d940856..aec4d80086919 100644 --- a/config/config.go +++ b/config/config.go @@ -89,6 +89,8 @@ type Config struct { version *semver.Version Persister *persister.Persister + + NumberSecrets uint64 } // Ordered plugins used to keep the order in which they appear in a file @@ -471,6 +473,9 @@ func (c *Config) LoadAll(configFiles ...string) error { c.Agent.SnmpTranslator = "netsnmp" } + // Check if there is enough lockable memory for the secret + c.NumberSecrets = uint64(secretCount.Load()) + // Let's link all secrets to their secret-stores return c.LinkSecrets() } diff --git a/config/secret.go b/config/secret.go index 98e2f34b93a58..48b669a4d6843 100644 --- a/config/secret.go +++ b/config/secret.go @@ -4,6 +4,7 @@ import ( "fmt" "regexp" "strings" + "sync/atomic" "github.com/awnumar/memguard" @@ -25,6 +26,8 @@ var secretStorePattern = regexp.MustCompile(`^\w+$`) // in a secret-store. var secretPattern = regexp.MustCompile(`@\{(\w+:\w+)\}`) +var secretCount atomic.Int64 + // Secret safely stores sensitive data such as a password or token type Secret struct { enclave *memguard.Enclave @@ -60,6 +63,9 @@ func (s *Secret) UnmarshalText(b []byte) error { // Initialize the secret content func (s *Secret) init(secret []byte) { + // Keep track of the number of secrets... + secretCount.Add(1) + // Remember if the secret is completely empty s.notempty = len(secret) != 0 @@ -87,6 +93,9 @@ func (s *Secret) Destroy() { lockbuf.Destroy() } s.enclave = nil + + // Keep track of the number of secrets... + secretCount.Add(-1) } // Empty return if the secret is completely empty