Skip to main content
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

1

Generate an SSH key (if needed)

If you don’t already have an SSH key:
ssh-keygen -t ed25519 -C "[email protected]"
2

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
3

Add your key to .sops.yaml

Edit .sops.yaml and add your age key:
.sops.yaml
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.
1

Add user to .sops.yaml

Define your user’s age key in the keys section:
.sops.yaml
keys:
  - &alice age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p

creation_rules:
  - path_regex: secrets/alice\.yaml
    key_groups:
      - age:
          - *alice
2

Create the secrets file

Create and edit your user secrets file:
sops secrets/alice.yaml
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.
3

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.
1

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
2

Add host key to .sops.yaml

Add the host’s key and create rules for service secrets:
.sops.yaml
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
3

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
4

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:
.sops.yaml
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

1

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
2

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

# 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

This means your age key isn’t authorized to decrypt the secret.Solution:
  1. Verify your age key is in .sops.yaml
  2. Run sops updatekeys on the secret file
  3. Ensure your age keyfile exists at ~/.config/sops/age/keys.txt
Check that:
  1. The secret is defined in sops.secrets
  2. The path in sopsFile is correct
  3. The secret exists in the YAML file
  4. The sops-nix module is imported
Secrets have strict permissions. Make sure:
  1. The owner matches the user/service accessing it
  2. The mode allows read access (e.g., "0400" or "0440")
  3. 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

Build docs developers (and LLMs) love