Skip to content

secretstores.vault: Setting a secret removes all other secrets at the same path #19287

Description

@skartikey

Relevant telegraf.conf

[[secretstores.vault]]
  id = "mystore"
  address = "http://127.0.0.1:8200"
  mount_path = "my-mount-path"
  secret_path = "my-secret-path"
  engine = "kv-v2"
  token = "SomeToken"

Logs from Telegraf

No errors are logged. The secrets are removed silently and subsequent reads of
the removed keys succeed while returning an empty value.

System info

Telegraf 1.40.0 (master, f7bc19a), Vault 1.20.4, Docker 28.3.2

Docker

Reproduced against the hashicorp/vault:1.20.4 image, using the same
testcontainers setup as the existing tests in plugins/secretstores/vault/vault_test.go.

Steps to reproduce

  1. Start Vault and enable a KV engine at my-mount-path.
  2. Store two secrets under the same secret path:
    vault kv put -mount=my-mount-path my-secret-path alpha=one beta=two
  3. Confirm both are visible: telegraf secrets list mystore prints alpha and beta.
  4. Add a third secret: telegraf secrets set mystore gamma three
  5. List again: telegraf secrets list mystore

Expected behavior

gamma is added to the secret path, and alpha and beta are still there.
This is what telegraf secrets set documents: "create or modify a secret in the
given store".

Actual behavior

The path holds only gamma. Both alpha and beta are gone.

Nothing reports an error. telegraf secrets get mystore alpha afterwards exits
successfully and prints an empty value, so a plugin referencing @{mystore:alpha}
resolves an empty secret and will attempt to authenticate with it rather than
failing loudly.

This happens on both kv-v1 and kv-v2. On kv-v2 the previous version is
still in Vault's version history, so the data is recoverable. On kv-v1 the
write overwrites in place and the other secrets are lost permanently.

Additional info

Reproduced with the following test added to plugins/secretstores/vault/vault_test.go:

func testSetSiblings(t *testing.T, engine string) {
	t.Helper()

	mountPath := "my-mount-path"
	secretPath := "my-secret-path"

	container, closer := createContainer(t, []string{
		fmt.Sprintf("secrets enable -path=%s %s", mountPath, engine),
		fmt.Sprintf("kv put -mount=%s %s alpha=one beta=two", mountPath, secretPath),
	})
	defer closer()

	addr, err := container.HttpHostAddress(context.Background())
	require.NoError(t, err)

	plugin := &Vault{
		ID:         "test_" + engine,
		Address:    addr,
		MountPath:  mountPath,
		SecretPath: secretPath,
		Engine:     engine,
		Token:      config.NewSecret([]byte("SomeToken")),
	}
	require.NoError(t, plugin.Init())

	require.NoError(t, plugin.Set("gamma", "three"))

	keys, err := plugin.List()
	require.NoError(t, err)
	slices.Sort(keys)
	require.Equal(t, []string{"alpha", "beta", "gamma"}, keys)
}

Output on the current master, for both engines:

[kv-v1] BEFORE Set: [alpha beta]
[kv-v1] AFTER  Set: [gamma]
[kv-v2] BEFORE Set: [alpha beta]
[kv-v2] AFTER  Set: [gamma]

Metadata

Metadata

Assignees

Labels

bugunexpected problem or unintended behavior

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions