Vault agent templates - how to get secret previous version

Hi,

I try to create template which will create file contain current and previous secret version.
I figure out that i can pull current version number from secret metadata. Then I can tansform it and use subtract to find previous version number. In this point I have information about version i want to get but i can’t figure out how to pull it. I theory it’s easy and i just need to add ?version= when i’m pulling secret from Vault however I can’t find any working examples. Maybe someone on forum have more experiance and know how to do it? I will be appreciated for any clues :).

this is what i try to do:

#This is working:
{{- with secret "kv/test" -}}
  {{- $cversion := .Data | toJSON | parseJSON}}
  {{- $pversion := $cversion.metadata.version | subtract 1 }}
---
 cv: {{ $cversion.metadata.version }}
 pv: {{ $pversion }}

 {{  .Data.data.test }}
---
#this part is not working - {{ $pversion }} is interpolated as ''
{{- with secret "kv/test?version={{ $pversion }}" -}}
   {{  .Data.data.test }}
{{- end -}}
{{- end -}}

Did you ever figure this out?

I missed this when first posted (sorry @jacekjaros). The problem in the original post is that “quoted strings” in templates are static strings and you need to evaluate it to get the version variable replaced. Replacing that last “not working” section with the below should work in that case…

{{ $vsecret := $pversion | printf "secret/bar?version=%d" }}
{{- with secret $vsecret -}}
   {{  .Data.data.test }}
{{- end -}}

That is you use the printf to create the string needed to query based on the dynamic $pversion variable.

Hope this helps.

2 Likes

Hi there,

I tried the solution and it does not work for me. $vsecret evaluates to "secret/bar?version=%!d(float64=2)" (In this example the latest version is 3). Somehow this doesn’t cause an error, but in the section below it causes {{ .Data.data.test }} to reference the current version and not the previous version.

{{ $vsecret := $pversion | printf "secret/bar?version=%d" }}
{{- with secret $vsecret -}}
   {{  .Data.data.test }}
{{- end -}}

For example, if you want to export both the new and old keys, you would expect:

  MINIO_ACCESS_KEY="minio-new"
  MINIO_SECRET_KEY="minio123-new"
  MINIO_ACCESS_KEY_OLD="minio"
  MINIO_SECRET_KEY_OLD="minio123"

Actual result:

  MINIO_ACCESS_KEY="minio-new"
  MINIO_SECRET_KEY="minio123-new"
  MINIO_ACCESS_KEY_OLD="minio-new"
  MINIO_SECRET_KEY_OLD="minio123-new"

So I think it is probably this bit… I had an additional change in this area that might be necessary. Here’s the version of those lines from my tests case…

{{- with secret "secret/foo" -}}
    {{- $pversion := .Data.data.version | parseInt | subtract 1 }}

That parseInt would convert the float64 (the default numeric type used when parsing numbers in the templates) to an integer and work as you’d think.

3 Likes

I managed to solve it similarly, by formatting %v rather than %d. Thank you for the help!

One more question: how to deal with the edge case when the previous secret was deleted or destroyed? I am trying keyExists, as follows:
{{- if keyExists path/to/previous/accessKey }} but this is getting connection errors such as:

vault-agent-init 2021-11-09T12:24:28.034Z [WARN] (view) kv.get(path/to/secret?version=3/accessKey): Get "http://127.0.0.1:8500/v1/kv/path/to/secret%3Fversion=3/accessKey?stale=&wait=60000ms": dial tcp 127.0.0.1:8500: connect: connection refused (retry attempt 6 after "8s")

I have also tried using hasKey from Sprig. That leads to the following error:

template: :9: function "hasKey" not defined" countered during run, refer to logs for more details.

keyExists only works with Consul keys, not Vault secrets. From the context I’m guessing you’re trying to use it with a secret which isn’t going to work.

If my guess is wrong, please include a bit more context on the problem. Thanks.

Indeed. I would like to include a conditional to check whether a (previous) secret was deleted or destroyed. When such a check is not in place, the code breaks.

Maybe a new post with a summary and a simple example of what you’re trying to accomplish will help provide some details to the community (including myself) that might suggest alternative approaches? Other than that the only suggestion I can think of at the moment is that you could submit a PR adding secretExists. Though I really think there is probably an alternative approach to your issue as this hasn’t come up before in my memory (or a quick search through existing issues/prs).

Thanks.

1 Like