Assign variable using tfe_variable

While experimenting on managing Terraform Cloud using tfe_* providers, I’m having an idea to manage Terraform Cloud workspace variable using terraform, and keep a “meta” workspace to manually add or remove variables. I’m having a difficulty with reusing terraform.tfvars since you can’t access var like:

variable "shared_vars" {
  default = ["aws_access_key", "aws_secret_key"]
}

resource "tfe_variable" "shared" {
  count = "${length(var.shared_vars)}"

  workspace_id = tfe_workspace.shared.id
  category     = "terraform"
  key          = var.shared_vars[count.index]
  
  # this got error "var object cannot be accessed directly"
  #value = "${lookup(var, var.shared_vars[count.index])}"
  
  # this, too, got error "var object cannot be accessed directly"
  #value = var[var.shared_vars[count.index]]

  # this evaluate as plain "var.variablename"
  #value = "${format("var.%s", var.shared_vars[count.index])}"
}

I’ve also tried with defining variables as maps, and using var.map as opposed to var:

variable "aws_access_key" {}
variable "aws_secret_key" {}

variable "map"
  default = {
    # this got error "variables not allowed"
    aws_access_key = var.aws_access_key
    aws_secret_key = var.aws_secret_key
  }
}

# later on tfe_variables
value = "${lookup(var.map, var.shared_vars[count.index])}"

A workaround is to just define the map variable using terraform.tfvars.json. But this feels ugly and weird to me. I know this is backwards way of thinking, but I’d like to know what can I do with terraform and Terraform Cloud. I feel like, tfe_workspace should just accept variables arguments, instead of making each one it’s own resource.

Any thoughts on this?

Hi @bentinata,

variable blocks are for declaring data to be passed in from outside of the module, so the default value of a variable must be a constant.

However, you can use Local Values to create re-usable values within a module, in which case you can use references in their expressions like this:

variable "aws_access_key" {}
variable "aws_secret_key" {}

locals {
  common_variables = {
    aws_access_key = var.aws_access_key
    aws_secret_key = var.aws_secret_key
  }
}

resource "tfe_variable" "shared" {
  for_each = local.common_variables

  workspace_id = tfe_workspace.shared.id
  category     = "terraform"
  key          = each.key
  value        = each.value
  sensitive    = true
}

Please note that we generally recommend representing information about “who” is running Terraform (credentials and other auth-related settings) as environment variables rather than as Terraform variables, because that then keeps them “out of band” of the Terraform configuration and reduces the risk that someone will inadvertently interpolate them into a place that could expose them. So I might suggest the following modification, for that reason:

variable "aws_access_key" {}
variable "aws_secret_key" {}

locals {
  environment_variables = {
    AWS_ACCESS_KEY_ID     = var.aws_access_key
    AWS_SECRET_ACCESS_KEY = var.aws_secret_key
  }
}

resource "tfe_variable" "shared" {
  for_each = local.common_variables

  workspace_id = tfe_workspace.shared.id
  category     = "env"
  key          = each.key
  value        = each.value
  sensitive    = true
}

Although in this case your AWS credential values will be specified as variables on the “meta” workspace (expected, because for that one you want to use them as data in the configuration), all of the other workspaces will see them as environment variables and thus they will be automatically available without the need to explicitly declare variable "aws_access_key", pass that into the provider configuration, etc.