From 74f87cc99a1679a0c7151f3841725265475713fa Mon Sep 17 00:00:00 2001 From: Tom Proctor Date: Mon, 22 May 2023 14:10:41 +0100 Subject: [PATCH 1/2] Support setting kv-v2 version for VaultStaticSecret --- CHANGELOG.md | 1 + api/v1alpha1/vaultstaticsecret_types.go | 4 ++++ ...secrets.hashicorp.com_vaultstaticsecrets.yaml | 5 +++++ ...secrets.hashicorp.com_vaultstaticsecrets.yaml | 5 +++++ controllers/vaultstaticsecret_controller.go | 6 +++++- .../vaultstaticsecret_integration_test.go | 16 +++++++++++++++- 6 files changed, 35 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56d215b7..ed98bd4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Features: Improvements: * VaultDynamicSecrets (VDS): Generate new credentials if lease renewal TTL is truncated [GH-170](https://github.com/hashicorp/vault-secrets-operator/pull/170) * VaultDynamicSecrets (VDS): Replace `Spec.Role` with `Spec.Path` (**breaking change**) [GH-172](https://github.com/hashicorp/vault-secrets-operator/pull/172) +* VaultStaticSecrets (VSS): Add `Spec.Version` field to support fetching a specific kv-v2 secret version [GH-200](https://github.com/hashicorp/vault-secrets-operator/pull/200) ## 0.1.0-beta (March 29th, 2023) diff --git a/api/v1alpha1/vaultstaticsecret_types.go b/api/v1alpha1/vaultstaticsecret_types.go index 0383e48f..c6a031bb 100644 --- a/api/v1alpha1/vaultstaticsecret_types.go +++ b/api/v1alpha1/vaultstaticsecret_types.go @@ -22,6 +22,10 @@ type VaultStaticSecretSpec struct { Mount string `json:"mount"` // Name of the secret in Vault Name string `json:"name"` + // Version of the secret to fetch. Only valid for type kv-v2. Corresponds to version query parameter: + // https://developer.hashicorp.com/vault/api-docs/secret/kv/kv-v2#version + // +kubebuilder:validation:Minimum=0 + Version int `json:"version,omitempty"` // Type of the Vault static secret // +kubebuilder:validation:Enum={kv-v1,kv-v2} Type string `json:"type"` diff --git a/chart/crds/secrets.hashicorp.com_vaultstaticsecrets.yaml b/chart/crds/secrets.hashicorp.com_vaultstaticsecrets.yaml index f7d5b71c..3d41ffbc 100644 --- a/chart/crds/secrets.hashicorp.com_vaultstaticsecrets.yaml +++ b/chart/crds/secrets.hashicorp.com_vaultstaticsecrets.yaml @@ -131,6 +131,11 @@ spec: specified the Operator will default to the `default` VaultAuth, configured in its own Kubernetes namespace. type: string + version: + description: 'Version of the secret to fetch. Only valid for type + kv-v2. Corresponds to version query parameter: https://developer.hashicorp.com/vault/api-docs/secret/kv/kv-v2#version' + minimum: 0 + type: integer required: - destination - mount diff --git a/config/crd/bases/secrets.hashicorp.com_vaultstaticsecrets.yaml b/config/crd/bases/secrets.hashicorp.com_vaultstaticsecrets.yaml index f7d5b71c..3d41ffbc 100644 --- a/config/crd/bases/secrets.hashicorp.com_vaultstaticsecrets.yaml +++ b/config/crd/bases/secrets.hashicorp.com_vaultstaticsecrets.yaml @@ -131,6 +131,11 @@ spec: specified the Operator will default to the `default` VaultAuth, configured in its own Kubernetes namespace. type: string + version: + description: 'Version of the secret to fetch. Only valid for type + kv-v2. Corresponds to version query parameter: https://developer.hashicorp.com/vault/api-docs/secret/kv/kv-v2#version' + minimum: 0 + type: integer required: - destination - mount diff --git a/controllers/vaultstaticsecret_controller.go b/controllers/vaultstaticsecret_controller.go index 5574658b..b83c8807 100644 --- a/controllers/vaultstaticsecret_controller.go +++ b/controllers/vaultstaticsecret_controller.go @@ -93,7 +93,11 @@ func (r *VaultStaticSecretReconciler) Reconcile(ctx context.Context, req ctrl.Re if err != nil { return ctrl.Result{}, err } - resp, err = w.Get(ctx, o.Spec.Name) + if o.Spec.Version == 0 { + resp, err = w.Get(ctx, o.Spec.Name) + } else { + resp, err = w.GetVersion(ctx, o.Spec.Name, o.Spec.Version) + } default: err = fmt.Errorf("unsupported secret type %q", o.Spec.Type) logger.Error(err, "") diff --git a/test/integration/vaultstaticsecret_integration_test.go b/test/integration/vaultstaticsecret_integration_test.go index 9b4c28c6..e5c98b57 100644 --- a/test/integration/vaultstaticsecret_integration_test.go +++ b/test/integration/vaultstaticsecret_integration_test.go @@ -275,6 +275,7 @@ func TestVaultStaticSecret_kv(t *testing.T) { expectedExisting []expectedData create int createTypes []string + version int }{ { name: "existing", @@ -300,6 +301,12 @@ func TestVaultStaticSecret_kv(t *testing.T) { create: 2, createTypes: []string{consts.KVSecretTypeV2}, }, + { + name: "create-kv-v2-fixed-version", + create: 2, + createTypes: []string{consts.KVSecretTypeV2}, + version: 1, + }, { name: "create-both", create: 2, @@ -355,7 +362,11 @@ func TestVaultStaticSecret_kv(t *testing.T) { } else { putKV(t, obj, expected.update) - data = expected.update + if obj.Spec.Version == 1 { + data = expected.initial + } else { + data = expected.update + } } secret, err := waitForSecretData(t, ctx, crdClient, 30, 1*time.Second, obj.Spec.Destination.Name, @@ -442,6 +453,9 @@ func TestVaultStaticSecret_kv(t *testing.T) { HMACSecretData: true, }, } + if tt.version != 0 { + vssObj.Spec.Version = tt.version + } if !skipCleanup { t.Cleanup(func() { From cb4140ebb490b3485532eccbe064709595a359a8 Mon Sep 17 00:00:00 2001 From: Tom Proctor Date: Mon, 22 May 2023 20:19:32 +0100 Subject: [PATCH 2/2] Remove parallel test race condition (I think) --- test/integration/vaultstaticsecret_integration_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/vaultstaticsecret_integration_test.go b/test/integration/vaultstaticsecret_integration_test.go index e5c98b57..9795462f 100644 --- a/test/integration/vaultstaticsecret_integration_test.go +++ b/test/integration/vaultstaticsecret_integration_test.go @@ -429,7 +429,7 @@ func TestVaultStaticSecret_kv(t *testing.T) { t.Parallel() mount := kvType + testID - dest := fmt.Sprintf("create-%s-%d", kvType, idx) + dest := fmt.Sprintf("%s-%s-%d", tt.name, kvType, idx) expected := expectedData{ initial: map[string]interface{}{"dest-initial": dest}, update: map[string]interface{}{"dest-updated": dest},