varsvars
Encryption & Security

PINs & Keys

How the two-layer PIN/key model protects your master key.

The PIN/key model

When you run vars init, two things are created:

  1. A master key — 32 bytes of random data. This is what actually encrypts your values.
  2. An encrypted copy of that master key — stored in .varskey (gitignored), locked behind your PIN.

The PIN is never stored anywhere. It goes through Argon2id — a memory-hard, brute-force-resistant KDF — to derive a wrapping key. That wrapping key decrypts the master key, the master key decrypts your values, and then the wrapping key is discarded.

The master key never touches disk in plaintext. Knowing the PIN is the only way to get it.

The PIN is prompted at the terminal every time vars needs to decrypt (vars show, vars hide, vars run). Not cached. Not stored in an env var. Not passed as a flag. You type it, it unlocks, done.

This two-layer design means changing your PIN only re-encrypts the 32-byte master key — not every secret in the file.


The key file

.varskey stores one line per PIN:

pin:v1:aes256gcm:master:<salt>:<iv>:<ct>:<tag>

With multi-pin enabled, owner entries are appended:

pin:v1:aes256gcm:master:<salt>:<iv>:<ct>:<tag>
pin:v1:aes256gcm:owner=backend-team:<salt>:<iv>:<ct>:<tag>
pin:v1:aes256gcm:owner=frontend-team:<salt>:<iv>:<ct>:<tag>

Each line is self-contained. You can delete lines to create scoped key files for sharing — give the backend team a file with only their owner=backend-team line and the PIN. They can decrypt their fields and nothing else.


Key rotation

vars rotate

Generates a new master key, re-encrypts all values, and prompts for a new PIN. If owner PIN entries exist, vars rotate warns that they'll be invalidated and asks for confirmation. After rotation, re-run vars pin create for each owner.