diff --git a/dependency/vault_read.go b/dependency/vault_read.go index 02b8db8d4..c2f837e4d 100644 --- a/dependency/vault_read.go +++ b/dependency/vault_read.go @@ -150,7 +150,7 @@ func (d *VaultReadQuery) readSecret(clients *ClientSet) (*api.Secret, error) { isKVv2 = false d.secretPath = d.rawPath } else if isKVv2 { - d.secretPath = shimKVv2Path(d.rawPath, mountPath) + d.secretPath = shimKVv2Path(d.rawPath, mountPath, clients.Vault().Namespace()) } else { d.secretPath = d.rawPath } @@ -196,18 +196,28 @@ func deletedKVv2(s *api.Secret) bool { // shimKVv2Path aligns the supported legacy path to KV v2 specs by inserting // /data/ into the path for reading secrets. Paths for metadata are not modified. -func shimKVv2Path(rawPath, mountPath string) string { +func shimKVv2Path(rawPath, mountPath, clientNamespace string) string { switch { case rawPath == mountPath, rawPath == strings.TrimSuffix(mountPath, "/"): return path.Join(mountPath, "data") default: - p := strings.TrimPrefix(rawPath, mountPath) + + // Canonicalize the client namespace path to always having a '/' suffix + if !strings.HasSuffix(clientNamespace, "/") { + clientNamespace += "/" + } + // Extract client namespace from mount path if it exists + rawPathNsAndMountPath := strings.TrimPrefix(mountPath, clientNamespace) + + // Trim (mount path - client namespace) from the raw path + p := strings.TrimPrefix(rawPath, rawPathNsAndMountPath) // Only add /data/ prefix to the path if neither /data/ or /metadata/ are // present. if strings.HasPrefix(p, "data/") || strings.HasPrefix(p, "metadata/") { return rawPath } - return path.Join(mountPath, "data", p) + + return path.Join(rawPathNsAndMountPath, "data", p) } } diff --git a/dependency/vault_read_test.go b/dependency/vault_read_test.go index 7b2200cc6..9dc0daaaf 100644 --- a/dependency/vault_read_test.go +++ b/dependency/vault_read_test.go @@ -652,66 +652,111 @@ func TestVaultReadQuery_String(t *testing.T) { func TestShimKVv2Path(t *testing.T) { cases := []struct { - name string - path string - mountPath string - expected string + name string + path string + mountPath string + expected string + clientNamespace string }{ { "full path", "secret/data/foo/bar", "secret/", "secret/data/foo/bar", + "", }, { "data prefix added", "secret/foo/bar", "secret/", "secret/data/foo/bar", + "", }, { "full path with data* in subpath", "secret/data/datafoo/bar", "secret/", "secret/data/datafoo/bar", + "", }, { "prefix added with data* in subpath", "secret/datafoo/bar", "secret/", "secret/data/datafoo/bar", + "", }, { "prefix added with *data in subpath", "secret/foodata/foo/bar", "secret/", "secret/data/foodata/foo/bar", + "", }, { "prefix not added to metadata", "secret/metadata/foo/bar", "secret/", "secret/metadata/foo/bar", + "", }, { "prefix added with metadata* in subpath", "secret/metadatafoo/foo/bar", "secret/", "secret/data/metadatafoo/foo/bar", + "", }, { "prefix added with *metadata in subpath", "secret/foometadata/foo/bar", "secret/", "secret/data/foometadata/foo/bar", + "", }, { "prefix added to mount path", "secret/", "secret/", "secret/data", + "", }, { "prefix added to mount path not exact match", "secret", "secret/", "secret/data", + "", + }, + { + "raw path contains partial namespace, not adjusted", + "c/secret/foo", + "a/b/c/secret/", + "c/secret/data/foo", + "a/b", + }, + { + "raw path contains partial namespace, adjusted", + "c/secret/data/foo", + "a/b/c/secret/", + "c/secret/data/foo", + "a/b", + }, + { + "raw path contains partial namespace, and 'data' in secret path, not adjusted", + "c/secret/random/data/here", + "a/b/c/secret/", + "c/secret/data/random/data/here", + "a/b", + }, { + "raw path contains partial namespace, and 'data' in secret path, adjusted", + "c/secret/data/random/data/here", + "a/b/c/secret/", + "c/secret/data/random/data/here", + "a/b", + }, + { + "raw path contains partial namespace, nested namespace has same name, adjusted", + "a/secret/data/foo", + "a/a/secret/", + "a/secret/data/foo", + "a/", }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { - actual := shimKVv2Path(tc.path, tc.mountPath) + actual := shimKVv2Path(tc.path, tc.mountPath, tc.clientNamespace) assert.Equal(t, tc.expected, actual) }) } diff --git a/dependency/vault_write.go b/dependency/vault_write.go index 3524f532e..2232d1c79 100644 --- a/dependency/vault_write.go +++ b/dependency/vault_write.go @@ -156,7 +156,7 @@ func (d *VaultWriteQuery) writeSecret(clients *ClientSet, opts *QueryOptions) (* data := d.data mountPath, isv2, _ := isKVv2(clients.Vault(), path) if isv2 { - path = shimKVv2Path(path, mountPath) + path = shimKVv2Path(path, mountPath, clients.Vault().Namespace()) data = map[string]interface{}{"data": d.data} }