The key on the front page
Keeping secrets out of code means a password, key or token is never written into the files of a project. It matters because anybody who can read the files can use the key. It also stays in the history after the file is changed.
A student pushes a project to a public repository. One file holds an access key, because it made the first test work. Programs that read public repositories all day find it within minutes.
By the end of this lesson
Note
I can keep a secret out of OpenTofu files and say where it still ends up.
Key words
| Word | What it means | Example |
|---|---|---|
| Secret | a value nobody else should see, such as a key | |
| Sensitive | marked so the tool hides it on screen | |
| Environment variable | a value the shell hands to a command | TF_VAR_token |
| State | the file where OpenTofu records what it made | |
| Ignore file | a list of files that version control skips | .gitignore |
The cells students fill in are left blank in this preview.
A secret stays out of committed files
A value written in a .tf file is saved with the project, copied to every clone and kept in the history. So a secret is given to OpenTofu from outside.
The usual way is an environment variable. A variable called token is set by TF_VAR_token. Marking the variable sensitive then hides it on screen.
Make a folder and go in
mkdir -p ~/iac-demo/vault && cd ~/iac-demo/vaultShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Write a project that takes a secret
printf '%s\n' 'variable "token" {' ' type = string' ' sensitive = true' '}' '' 'resource "terraform_data" "login" {' ' input = var.token' '}' '' 'output "shown" {' ' value = terraform_data.login.output' ' sensitive = true' '}' > main.tfShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Prepare the folder
tofu init -no-color | grep successfullyShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Plan with the secret in the environment
TF_VAR_token=moon42 tofu plan -no-color | grep -E "input|^Plan"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Apply it
TF_VAR_token=moon42 tofu apply -auto-approve -no-color | grep -E "Apply complete|shown"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
List the outputs
tofu outputShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Sensitive hides a value only
sensitive only changes what is printed. The state still records every value in plain text, because OpenTofu needs it to compare next time.
So the state file is as secret as the secret. Keep it out of version control, and in real work keep it in a store that is encrypted and has limited access.
Count the places the state holds the value
grep -c moon42 terraform.tfstateShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Ask for the raw output
tofu output -raw shown; echoShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
A common mistake
Warning
Many people think sensitive encrypts a value. It does not. It hides the value in the plan and the output, and anybody who can read the state or run tofu output -raw still sees it. Protect the state as well.
An ignore file keeps the state out
A .gitignore lists files that version control never adds. Four lines cover an OpenTofu project: the state, its backup, any .tfvars file and the .terraform folder.
Leaving one out is how a state with a secret in it gets pushed.
Write an ignore file
printf '%s\n' 'terraform.tfstate' 'terraform.tfstate.backup' '*.tfvars' '.terraform/' > .gitignoreShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Plant a secret and scan for it
printf '%s\n' 'locals {' ' api_token = "moon42"' '}' > leak.tf; grep -nE '(token|secret|password|key)[a-z_]* *= *"' *.tf; rm leak.tfShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
A scan for secrets, worked out in Python
# Find lines that give a secret a value in the file itself.
lines = [
'region = "eu-west-2"',
'api_token = "moon42"',
'api_token = var.api_token',
]
words = ["token", "secret", "password", "key"]
for number, line in enumerate(lines, 1):
name = line.split("=")[0].strip().lower()
value = line.split("=")[1].strip()
if any(word in name for word in words) and value.startswith('"'):
print("line", number, "gives", name, "a value")
# Change the third line to a quoted value and look again.
Going further: a variable file
Write the line token = "sun77" in a file called secret.tfvars. Run tofu plan -no-color -var-file=secret.tfvars | grep -E "input|^Plan", then delete the file.
Why is *.tfvars in the ignore file, and does the plan show the new value?