pkaramol
pkaramol

Reputation: 19382

Validating through terraform that a vault policy exists before using it in a group

I have the following structure

module "policies" {
  source   = "../../../../path/to/my/custom/modules/groups"
  for_each = var.config.policies

  name   = each.key
  policy = each.value
}

module "groups" {
  source   = "../../../../path/to/my/custom/modules/groups"
  for_each = var.config.groups

  name     = each.key
  type     = each.value.type
  policies = each.value.policies
  depends_on = [
    module.policies
  ]
}

Policies and groups are declared in a yaml file from which through yamldecode the corresponding variables to for_each are created.

Is there any way to make sure that the policies passed to policies = each.value.policies of the groups module DO exist?

I mean, OK I have the depends_on clause, but I want to also provision for typos in the yaml file and other similar situations.

Upvotes: 0

Views: 587

Answers (1)

Martin Atkins
Martin Atkins

Reputation: 74479

The usual way to declare a dependency on an external object (managed elsewhere) in Terraform is to use a data block using a data source defined by the provider responsible for that object. If the goal is only to verify that the object exists then it's enough to declare the data source and then have your downstream object's configuration refer to anything about its result, just so Terraform can see that the data source is a dependency and so should be resolved first.

Unfortunately it seems like the hashicorp/vault provider doesn't currently have a data source for declaring a dependency on a policy, although there is a feature request for it.

Assuming that it did exist then the pattern might look something like this:

data "vault_policy" "needed" {
  for_each = var.config.policies

  name = each.value
}

module "policies" {
  source   = "../../../../path/to/my/custom/modules/groups"
  for_each = var.config.policies

  name = each.key

  # Accessing this indirectly via the data resource tells
  # Terraform that it must complete the data lookup before
  # planning anything which depends on this "policy" argument.
  policy = data.vault_policy.needed[each.key].name
}

Without a data source for this particular object type I don't think there will be an elegant way to solve this, but you may be able to work around it by using a more general data source like hashicorp/external's external data source for collecting data by running an external program that prints JSON.

Again because you don't actually seem to need any specific data from the policy and only want to check whether it exists, it would be sufficient to write an external program which queries vault and then exists with an unsuccessful status if the request fails, or prints an empty JSON object {} if the request succeeds.

data "external" "vault_policy" {
  for_each = var.config.policies

  program = ["${path.module}/query-vault"]

  query = {
    policy_name = each.value
  }
}

module "policies" {
  source   = "../../../../path/to/my/custom/modules/groups"
  for_each = var.config.policies

  name   = each.key
  policy = data.external.vault_policy.query.policy_name
}

I'm not familiar enough with Vault to suggest a specific implementation of this query-vault program, but you may be able to use a shell script wrapping the vault CLI program if you follow the advice in Processing JSON in shell scripts. You only need to do the input parsing part of that, because your result would be communicated either by exit 1 to signal failure or echo '{}' followed by exiting successfully to signal success.

Upvotes: 2

Related Questions