2
votes

I'm writing a terraform module that will select a value from a map, based on a key passed to it. Nothing unusual.

The values in that map are secret however, and do not change based on who is calling the module. A simple way I thought to keep those secrets secret would be to define the variable as a map in variables.tf in the module, put the keys/values in terraform.tfvars in the module, .gitignore terraform.tfvars, and encrypt it to terraform.tfvars.gpg or something.

But that doesn't work, because I have no default for the variable in the module terraform is expecting the variable to be set by the caller. I can define the variable in the caller without a value, add it to the call, and either specify manually --var-file or include a terraform.tfvars in the caller. But that means the user having to remember a magic --var-file invocation or the duplication of terraform.tfvars everywhere my new module is used. Remembering magic strings and duplication are both not good options.

Is it possible for a module to use its own tfvars to fill in variables not passed to it?

2

2 Answers

1
votes

There is no way to use an automatic .tfvars file with a non-root module. Child modules always get all of their values from the calling module block (with default values inserted where appropriate); .tfvars is only for assigning values to root module variables.

Another option with similar characteristics to what you're describing is to use a data file in either JSON or YAML format inside the module directory, and load it in using the file function and one of the decoding functions. For example:

locals {
  # This file must be created before using this module by
  # decrypting secrets.yaml.gpg in this directory.
  secrets = yamldecode(file("${path.module}/secrets.yaml"))
}

If the caller neglects to decrypt into the .gitignored file before using the module then the file call will fail with a "file not found" error message.

0
votes

I'm not totally sure I understand but taking a stab. Are you using AWS? A fun solution I've used in the past is SSM parameters.

data "aws_ssm_parameter" "foo" {
  name  = "foo"
}

...
  value = data.aws_ssm_parameter.foo.value
...

The SSM param could be created outside of tf and looked up in your module (and policies granting access depending on caller via IAM, or whatever).