terraform icon indicating copy to clipboard operation
terraform copied to clipboard

Variable Flag: use_existing_value

Open bondsb opened this issue 4 years ago • 5 comments

Current Terraform Version

terraform v0.14.10

Use-cases

Terraform prompts for any variable whose value has not been supplied. But when it was supplied in a previous run, sometimes I prefer to use the value that was originally provided.

An example is a database password. When I first create the database, I expect Terraform to prompt for the password. But for subsequent runs, I do not want to be prompted.

Proposal

I would like to indicate that the variable should not create a prompt after the first run, but instead use the original value. This could be a flag on the variable definition:

variable "password" {
  type               = string
  use_existing_value = true
}

For the first apply, the value is unknown and Terraform prompts for var.password. For subsequent applies, the existing value is used and a prompt is not displayed.

Consideration

Providing the value through another mechanism, such as tfvars or an environment variable, would override this flag. As a result, the variable value is changed.

If changing the value through those mechanisms is undesirable, the flag can be combined with ignore_changes on the target resource.

bondsb avatar Apr 23 '21 17:04 bondsb

Hi @bondsb! Thanks for this feature request.

Terraform does not currently "remember" your variable values from one run to the next, because root module variables are per-operation settings. So I think this use-case is also, as a side-effect, calling for some mechanism to automatically save variables for later use, and thus we'll need to consider those together.

The typical answer for "sticky" (that is, not-per-run) variables today is to create a .tfvars file to write them in. If you name it with a suffix .auto.tfvars and put it in the same directory as your root module then Terraform will read it automatically without the need to set any extra arguments. For that reason, writing your password into a .tfvars file would get effectively the result you are looking for here, though of course you'd need to be careful not to send that .tfvars file anywhere that the password shouldn't be visible. (That would also be true of a hypothetical variables file that Terraform might create automatically itself as part of meeting your use-case, of course.)

apparentlymart avatar Apr 23 '21 21:04 apparentlymart

Thanks @apparentlymart!

I actually started this request as a more specific case, which might be more feasible if saving variable values is undesirable.

In that case, the flag wasn't used. Terraform would not prompt for any variables whose values were either:

  1. known (current behavior), or
  2. ignored via ignore_changes everywhere it is referenced (new behavior)

If this seems like a more viable option, I can update the ticket.

bondsb avatar Apr 23 '21 21:04 bondsb

Another extension could be to not prompt when the variable's value is unused, either because it is unreferenced or because no resources will be created which reference it (e.g. count = 0).

bondsb avatar Apr 23 '21 21:04 bondsb

The random provider does something like this.

As noted above, the random resources generate randomness only when they are created; the results produced are stored in the Terraform state and re-used until the inputs change, prompting the resource to be recreated.

https://registry.terraform.io/providers/hashicorp/random/latest/docs

You could use this to cache the value if you had a second variable to trigger refreshes:

resource "random_integer" "cached_index" {
  min = var.cached_index
  max = var.cached_index

  keepers = {  
    trigger = var.trigger
  } 

  lifecycle {
      ignore_changes = [
        min,
        max
      ]
   }
}

akvadrako avatar Feb 27 '25 12:02 akvadrako

I wrote my previous comment while on the Terraform team but I am no longer employed by HashiCorp so the following is me speaking only for myself.


FWIW, I think today's v1.11.0 release offers a plausible way for a utility provider to offer a sort of "memory" that can be updated when needed but retains its value when not being updated, using write-only arguments.

I'm imagining a provider that offers a resource type called memory, which has a write-only attribute which changes the stored value whenever it isn't null but just retains the previous value when it is null, to be used something like this:

variable "new_value" {
  type    = string
  default = null
}

resource "memory" "example" {
  new_value = var.new_value
}

output "stored_value" {
  value = memory.example.stored_value
}

When asked to plan creation, memory would treat new_value as a required argument and so return an error if it is null, since it needs to establish an initial value to use. It would propose to create memory.example with its stored_value attribute set to whatever new_value was set to.

When asked to plan an update, memory would check whether new_value is null in the config or not:

  • If it's null, propose no changes whatsoever. The stored_value attribute remains unchanged.
  • If it's non-null, propose to change stored_value to the given new_value.

This would mean that you could then use terraform apply -var=new_value=whatever to write to this "memory", but a normal terraform apply with no special arguments would retain the previously-stored value.

The memory resource instance is therefore acting as a memory cell stored in the Terraform state, without the need for any external storage. Of course, it would not be appropriate to store sensitive values in this way unless you are comfortable with them being persisted in cleartext in your Terraform state, but the original request here implied that the requester was comfortable with that; it's your own risk tradeoff to make[^1].

If I've understood the Plugin Framework documentation about write-only attributes correctly I think it should be technically possible for anyone to develop and publish such a provider. The above is just a novel application of the new features in Terraform v1.11.

[^1]: In case any readers are not aware, it seems that the main intended purpose of this "write-only attributes" feature is to allow you to persist secrets into remote secret stores without also storing them in the Terraform state, and so if you want to persist a sensitive value to some other location without storing it in the Terraform state then the better answer would be to use a resource type that uses write-only attributes to update data in a remote system.

For example, you can use [`aws_secretsmanager_secret_version`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret_version) with its `secret_string_wo` attribute to use _AWS Secrets Manager_ as the backing store, instead of the Terraform state.

apparentlymart avatar Feb 27 '25 16:02 apparentlymart