Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for enumerating all versions of a keyvault secret #27347

Open
1 task done
ben-childs-docusign opened this issue Sep 10, 2024 · 8 comments · May be fixed by #27393
Open
1 task done

Support for enumerating all versions of a keyvault secret #27347

ben-childs-docusign opened this issue Sep 10, 2024 · 8 comments · May be fixed by #27393

Comments

@ben-childs-docusign
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
  • Please do not leave comments along the lines of "+1", "me too" or "any updates", they generate extra noise for issue followers and do not help prioritize the request
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment and review the contribution guide to help.

Description

A prior issue was filed to support this but it was closed with only a partial implementation:
#21283

It is possible to pass the version as a parameter to the secret object however it is still not possible to enumerate all versions of a secret which would be useful in the case that you want to e.g. publish the last 2 versions of a secret automatically.

New or Affected Resource(s)/Data Source(s)

azurerm_key_vault_secret

Potential Terraform Configuration

data "azurerm_key_vault_secret_versions" "sourced_secret_versions" {
  name         = secret_name
  key_vault_id = data.azurerm_key_vault.source.id
}

data "azurerm_key_vault_secret" "sourced_secret" {
  name         = secret_name
  version_id   = data.azurerm_key_vault_secret_versions.sourced_secret_versions.first
  key_vault_id = data.azurerm_key_vault.source.id
}

References

#21283

@github-actions github-actions bot added the service/key-vault Key Vault label Sep 10, 2024
@ned1313
Copy link
Contributor

ned1313 commented Sep 11, 2024

@ben-childs-docusign what attributes would you expect to be returned by the data source azurerm_key_vault_secret_versions? The API call in question would be Get Secret Versions and the response includes a lot more than just the secret ID for each version.

The resulting list of versions would probably be a list of maps ordered by creation date. Each map would at least have the id key, which would make your code look more like this:

data "azurerm_key_vault_secret_versions" "sourced_secret_versions" {
  name         = secret_name
  key_vault_id = data.azurerm_key_vault.source.id
}

data "azurerm_key_vault_secret" "sourced_secret" {
  name         = secret_name
  version_id   = data.azurerm_key_vault_secret_versions.sourced_secret_versions[0].id
  key_vault_id = data.azurerm_key_vault.source.id
}

What other keys would you expect to find in the map for each secret version? I would think you would want enabled status and creation date. What do you think?

Your special attribute first has some ambiguity to it. Does first refer to the first version of the secret ever created, or does it refer to the most recent version of the secret? Do you think we need the first attribute or would latest be better?

@ben-childs-docusign
Copy link
Author

Hi Ned, thanks for taking a look,

I just copied this definition from the prior opened issue which was closed without adding support to list versions. So I didn't give the definition much thought.

For our specific use case we want to be able to list the most recent "n" versions of a secret and I agree it should probably return an array.

Ideally each secret version would include a version id, not before, expiry and enabled flags. I suppose we may as well return all these attributes provided by the api

image

@ben-childs-docusign
Copy link
Author

it might also be useful to have a parameter to control the max number of results (maxresults) e.g. in our case we would likely only be interested in the last 2-3 versions. The use case for us is staged rollout of automatically renewed certificates in which case we need both the current and prior versions.

@ned1313
Copy link
Contributor

ned1313 commented Sep 11, 2024

Thanks for the feedback and clarification! The API does support a max version query value, so that should be simple enough. For the data source arguments, it sounds like we'd want:

  • name
  • key_vault_id
  • results (defaulted to 25)

And for the returned list of secret versions, we would have the attributes:

  • secret_id
  • created_on
  • expired_on
  • updated_on
  • not_before
  • enabled

If all that sounds good, I'll start working on the data source.

@ben-childs-docusign
Copy link
Author

ben-childs-docusign commented Sep 11, 2024

That sound great thanks Ned! Also just to confirm each secret version should include the actual version id, i guess that would be part of secret_id?

@ned1313
Copy link
Contributor

ned1313 commented Sep 12, 2024

It will have the id along with the other attributes as part of each version.

@ned1313
Copy link
Contributor

ned1313 commented Sep 13, 2024

The returned ID is the full URI, so I added two attributes:

  • id - the short ID that can be used with the azurerm_key_vault_secret data source.
  • uri - the full URI of the secret, just in case.

@ned1313 ned1313 linked a pull request Sep 13, 2024 that will close this issue
10 tasks
@ben-childs-docusign
Copy link
Author

ben-childs-docusign commented Oct 3, 2024

In the mean time I was able to get a version of this working using external data with the following script:

#/bin/bash
set -e
set -x

# Read input parameters
eval "$(jq -r '@sh "VAULT=\(.vault) SECRET=\(.secret)"')"

# Load secret versions using az cli which returns an array of values in json [ { version info } ... ]
# map id property of each value to the key of the dictionary, e.g. { id => { version info } ... }
# and then json encode the values so { id => "\{ version info \}" ...} since terraform wants a map of string => string
az keyvault secret list-versions --name $SECRET --vault-name $VAULT -o json \
  | jq 'map({(.id): .}) | add' \
  | jq 'with_entries(.value |= @json)'
data "external" "secret_versions" {
  program = ["bash", "get-secret-versions.sh"]
  query = {
    vault  = "vault-name"
    secret = "secret-name"
  }
}

locals {
  secret_versions = {
    for key, value in
    { for key, value in data.external.secret_versions.result : one(regex("secrets/([^/]+/[0-9a-f]+)$", key)) => jsondecode(value) } :
    key => merge(value, {
      name    = split("/", key)[0]
      version = split("/", key)[1]
    }) if value.attributes.enabled
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants