From 34ba1bd328352ea93c8048409cd12ee6156d6965 Mon Sep 17 00:00:00 2001 From: VioletHynes Date: Mon, 12 Feb 2024 11:18:05 -0500 Subject: [PATCH 1/3] VAULT-528 Fix issue with consul-template not rendering secrets with delete_version_after set on them --- CHANGELOG.md | 1 + dependency/vault_read.go | 15 ++++++++- dependency/vault_read_test.go | 60 +++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94a3eac1f..a24660238 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ NEW FEATURES: BUG FIXES: * Fetch services query not overriding opts correctly [NET-7571](https://hashicorp.atlassian.net/browse/NET-7571) +* Consul-template now correctly renders KVv2 secrets with `delete_version_after` set [NET-3777](https://hashicorp.atlassian.net/browse/NET-3777) ## v0.36.0 (January 3, 2024) diff --git a/dependency/vault_read.go b/dependency/vault_read.go index f301de1d2..eb77a32e2 100644 --- a/dependency/vault_read.go +++ b/dependency/vault_read.go @@ -176,7 +176,20 @@ func (d *VaultReadQuery) readSecret(clients *ClientSet) (*api.Secret, error) { func deletedKVv2(s *api.Secret) bool { switch md := s.Data["metadata"].(type) { case map[string]interface{}: - return md["deletion_time"] != "" + deletionTime, ok := md["deletion_time"].(string) + if !ok { + // Not a string, end early + return false + } + t, err := time.Parse(time.RFC3339, deletionTime) + if err != nil { + // Deletion time is either empty, or not a valid string. + return false + } + + // If now is 'after' the deletion time, then the secret + // should be deleted. + return time.Now().After(t) } return false } diff --git a/dependency/vault_read_test.go b/dependency/vault_read_test.go index 73cdd8d41..4060fcb18 100644 --- a/dependency/vault_read_test.go +++ b/dependency/vault_read_test.go @@ -711,3 +711,63 @@ func TestShimKVv2Path(t *testing.T) { }) } } + +// TestDeletedKVv2 tests that deletedKVv2 returns true and false +// in the correct scenarios. +func TestDeletedKVv2(t *testing.T) { + // Intentionally using string literals here since they are taken + // directly from Vault's API. + assert.True(t, deletedKVv2(&api.Secret{ + Data: map[string]interface{}{ + "metadata": map[string]interface{}{ + "deletion_time": "2022-06-15T20:23:40.067093Z", + }, + }, + })) + assert.True(t, deletedKVv2(&api.Secret{ + Data: map[string]interface{}{ + "metadata": map[string]interface{}{ + "deletion_time": "2019-06-19T20:56:35.662563Z", + }, + }, + })) + + // It should work with any RFC3339 formatted string + assert.True(t, deletedKVv2(&api.Secret{ + Data: map[string]interface{}{ + "metadata": map[string]interface{}{ + "deletion_time": time.Now().Add(-1 * time.Hour).Format(time.RFC3339), + }, + }, + })) + + assert.False(t, deletedKVv2(&api.Secret{ + Data: map[string]interface{}{ + "metadata": map[string]interface{}{ + "deletion_time": time.Now().Add(time.Hour).String(), + }, + }, + })) + + // Edge cases: + assert.False(t, deletedKVv2(&api.Secret{})) + assert.False(t, deletedKVv2(&api.Secret{ + Data: map[string]interface{}{ + "metadata": map[string]interface{}{}, + }, + })) + assert.False(t, deletedKVv2(&api.Secret{ + Data: map[string]interface{}{ + "metadata": map[string]interface{}{ + "deletion_time": "", + }, + }, + })) + assert.False(t, deletedKVv2(&api.Secret{ + Data: map[string]interface{}{ + "metadata": map[string]interface{}{ + "deletion_time": "foo", + }, + }, + })) +} From 31622a139289bdbae0b10cef420d485a324d0b6e Mon Sep 17 00:00:00 2001 From: VioletHynes Date: Tue, 13 Feb 2024 08:48:43 -0500 Subject: [PATCH 2/3] VAULT-528 Improve comment --- dependency/vault_read.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependency/vault_read.go b/dependency/vault_read.go index eb77a32e2..02b8db8d4 100644 --- a/dependency/vault_read.go +++ b/dependency/vault_read.go @@ -178,7 +178,7 @@ func deletedKVv2(s *api.Secret) bool { case map[string]interface{}: deletionTime, ok := md["deletion_time"].(string) if !ok { - // Not a string, end early + // Key not present or not a string, end early return false } t, err := time.Parse(time.RFC3339, deletionTime) From 072b5966846f980c8950dbec3bd618e31912cdda Mon Sep 17 00:00:00 2001 From: VioletHynes Date: Tue, 13 Feb 2024 09:58:06 -0500 Subject: [PATCH 3/3] VAULT-528 two extra edge cases --- dependency/vault_read_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dependency/vault_read_test.go b/dependency/vault_read_test.go index 4060fcb18..f055fc791 100644 --- a/dependency/vault_read_test.go +++ b/dependency/vault_read_test.go @@ -770,4 +770,12 @@ func TestDeletedKVv2(t *testing.T) { }, }, })) + assert.False(t, deletedKVv2(&api.Secret{ + Data: map[string]interface{}{ + "metadata": "not an interface", + }, + })) + assert.False(t, deletedKVv2(&api.Secret{ + Data: map[string]interface{}{}, + })) }