SOPS & Age
None of the keys shown here are actually used for anything other than this example.
Keeping Infrastructure as Code (IaC) files usually means also storing secrets to be used in these files. These secrets can’t just be stored in a git repo unencrypted like regular IaC files, that would be silly. So, how can we do it?
With SOPS and Age.
After using these two tools for the last couple of months, I have become quite comfortable with using them to script deployments requiring tokens, api keys, and other sercets.
SOPS
First, a quick briefing on these tools. Secrets OPerationS is a tool designed to encrypt structured files. It’s source code is public and can be found here.
It supports YAML, JSON, ENV, and other formats and encrypts with age, PGP, and various other cloud vaults.
Age
Age is a very simple encryption tool developed by FiloSottile and it’s source code is available here. It uses public and private keys, and is able to encrypt values for multiple recipients.
Usage
Now, let’s look at using this combination.
To create public and private keys using age, we can use age-keygen -o key:
age-keygen -o keyfile
Public key: age1vkdu7fkcn7afjh6r0xtqf2g6geg7hg0ltd2rypshq568q2g7t9tq03wjtt
cat key
# created: 2026-07-24T01:10:09-04:00
# public key: age1vkdu7fkcn7afjh6r0xtqf2g6geg7hg0ltd2rypshq568q2g7t9tq03wjtt
AGE-SECRET-KEY-1J358HZDA02KHZKSFKHQK56NCKLG77UJ24SC25QWC33URYCZA3A0S88VRPE
Now, since we don’t want to save this key in our repo we’ll take the public key and add it to a new file that will be saved in our repo.
echo "age1vkdu7fkcn7afjh6r0xtqf2g6geg7hg0ltd2rypshq568q2g7t9tq03wjtt" > public-keys.txt
Now, we’re using this to keep secrets safe, right? So let’s creae some secrets. Since I like using jq for scripting, I’ll use JSON for structuring my secrets.
cat secrets.json
{
"super_secret_key": "abc123"
}
To encrypt or decrypt files, we can do something like this:
sops --encrypt --input-type json --output-type json --age [insert public keys] secrets.json > secrets.json.enc
and
SOPS_AGE_KEY_FILE=keyfile sops --decrypt --input-type json --output-type json secrets.json.enc
{
"super_secret_key": "abc123"
}
Note, there are different types of variables to use for providing the key:
- SOPS/Age can be used with SSH keys
- ‘SOPS_AGE_SSH_PRIVATE_KEY_FILE’
- ‘SOPS_AGE_SSH_PRIVATE_KEY_CMD’
- ‘/home/dev/.ssh/id_rsa’
- Provides the key directly
- ‘SOPS_AGE_KEY’
- Provides the key file location
- ‘SOPS_AGE_KEY_FILE’
- Provides the key via a command
- ‘SOPS_AGE_KEY_CMD’