feat(secretstores): Add systemd-credentials plugin (#13657)
This commit is contained in:
parent
f2cc928178
commit
2dc8e436db
2
go.mod
2
go.mod
|
|
@ -63,6 +63,7 @@ require (
|
|||
github.com/coocood/freecache v1.2.3
|
||||
github.com/coreos/go-semver v0.3.1
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f
|
||||
github.com/coreos/go-systemd/v22 v22.5.0
|
||||
github.com/couchbase/go-couchbase v0.1.1
|
||||
github.com/digitalocean/go-libvirt v0.0.0-20220811165305-15feff002086
|
||||
github.com/dimchansky/utfbom v1.1.1
|
||||
|
|
@ -321,6 +322,7 @@ require (
|
|||
github.com/goburrow/serial v0.1.1-0.20211022031912-bfb69110f8dd // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/gofrs/uuid v4.2.0+incompatible // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
|
||||
|
|
|
|||
4
go.sum
4
go.sum
|
|
@ -1029,6 +1029,8 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7
|
|||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c=
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/couchbase/go-couchbase v0.1.1 h1:ClFXELcKj/ojyoTYbsY34QUrrYCBi/1G749sXSCkdhk=
|
||||
github.com/couchbase/go-couchbase v0.1.1/go.mod h1:+/bddYDxXsf9qt0xpDUtRR47A2GjaXmGGAqQ/k3GJ8A=
|
||||
|
|
@ -1234,6 +1236,8 @@ github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+
|
|||
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
|
||||
|
|
|
|||
|
|
@ -6,5 +6,6 @@ This folder contains the plugins for the secret-store functionality:
|
|||
* http: Query secrets from an HTTP endpoint
|
||||
* jose: Javascript Object Signing and Encryption
|
||||
* os: Native tooling provided on Linux, MacOS, or Windows.
|
||||
* systemd: Secret-store to access systemd secrets
|
||||
|
||||
See each plugin's README for additional details.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
//go:build !custom || secretstores || secretstores.systemd
|
||||
|
||||
package all
|
||||
|
||||
import _ "github.com/influxdata/telegraf/plugins/secretstores/systemd" // register plugin
|
||||
|
|
@ -0,0 +1,246 @@
|
|||
|
||||
# Systemd Secret-Store Plugin
|
||||
|
||||
The `systemd` plugin allows utilizing credentials and secrets provided by
|
||||
[systemd][] to the Telegraf service. Systemd ensures that only the intended
|
||||
service can access the credentials for the lifetime of this service. The
|
||||
credentials appear as plaintext files to the consuming service but are stored
|
||||
encrypted on the host system. This encryption can also use TPM2 protection if
|
||||
available (see [this article][systemd-descr] for details).
|
||||
|
||||
This plugin does not support setting the credentials. See the
|
||||
[credentials management section](#credential-management) below for how to
|
||||
setup systemd credentials and how to add credentials
|
||||
|
||||
**Note**: Secrets of this plugin are static and are not updated after startup.
|
||||
|
||||
## Requirements and caveats
|
||||
|
||||
This plugin requires **systemd version 250+** with correctly set-up credentials
|
||||
via [systemd-creds][] (see [setup section](#credential-management)).
|
||||
However, to use `ImportCredential`, as done in the default service file, you
|
||||
need **systemd version 254+** otherwise you need to specify the credentials
|
||||
using `LoadCredentialEncrypted` in a service-override.
|
||||
|
||||
In the default setup, Telegraf expects credential files to be prefixed with
|
||||
`telegraf.` and without a custom name setting (i.e. no `--name`).
|
||||
|
||||
It is important to note that when TPM2 sealing is available on the host,
|
||||
credentials can only be created and used on the **same machine** as decrypting
|
||||
the secrets requires the encryption key *and* a key stored in TPM2. Therefore,
|
||||
creating credentials and then copying it to another machine will fail!
|
||||
|
||||
Please be aware that, due to its nature, this plugin is **ONLY** available
|
||||
when started as a service. It does **NOT** find any credentials when started
|
||||
manually via the command line! Therefore, `secrets` commands should **not**
|
||||
be used with this plugin.
|
||||
|
||||
## Usage <!-- @/docs/includes/secret_usage.md -->
|
||||
|
||||
Secrets defined by a store are referenced with `@{<store-id>:<secret_key>}`
|
||||
the Telegraf configuration. Only certain Telegraf plugins and options of
|
||||
support secret stores. To see which plugins and options support
|
||||
secrets, see their respective documentation (e.g.
|
||||
`plugins/outputs/influxdb/README.md`). If the plugin's README has the
|
||||
`Secret-store support` section, it will detail which options support secret
|
||||
store usage.
|
||||
|
||||
## Configuration
|
||||
|
||||
```toml @sample.conf
|
||||
# Secret-store to access systemd secrets
|
||||
[[secretstores.systemd]]
|
||||
## Unique identifier for the secretstore.
|
||||
## This id can later be used in plugins to reference the secrets
|
||||
## in this secret-store via @{<id>:<secret_key>} (mandatory)
|
||||
id = "systemd"
|
||||
|
||||
## Path to systemd credentials directory
|
||||
## This should not be required as systemd indicates this directory
|
||||
## via the CREDENTIALS_DIRECTORY environment variable.
|
||||
# path = "${CREDENTIALS_DIRECTORY}"
|
||||
|
||||
## Prefix to remove from systemd credential-filenames to derive secret names
|
||||
# prefix = "telegraf."
|
||||
|
||||
```
|
||||
|
||||
Each Secret provided by systemd will be available as file under
|
||||
`${CREDENTIALS_DIRECTORY}/<secret-name>` for the service. You will **not** be
|
||||
able to see them as a regular, non-telegraf user. Credential visibility from
|
||||
other systemd services is mediated by the `User=` and `PrivateMounts=`
|
||||
service-unit directives for those services. See the
|
||||
[systemd.exec man-page][systemd-exec] for details.
|
||||
|
||||
## Credential management
|
||||
|
||||
Most steps here are condensed from the [systemd-creds man-page][systemd-creds]
|
||||
and are using this command. Please also check that man-page as the options
|
||||
or verbs used here might be outdated for the systemd version you are using.
|
||||
|
||||
**Please note**: We are using `/etc/credstore.encrypted` as our storage
|
||||
location for encrypted credentials throughout the examples below and assuming
|
||||
a Telegraf install via package manager. If you are using some other means to
|
||||
install Telegraf you might need to create that directory.
|
||||
Furthermore, we assume the secret-store ID to be set to `systemd` in the
|
||||
examples.
|
||||
|
||||
Setting up systemd-credentials might vary on your distribution or version so
|
||||
please also check the documentation there. You might also need to install
|
||||
supporting packages such as `tpm2-tools`.
|
||||
|
||||
### Setup
|
||||
|
||||
If you have not done it already, systemd requires a first-time setup of the
|
||||
credential system. If you are planning to use the TPM2 chip of your system
|
||||
for protecting the credentials, you should first make sure that it is
|
||||
available using
|
||||
|
||||
```shell
|
||||
sudo systemd-creds has-tpm2
|
||||
```
|
||||
|
||||
The output should look similar to
|
||||
|
||||
```text
|
||||
partial
|
||||
-firmware
|
||||
+driver
|
||||
+system
|
||||
+subsystem
|
||||
```
|
||||
|
||||
If TPM2 is available on your system, credentials can also be tied to the device
|
||||
by utilizing TPM2 sealing. See the [systemd-creds man-page][systemd-creds] for
|
||||
details.
|
||||
|
||||
Now setup the credentials by creating the root key.
|
||||
|
||||
```shell
|
||||
sudo systemd-creds setup
|
||||
```
|
||||
|
||||
A warning may appears if you are storing the generated key on an unencrypted
|
||||
disk which is not recommended. With this, we are all set to create credentials.
|
||||
|
||||
### Creating credentials
|
||||
|
||||
After setting up the encryption key we can create a new credential using
|
||||
|
||||
```shell
|
||||
echo -n "john-doe-jr" | sudo systemd-creds encrypt - /etc/credstore.encrypted/telegraf.http_user
|
||||
```
|
||||
|
||||
You should now have a file named `telegraf.http_user` containing the encrypted
|
||||
username. The secret-store later provides the secret using this filename as the
|
||||
secret's key.
|
||||
**Please note:**: By default Telegraf strips the `telegraf.` prefix. If you use
|
||||
a different prefix or no prefix at all you need to adapt the `prefix` setting!
|
||||
|
||||
We can now add more secrets. To avoid potentially leaking the plain-text
|
||||
credentials through command-history or showing it on the screen we use
|
||||
|
||||
```shell
|
||||
systemd-ask-password -n | sudo systemd-creds encrypt - /etc/credstore.encrypted/telegraf.http_password
|
||||
```
|
||||
|
||||
to interactively enter the password.
|
||||
|
||||
### Using credentials as secrets
|
||||
|
||||
To use the credentials as secrets you need to first instantiate a `systemd`
|
||||
secret-store by adding
|
||||
|
||||
```toml
|
||||
[[secretstores.systemd]]
|
||||
id = "systemd"
|
||||
```
|
||||
|
||||
to your Telegraf configuration. Assuming the two example credentials
|
||||
`http_user` and `http_password` you can now use those as secrets via
|
||||
|
||||
```toml
|
||||
[[inputs.http]]
|
||||
urls = ["http://localhost/metrics"]
|
||||
username = "@{systemd:http_user}"
|
||||
password = "@{systemd:http_password}"
|
||||
|
||||
```
|
||||
|
||||
in your plugins.
|
||||
|
||||
### Chaining for unattended start
|
||||
|
||||
When using many secrets or when secrets need to be shared among hosts, listing
|
||||
all of them in the service file might be cumbersome. Additionally, it is hard
|
||||
to manually test Telegraf configurations with the `systemd` secret-store as
|
||||
those secrets are only available when started as a service.
|
||||
|
||||
Here, secret-store chaining comes into play, denoting a setup where one
|
||||
secret-store, in our case `secretstores.systemd`, is used to unlock another
|
||||
secret-store (`secretstores.jose` in this example).
|
||||
|
||||
```toml
|
||||
[[secretstores.systemd]]
|
||||
id = "systemd"
|
||||
|
||||
[[secretstores.jose]]
|
||||
id = "mysecrets"
|
||||
path = "/etc/telegraf/secrets"
|
||||
password = "@{systemd:initial}"
|
||||
```
|
||||
|
||||
Here we assume that an `initial` credential was injected through the service
|
||||
file. This `initial` secret is then used to unlock the `jose` secret-store
|
||||
which might provide many different secrets backed by encrypted files.
|
||||
|
||||
Input and output plugins can the use the `jose` secrets (via `@{mysecrets:...}`)
|
||||
to fill sensitive data such as usernames, passwords or tokens.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
Please always make sure your systemd version matches Telegraf's requirements,
|
||||
i.e. you do have version 254 or later.
|
||||
|
||||
When not being able to start the service please check the logs. A common issue
|
||||
is using the `--name` option which does not work with systemd's
|
||||
`ImportCredential` setting.
|
||||
a mismatch between the name stored in the credential (given during
|
||||
`systemd-creds encrypt`) and the one used in the
|
||||
`LoadCredentialEncrypted` statement.
|
||||
|
||||
In case you are having trouble referencing credentials in Telegraf, you should
|
||||
check what is available via
|
||||
|
||||
```shell
|
||||
CREDENTIALS_DIRECTORY=/etc/credstore.encrypted sudo systemd-creds list
|
||||
```
|
||||
|
||||
for the example above you should see
|
||||
|
||||
```text
|
||||
NAME SECURE SIZE PATH
|
||||
-------------------------------------------------------------------
|
||||
telegraf.http_password insecure 146B /etc/credstore.encrypted/telegraf.http_password
|
||||
telegraf.http_user insecure 142B /etc/credstore.encrypted/telegraf.http_user
|
||||
```
|
||||
|
||||
**Please note**: Telegraf's secret management functionality is not helpful here
|
||||
as credentials are *only* available to the systemd service, not via commandline.
|
||||
|
||||
Remember to remove the `prefix` configured in your secret-store from the `NAME`
|
||||
column to get the secrets' `key`.
|
||||
|
||||
To get the actual value of a credential use
|
||||
|
||||
```shell
|
||||
sudo systemd-creds decrypt /etc/credstore.encrypted/telegraf.http_password -
|
||||
```
|
||||
|
||||
Please use the above command(s) with care as they do reveal the secret value
|
||||
of the credential!
|
||||
|
||||
[systemd]: https://www.freedesktop.org/wiki/Software/systemd/
|
||||
[systemd-descr]: https://systemd.io/CREDENTIALS
|
||||
[systemd-creds]: https://www.freedesktop.org/software/systemd/man/systemd-creds.html
|
||||
[systemd-exec]: https://www.freedesktop.org/software/systemd/man/systemd.exec.html
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# Secret-store to access systemd secrets
|
||||
[[secretstores.systemd]]
|
||||
## Unique identifier for the secretstore.
|
||||
## This id can later be used in plugins to reference the secrets
|
||||
## in this secret-store via @{<id>:<secret_key>} (mandatory)
|
||||
id = "systemd"
|
||||
|
||||
## Path to systemd credentials directory
|
||||
## This should not be required as systemd indicates this directory
|
||||
## via the CREDENTIALS_DIRECTORY environment variable.
|
||||
# path = "${CREDENTIALS_DIRECTORY}"
|
||||
|
||||
## Prefix to remove from systemd credential-filenames to derive secret names
|
||||
# prefix = "telegraf."
|
||||
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
//go:build linux
|
||||
|
||||
//go:generate ../../../tools/readme_config_includer/generator
|
||||
package systemd
|
||||
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/coreos/go-systemd/v22/dbus"
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/plugins/secretstores"
|
||||
)
|
||||
|
||||
const systemdMinimumVersion = 250
|
||||
|
||||
// Required to be a variable to mock the version in tests
|
||||
var getSystemdVersion = getSystemdMajorVersion
|
||||
|
||||
//go:embed sample.conf
|
||||
var sampleConfig string
|
||||
|
||||
type Systemd struct {
|
||||
Path string `toml:"path"`
|
||||
Prefix string `toml:"prefix"`
|
||||
Log telegraf.Logger `toml:"-"`
|
||||
}
|
||||
|
||||
func (*Systemd) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
// Init initializes all internals of the secret-store
|
||||
func (s *Systemd) Init() error {
|
||||
version, err := getSystemdVersion()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to detect systemd version: %w", err)
|
||||
}
|
||||
s.Log.Debugf("Found systemd version %d...", version)
|
||||
if version < systemdMinimumVersion {
|
||||
return fmt.Errorf("systemd version %d below minimum version %d", version, systemdMinimumVersion)
|
||||
}
|
||||
|
||||
// By default the credentials directory is passed in by systemd
|
||||
// via the "CREDENTIALS_DIRECTORY" environment variable.
|
||||
defaultPath := os.Getenv("CREDENTIALS_DIRECTORY")
|
||||
if defaultPath == "" {
|
||||
s.Log.Warn("CREDENTIALS_DIRECTORY environment variable undefined. Make sure credentials are setup correctly!")
|
||||
if s.Path == "" {
|
||||
return errors.New("'path' required without CREDENTIALS_DIRECTORY")
|
||||
}
|
||||
}
|
||||
|
||||
// Use default path if no explicit was specified. This should be the common case.
|
||||
if s.Path == "" {
|
||||
s.Path = defaultPath
|
||||
}
|
||||
s.Path, err = filepath.Abs(s.Path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot determine absolute path of %q: %w", s.Path, err)
|
||||
}
|
||||
|
||||
// Check if we can access the target directory
|
||||
if _, err := os.Stat(s.Path); err != nil {
|
||||
return fmt.Errorf("accessing credentials directory %q failed: %w", s.Path, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Systemd) Get(key string) ([]byte, error) {
|
||||
secretFile, err := filepath.Abs(filepath.Join(s.Path, s.Prefix+key))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if filepath.Dir(secretFile) != s.Path {
|
||||
return nil, fmt.Errorf("invalid directory detected for key %q", key)
|
||||
}
|
||||
value, err := os.ReadFile(secretFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot read the secret's value: %w", err)
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (s *Systemd) List() ([]string, error) {
|
||||
secretFiles, err := os.ReadDir(s.Path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot read files: %w", err)
|
||||
}
|
||||
secrets := make([]string, 0, len(secretFiles))
|
||||
for _, entry := range secretFiles {
|
||||
key := strings.TrimPrefix(entry.Name(), s.Prefix)
|
||||
secrets = append(secrets, key)
|
||||
}
|
||||
return secrets, nil
|
||||
}
|
||||
|
||||
func (s *Systemd) Set(_, _ string) error {
|
||||
return errors.New("secret-store does not support creating secrets")
|
||||
}
|
||||
|
||||
// GetResolver returns a function to resolve the given key.
|
||||
func (s *Systemd) GetResolver(key string) (telegraf.ResolveFunc, error) {
|
||||
resolver := func() ([]byte, bool, error) {
|
||||
s, err := s.Get(key)
|
||||
return s, false, err
|
||||
}
|
||||
return resolver, nil
|
||||
}
|
||||
|
||||
func getSystemdMajorVersion() (int, error) {
|
||||
ctx := context.Background()
|
||||
conn, err := dbus.NewWithContext(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
fullVersion, err := conn.GetManagerProperty("Version")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
fullVersion = strings.Trim(fullVersion, "\"")
|
||||
return strconv.Atoi(strings.SplitN(fullVersion, ".", 2)[0])
|
||||
}
|
||||
|
||||
// Register the secret-store on load.
|
||||
func init() {
|
||||
secretstores.Add("systemd", func(_ string) telegraf.SecretStore {
|
||||
return &Systemd{Prefix: "telegraf."}
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
package systemd
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
//go:build linux
|
||||
|
||||
package systemd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func getSystemdVersionMin() (int, error) {
|
||||
return systemdMinimumVersion, nil
|
||||
}
|
||||
|
||||
func TestSampleConfig(t *testing.T) {
|
||||
plugin := &Systemd{}
|
||||
require.NotEmpty(t, plugin.SampleConfig())
|
||||
}
|
||||
|
||||
func TestMinimumVersion(t *testing.T) {
|
||||
getSystemdVersion = func() (int, error) { return 123, nil }
|
||||
|
||||
plugin := &Systemd{Log: testutil.Logger{}}
|
||||
require.ErrorContains(t, plugin.Init(), "below minimum version")
|
||||
}
|
||||
|
||||
func TestEmptyPath(t *testing.T) {
|
||||
getSystemdVersion = getSystemdVersionMin
|
||||
|
||||
plugin := &Systemd{Log: testutil.Logger{}}
|
||||
require.ErrorContains(t, plugin.Init(), "'path' required without CREDENTIALS_DIRECTORY")
|
||||
}
|
||||
|
||||
func TestEmptyCredentialsDirectoryWarning(t *testing.T) {
|
||||
getSystemdVersion = getSystemdVersionMin
|
||||
|
||||
logger := &testutil.CaptureLogger{}
|
||||
plugin := &Systemd{
|
||||
Path: "testdata",
|
||||
Log: logger}
|
||||
require.NoError(t, plugin.Init())
|
||||
|
||||
actual := logger.Warnings()
|
||||
require.Len(t, actual, 1)
|
||||
require.Contains(t, actual[0], "CREDENTIALS_DIRECTORY environment variable undefined")
|
||||
}
|
||||
|
||||
func TestPathNonExistentExplicit(t *testing.T) {
|
||||
getSystemdVersion = getSystemdVersionMin
|
||||
t.Setenv("CREDENTIALS_DIRECTORY", "testdata")
|
||||
|
||||
plugin := &Systemd{
|
||||
Path: "non/existent/path",
|
||||
Log: testutil.Logger{},
|
||||
}
|
||||
require.ErrorContains(t, plugin.Init(), "accessing credentials directory")
|
||||
}
|
||||
|
||||
func TestPathNonExistentImplicit(t *testing.T) {
|
||||
getSystemdVersion = getSystemdVersionMin
|
||||
t.Setenv("CREDENTIALS_DIRECTORY", "non/existent/path")
|
||||
|
||||
plugin := &Systemd{
|
||||
Log: testutil.Logger{},
|
||||
}
|
||||
require.ErrorContains(t, plugin.Init(), "accessing credentials directory")
|
||||
}
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
getSystemdVersion = getSystemdVersionMin
|
||||
t.Setenv("CREDENTIALS_DIRECTORY", "testdata")
|
||||
|
||||
plugin := &Systemd{Log: testutil.Logger{}}
|
||||
require.NoError(t, plugin.Init())
|
||||
}
|
||||
|
||||
func TestSetNotAvailable(t *testing.T) {
|
||||
getSystemdVersion = getSystemdVersionMin
|
||||
t.Setenv("CREDENTIALS_DIRECTORY", "testdata")
|
||||
|
||||
plugin := &Systemd{Log: testutil.Logger{}}
|
||||
require.NoError(t, plugin.Init())
|
||||
|
||||
// Try to Store the secrets, which this plugin should not let
|
||||
require.ErrorContains(t, plugin.Set("foo", "bar"), "secret-store does not support creating secrets")
|
||||
}
|
||||
|
||||
func TestListGet(t *testing.T) {
|
||||
getSystemdVersion = getSystemdVersionMin
|
||||
t.Setenv("CREDENTIALS_DIRECTORY", "testdata")
|
||||
|
||||
// secret files name and their content to compare under the `testdata` directory
|
||||
secrets := map[string]string{
|
||||
"secret-file-1": "IWontTell",
|
||||
"secret_file_2": "SuperDuperSecret!23",
|
||||
"secretFile": "foobar",
|
||||
}
|
||||
|
||||
// Initialize the plugin
|
||||
plugin := &Systemd{Log: testutil.Logger{}}
|
||||
require.NoError(t, plugin.Init())
|
||||
|
||||
// List the Secrets
|
||||
keys, err := plugin.List()
|
||||
require.NoError(t, err)
|
||||
require.Len(t, keys, len(secrets))
|
||||
// check if the returned array from List() is the same
|
||||
// as the name of secret files
|
||||
for secretFileName := range secrets {
|
||||
require.Contains(t, keys, secretFileName)
|
||||
}
|
||||
|
||||
// Get the secrets
|
||||
for _, k := range keys {
|
||||
value, err := plugin.Get(k)
|
||||
require.NoError(t, err)
|
||||
v, found := secrets[k]
|
||||
require.Truef(t, found, "unexpected secret requested that was not found: %q", k)
|
||||
require.Equal(t, v, string(value))
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolver(t *testing.T) {
|
||||
getSystemdVersion = getSystemdVersionMin
|
||||
t.Setenv("CREDENTIALS_DIRECTORY", "testdata")
|
||||
|
||||
// Secret Value Name to Resolve
|
||||
secretFileName := "secret-file-1"
|
||||
// Secret Value to Resolve To
|
||||
secretVal := "IWontTell"
|
||||
|
||||
// Initialize the plugin
|
||||
plugin := &Systemd{Log: testutil.Logger{}}
|
||||
require.NoError(t, plugin.Init())
|
||||
|
||||
// Get the resolver
|
||||
resolver, err := plugin.GetResolver(secretFileName)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resolver)
|
||||
s, dynamic, err := resolver()
|
||||
require.NoError(t, err)
|
||||
require.False(t, dynamic)
|
||||
require.Equal(t, secretVal, string(s))
|
||||
}
|
||||
|
||||
func TestResolverInvalid(t *testing.T) {
|
||||
getSystemdVersion = getSystemdVersionMin
|
||||
t.Setenv("CREDENTIALS_DIRECTORY", "testdata")
|
||||
|
||||
// Initialize the plugin
|
||||
plugin := &Systemd{Log: testutil.Logger{}}
|
||||
require.NoError(t, plugin.Init())
|
||||
|
||||
// Get the resolver
|
||||
resolver, err := plugin.GetResolver("foo")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resolver)
|
||||
_, _, err = resolver()
|
||||
require.ErrorContains(t, err, "cannot read the secret's value:")
|
||||
}
|
||||
|
||||
func TestGetNonExistant(t *testing.T) {
|
||||
getSystemdVersion = getSystemdVersionMin
|
||||
t.Setenv("CREDENTIALS_DIRECTORY", "testdata")
|
||||
|
||||
// Initialize the plugin
|
||||
plugin := &Systemd{Log: testutil.Logger{}}
|
||||
require.NoError(t, plugin.Init())
|
||||
|
||||
// Get the resolver
|
||||
_, err := plugin.Get("foo")
|
||||
require.ErrorContains(t, err, "cannot read the secret's value:")
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
IWontTell
|
||||
|
|
@ -0,0 +1 @@
|
|||
foobar
|
||||
|
|
@ -0,0 +1 @@
|
|||
SuperDuperSecret!23
|
||||
|
|
@ -8,6 +8,7 @@ Wants=network-online.target
|
|||
Type=notify
|
||||
EnvironmentFile=-/etc/default/telegraf
|
||||
User=telegraf
|
||||
ImportCredential=telegraf.*
|
||||
ExecStart=/usr/bin/telegraf -config /etc/telegraf/telegraf.conf -config-directory /etc/telegraf/telegraf.d $TELEGRAF_OPTS
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
Restart=on-failure
|
||||
|
|
@ -15,6 +16,7 @@ RestartForceExitStatus=SIGPIPE
|
|||
KillMode=mixed
|
||||
TimeoutStopSec=5
|
||||
LimitMEMLOCK=8M:8M
|
||||
PrivateMounts=true
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
|
|||
Loading…
Reference in New Issue