SOPS (Secrets OPerationS) Management
This documentation covers the SOPS (Secrets OPerationS) integration used in this NixOS/Darwin configuration for secure secrets management.
Overview
SOPS is a tool for managing secrets (passwords, keys, certificates, etc.) in a secure, encrypted format. This configuration uses SOPS with age encryption to manage sensitive data across all systems.
Key Features
- Age Encryption: Uses modern age encryption for security
- Cross-Platform: Works on both NixOS and Darwin systems
- Git-Safe: Encrypted secrets can be safely committed to version control
- Flexible: Supports multiple encryption keys and formats
Architecture
Encryption Keys
The system uses age keys for encryption with platform-specific locations:
Darwin (macOS):
- Location:
/Users/roelc/.config/sops/age/keys.txt
- Format: Standard age private key format
- Generation: Automatically generated when missing
Linux (NixOS):
- Location:
/home/roelc/.config/sops/age/keys.txt
- Format: Standard age private key format
- Generation: Automatically generated when missing
SSH Keys (Linux Only)
On NixOS systems, SSH host keys provide additional security:
- Location:
/etc/ssh/ssh_host_ed25519_key
(or persistence path if enabled) - Persistence Path:
${config.dc-tec.persistence.dataPrefix}/etc/ssh/ssh_host_ed25519_key
- Purpose: Additional encryption layer for system-level secrets
- Condition: Only used when
config.dc-tec.isLinux
is true
Secrets Configuration
Default Settings
sops = {
defaultSopsFile = ../../../secrets/secrets.yaml;
defaultSopsFormat = "yaml";
age = {
keyFile =
if config.dc-tec.isDarwin then
"/Users/${config.dc-tec.user.name}/.config/sops/age/keys.txt"
else
"/home/${config.dc-tec.user.name}/.config/sops/age/keys.txt";
sshKeyPaths = lib.optionals config.dc-tec.isLinux [
(if config.dc-tec.persistence.enable then
"${config.dc-tec.persistence.dataPrefix}/etc/ssh/ssh_host_ed25519_key"
else
"/etc/ssh/ssh_host_ed25519_key")
];
generateKey = true;
};
};
Managed Secrets
User Management Secrets
users/roelc
: User password hash (Linux only,neededForUsers = true
)users/root
: Root password hash (Linux only,neededForUsers = true
)
SSH Access Secrets
authorized_keys/roelc
: SSH public keys deployed to/home/roelc/.ssh/authorized_keys
(Linux) or/Users/roelc/.ssh/authorized_keys
(Darwin)authorized_keys/root
: SSH public keys deployed to/root/.ssh/authorized_keys
(Linux only)
GPG Key Management
gpg/private_key
: GPG private key deployed to~/.gnupg/private-key.asc
(mode 0600)gpg/public_key
: GPG public key deployed to~/.gnupg/public-key.asc
(mode 0644)gpg/trust_db
: GPG trust database deployed to~/.gnupg/trust-db.txt
(mode 0600)
Network Secrets
wireless
: Wireless network credentials (Linux only)
Platform-Specific Configuration
NixOS (Linux):
- User password hashes for system login
- Wireless network credentials
- Root SSH access keys
- Full GPG key management
Darwin (macOS):
- User SSH keys only
- GPG key management
- No wireless or user password management
Initial Setup
1. Generate Age Keys
Age keys are automatically generated by the NixOS/Darwin configuration when missing. The system will create them at the appropriate location based on your platform.
For manual generation (if needed):
# Darwin (macOS)
mkdir -p /Users/roelc/.config/sops/age
age-keygen -o /Users/roelc/.config/sops/age/keys.txt
# Linux (NixOS)
mkdir -p /home/roelc/.config/sops/age
age-keygen -o /home/roelc/.config/sops/age/keys.txt
2. Get Public Key
Extract your public key for adding to the repository's .sops.yaml
:
# Darwin
age-keygen -y /Users/roelc/.config/sops/age/keys.txt
# Linux
age-keygen -y /home/roelc/.config/sops/age/keys.txt
3. Add to Repository Configuration
Add your public key to the .sops.yaml
file in the repository root:
keys:
- &roelc_key age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
creation_rules:
- path_regex: secrets/secrets.yaml$
key_groups:
- age:
- *roelc_key
The secrets are stored in secrets/secrets.yaml
and automatically referenced by the configuration.
Managing Secrets
Adding New Secrets
Edit the secrets file:
sops secrets/secrets.yaml
Add your secret following the existing structure:
# Add to existing categories or create new ones new_category: secret_name: "secret_value"
Configure in the sops.nix module (if not already handled):
sops.secrets."new_category/secret_name" = { path = "/path/to/secret/file"; owner = config.dc-tec.user.name; mode = "0600"; };
Updating Existing Secrets
# Edit existing secrets
sops secrets/secrets.yaml
# Re-encrypt for new keys (when adding new machines)
sops updatekeys secrets/secrets.yaml
Viewing Secrets
# View all decrypted secrets (local only)
sops -d secrets/secrets.yaml
# View specific secret categories
sops -d --extract '["users"]' secrets/secrets.yaml
sops -d --extract '["authorized_keys"]' secrets/secrets.yaml
sops -d --extract '["gpg"]' secrets/secrets.yaml
Common Workflows
Updating User Passwords
Generate password hash:
mkpasswd -m sha-512 "new_password"
Update in secrets:
sops secrets/secrets.yaml
users: roelc: "$6$new_hashed_password..." root: "$6$new_hashed_password..."
Apply changes:
# NixOS sudo nixos-rebuild switch --flake .#hostname
Managing SSH Access
Update SSH public keys in secrets:
sops secrets/secrets.yaml
authorized_keys: roelc: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5... roelc@newhost" root: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5... roelc@newhost"
Keys are automatically deployed to:
/home/roelc/.ssh/authorized_keys
(Linux/Darwin)/Users/roelc/.ssh/authorized_keys
(Darwin)/root/.ssh/authorized_keys
(Linux only)
Updating Wireless Credentials
Update wireless password (NixOS only):
sops secrets/secrets.yaml
wireless: "new_wifi_password"
Apply changes:
sudo nixos-rebuild switch --flake .#hostname
Managing GPG Keys
Export your current GPG keys:
# Export private key gpg --export-secret-keys --armor YOUR_KEY_ID > private-key.asc # Export public key gpg --export --armor YOUR_KEY_ID > public-key.asc # Export trust database gpg --export-ownertrust > trust-db.txt
Add to secrets:
sops secrets/secrets.yaml
gpg: private_key: | -----BEGIN PGP PRIVATE KEY BLOCK----- [paste private key content] -----END PGP PRIVATE KEY BLOCK----- public_key: | -----BEGIN PGP PUBLIC KEY BLOCK----- [paste public key content] -----END PGP PUBLIC KEY BLOCK----- trust_db: | [paste trust database content]
Keys are automatically deployed to:
~/.gnupg/private-key.asc
(mode 0600)~/.gnupg/public-key.asc
(mode 0644)~/.gnupg/trust-db.txt
(mode 0600)
Troubleshooting
Common Issues
Cannot Decrypt Secrets
Problem: sops: error: cannot decrypt
Solutions:
- Verify age key exists:
ls -la ~/.config/sops/age/keys.txt
- Check public key is in
.sops.yaml
- Re-encrypt secrets:
sops updatekeys secrets/secrets.yaml
Permission Denied
Problem: Secrets file has wrong permissions
Solutions:
- Check file ownership in secret configuration
- Verify user exists before secret deployment
- Use
neededForUsers = true
for user password secrets
Keys Not Found
Problem: Age keys missing after system rebuild
Solutions:
- Restore from backup
- Regenerate and re-encrypt all secrets
- Check key file path configuration
Debugging Commands
# Check SOPS configuration
sops -d secrets/secrets.yaml
# Verify age key (platform-specific)
# Darwin
age-keygen -y /Users/roelc/.config/sops/age/keys.txt
# Linux
age-keygen -y /home/roelc/.config/sops/age/keys.txt
# Check deployed secrets
ls -la /run/secrets/
ls -la /run/secrets/users/
ls -la /run/secrets/authorized_keys/
ls -la /run/secrets/gpg/
# Test specific secret decryption
sudo cat /run/secrets/users/roelc
sudo cat /run/secrets/wireless
sudo cat /run/secrets/gpg/private_key
# Check SSH authorized keys deployment
ls -la /home/roelc/.ssh/authorized_keys # Linux
ls -la /Users/roelc/.ssh/authorized_keys # Darwin
ls -la /root/.ssh/authorized_keys # Linux only
# Check GPG key deployment
ls -la ~/.gnupg/private-key.asc
ls -la ~/.gnupg/public-key.asc
ls -la ~/.gnupg/trust-db.txt
# Verify GPG key import
gpg --list-keys
gpg --list-secret-keys
Security Best Practices
Key Management
- Backup age keys securely
- Use separate keys for different environments
- Rotate keys periodically
- Never commit private keys to version control
Secret Organization
- Use descriptive secret names
- Group related secrets logically
- Document secret purposes
- Implement least-privilege access
Operational Security
- Audit secret access regularly
- Monitor for unauthorized changes
- Use temporary secrets when possible
- Implement secret rotation policies
Integration with NixOS/Darwin
Automatic Deployment
Secrets are automatically deployed during system builds to /run/secrets/
:
# NixOS systems (chad, legion, ghost)
sudo nixos-rebuild switch --flake .#hostname
# Darwin systems (macOS)
darwin-rebuild switch --flake .#hostname
Service Integration
Services can reference secrets through the /run/secrets/
path:
# Example: Using wireless secret in networking configuration
networking.wireless = {
enable = true;
networks."YourNetworkName".pskFile = config.sops.secrets.wireless.path;
};
User Environment
GPG keys are automatically imported into the user's GPG keyring during system activation.
Advanced Topics
Adding New Machines
When adding a new machine to the configuration:
Generate age key on new machine:
# Keys are auto-generated, or manually: age-keygen -o ~/.config/sops/age/keys.txt age-keygen -y ~/.config/sops/age/keys.txt # Get public key
Add to
.sops.yaml
:keys: - &roelc_key age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - &new_machine_key age1yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy creation_rules: - path_regex: secrets/secrets.yaml$ key_groups: - age: - *roelc_key - *new_machine_key
Re-encrypt secrets:
sops updatekeys secrets/secrets.yaml
Machine-Specific Secrets
For secrets that only apply to specific machines, you can extend the configuration:
# In machine-specific configuration
sops.secrets = lib.mkMerge [
# Standard secrets from shared/utils/sops.nix
# Machine-specific secrets
(lib.mkIf (config.networking.hostName == "specific-machine") {
"machine-specific/secret" = {
path = "/etc/machine-specific-secret";
mode = "0600";
};
})
];
Secret Backup Strategy
- Backup age keys - Store securely offline
- Version control - All encrypted secrets are in git
- Key rotation - Periodically generate new age keys
- Documentation - Keep track of what secrets exist and their purpose