An open API service indexing awesome lists of open source software.

https://github.com/josh/tofu-age-encryption

Encrypt OpenTofu state data with age encryption keys
https://github.com/josh/tofu-age-encryption

age-encryption opentofu

Last synced: 6 months ago
JSON representation

Encrypt OpenTofu state data with age encryption keys

Awesome Lists containing this project

README

          

# tofu-age-encryption

tofu-age-encryption provides an external encryption method for [OpenTofu](https://opentofu.org/) using [age](https://age-encryption.org/).

OpenTofu encrypts state with a symmetric key derived from a shared passphrase that every operator must share and rotate together. This project replaces that workflow with age's asymmetric key pairs so operators can keep private keys, specify their own recipients, and rotate access without redistributing a secret.

## Usage

1. Provide the age recipient and identity file using either environment variables or CLI flags:

Environment variables:
- `AGE_IDENTITY_FILE` (alias: `AGE_KEY_FILE`): path to your age identity file
- `AGE_IDENTITY` (alias: `AGE_KEY`): age identity string; supports `file:PATH`, `cmd:COMMAND`, and `command:COMMAND`
- `AGE_IDENTITY_COMMAND` (alias: `AGE_IDENTITY_CMD`): command whose output is the age identity
- `AGE_RECIPIENT` or `AGE_RECIPIENTS`: comma-separated list of age recipients
- `AGE_RECIPIENTS_FILE`: path to a file with newline-separated age recipients

The following `SOPS_`-prefixed variables are also supported as aliases for compatibility with tools that expect them:
- `SOPS_AGE_KEY_FILE`: alias for `AGE_IDENTITY_FILE`
- `SOPS_AGE_KEY`: age identity string
- `SOPS_AGE_KEY_CMD`: alias for `AGE_IDENTITY_COMMAND`
- `SOPS_AGE_RECIPIENTS`: alias for `AGE_RECIPIENT`/`AGE_RECIPIENTS` (values from both variables are merged; duplicates are ignored)

CLI flags:

- `--identity-file`: path to your age identity file
- `--identity`: age identity string or `file:PATH`, `cmd:COMMAND`, `command:COMMAND`
- `--identity-command`: command whose output is the age identity
- `--recipient`: may be provided multiple times or as a comma-separated list of recipients
- `--recipients-file`: path to a file with newline-separated age recipients

2. Configure OpenTofu to use the external method. For multiple recipients, build the command dynamically:

```hcl
terraform {
encryption {
method "external" "age" {
encrypt_command = concat(
["tofu-age-encryption", "--encrypt"],
flatten([for recipient in local.age_recipients : ["--recipient", recipient]])
)
decrypt_command = ["tofu-age-encryption", "--decrypt", "--identity", nonsensitive(var.age_identity)]
}

state {
method = method.external.age
enforced = true
}

plan {
method = method.external.age
enforced = true
}
}
}

locals {
age_recipients = [
"KEY_A",
"KEY_B",
"KEY_C",
]
}

variable "age_identity" {
type = string
sensitive = true
}

resource "random_pet" "example" {}

output "pet" {
value = random_pet.example.id
}
```

3. Run OpenTofu as usual. The state and plan files are encrypted with the given age recipients:

```sh
$ tofu init
$ tofu apply
```

## Manual state recovery

If the `tofu-age-encryption` binary is unavailable, you can decrypt an existing state file using common command-line tools:

```sh
jq --raw-output '.encrypted_data' terraform.tfstate | base64 --decode >state.age
age --decrypt --identity key.txt state.age >state.json
jq . state.json
```

This process does not require `tofu-age-encryption` and can be used to recover the plain text state for backup or debugging.