This repository uses sops-nix to manage secrets that aren’t files, such as SSH keys, API keys, passwords, and other plaintext secrets. All secrets are encrypted with age keys and stored in the repository.
The secrets in this repository are encrypted with specific age keys. You must set up your own keys and re-encrypt all secrets for them to work in your configuration.
How sops-nix works
Secrets are encrypted using age keys derived from:
User SSH keys (for user-level secrets)
Host SSH keys (for system-level secrets)
The .sops.yaml file defines which keys can decrypt which secrets.
Setting up your age key
Generate an SSH key (if needed)
If you don’t already have an SSH key:
Convert SSH key to age key
Convert your SSH public key to an age public key: ssh-to-age < ~/.ssh/id_ed25519.pub
This outputs something like: age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p
Add your key to .sops.yaml
Edit .sops.yaml and add your age key: keys :
- & yourname age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p
creation_rules :
- path_regex : secrets/yourname\.yaml
key_groups :
- age :
- * yourname
User secrets
User-level secrets are stored per-user and can only be decrypted by that user’s age key.
Add user to .sops.yaml
Define your user’s age key in the keys section: keys :
- & alice age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p
creation_rules :
- path_regex : secrets/alice\.yaml
key_groups :
- age :
- * alice
Create the secrets file
Create and edit your user secrets file: Add your secrets in YAML format: # API keys
github_token : ghp_...
openai_api_key : sk-...
# SSH keys
git_ssh_key : |
-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----
# Passwords
postgres_password : secretpassword123
Save and exit. The file will be encrypted automatically.
Use secrets in your configuration
Reference secrets in your home-manager or NixOS configuration: home/alice/system/secrets.nix
{
config ,
...
}:
{
sops = {
age . keyFile = " ${ config . home . homeDirectory } /.config/sops/age/keys.txt" ;
secrets = {
github_token = {
sopsFile = ../../../secrets/alice.yaml ;
};
git_ssh_key = {
sopsFile = ../../../secrets/alice.yaml ;
path = " ${ config . home . homeDirectory } /.ssh/git_key" ;
};
};
};
# Use the secret
programs . git . extraConfig = {
github . oauth-token-command = "cat ${ config . sops . secrets . github_token . path } " ;
};
}
System secrets
System-level secrets are accessible to services and can be decrypted by multiple hosts.
Get host SSH key
Get the host’s age public key: On the target machine: ssh-to-age < /etc/ssh/ssh_host_ed25519_key.pub
Or remotely: ssh-keyscan hostname | ssh-to-age
Add host key to .sops.yaml
Add the host’s key and create rules for service secrets: keys :
- & alice age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p
- & server age1r3v2mx6mhd7ddlw0px0mzmwl6v4xvg2xxy2dzqg44f2fv7gm7cvqv0lmgv
creation_rules :
- path_regex : secrets/services/[^/]+\.(yaml|json|env|ini)$
key_groups :
- age :
- * alice # You can still decrypt
- * server # Host can decrypt
Create service secrets
Create secrets for a specific service: sops secrets/services/postgresql.yaml
Add the service secrets: database_password : supersecretpassword
admin_password : anothersecret
replication_password : replicationsecret
Use in NixOS configuration
Reference system secrets in your NixOS modules: modules/nixos/services/postgresql.nix
{
config ,
lib ,
...
}:
{
sops . secrets . postgres_password = {
sopsFile = ../../../secrets/services/postgresql.yaml ;
owner = "postgres" ;
group = "postgres" ;
mode = "0440" ;
};
services . postgresql = {
enable = true ;
authentication = lib . mkForce '''
local all all peer
host all all 127.0.0.1/32 scram-sha-256
''' ;
initialScript = pkgs.writeText "init.sql" '''
ALTER USER postgres PASSWORD '$(< ${ config . sops . secrets . postgres_password . path } )';
''' ;
};
}
Example .sops.yaml structure
From the repository:
keys :
- & isabel age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p
- & minerva age1r3v2mx6mhd7ddlw0px0mzmwl6v4xvg2xxy2dzqg44f2fv7gm7cvqv0lmgv
- & skadi age1yj9dxjdurmwcy2lq98phdwvg7mhjq5gvk8l427xqz7w3m2qm4l6qcq4y8t
- & athena age1xv8xx9j9m2y0ddjjdvlr2rp2k3l5g3m6zmf0w7qr9s3k9h6w9cqsy9l2x4
creation_rules :
# User secrets - only accessible to the specific user
- path_regex : secrets/isabel\.yaml
key_groups :
- age :
- * isabel
# Service secrets - accessible to user and all servers
- path_regex : secrets/services/[^/]+\.(yaml|json|env|ini)$
key_groups :
- age :
- * isabel
- * minerva
- * skadi
- * athena
Managing secrets
Editing secrets
Edit an encrypted file:
sops secrets/yourname.yaml
SOPS will decrypt, open in your editor, and re-encrypt on save.
Rotating secrets
Rotate a single secret file:
sops rotate -i secrets/yourname.yaml
Rotate all secrets:
find secrets/ -name "*.yaml" | xargs -I {} sops rotate -i {}
Adding new owners to existing secrets
Update .sops.yaml
Add the new recipient’s age key to .sops.yaml: keys :
- & newuser age1abc123...
creation_rules :
- path_regex : secrets/services/.*
key_groups :
- age :
- * isabel
- * newuser # Add here
Update secret keys
Update a specific file: sops updatekeys secrets/services/database.yaml
Update all secrets: find secrets/ -name "*.yaml" | xargs -I {} sops updatekeys -y {}
Common secret patterns
API keys
Service credentials
Database secrets
# secrets/yourname.yaml
github_token : ghp_abc123...
openai_key : sk-proj-xyz...
aws_access_key : AKIAIOSFODNN7EXAMPLE
aws_secret_key : wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Secret deployment workflow
Troubleshooting
Error: no key could decrypt the data
This means your age key isn’t authorized to decrypt the secret. Solution:
Verify your age key is in .sops.yaml
Run sops updatekeys on the secret file
Ensure your age keyfile exists at ~/.config/sops/age/keys.txt
Secrets not available at runtime
Check that:
The secret is defined in sops.secrets
The path in sopsFile is correct
The secret exists in the YAML file
The sops-nix module is imported
Permission denied when accessing secret
Secrets have strict permissions. Make sure:
The owner matches the user/service accessing it
The mode allows read access (e.g., "0400" or "0440")
The process runs as the correct user
Next steps
Adding users Set up users with encrypted secrets
Adding systems Configure systems with service secrets
Troubleshooting Fix secrets-related issues
sops-nix docs Read the full sops-nix documentation