Reliquary Backup & Restoration — Age Key Management
Secrets are sealed with sops-nix and age keys.
The encrypted files (.yaml) are versioned in git — safe to expose without the private key.
What must be absolutely guarded is the master age key of exampleHost.
Secret Files Overview
Section titled “Secret Files Overview”| File | Encrypted by |
|---|---|
secrets/kuri_exampleHost.yaml | exampleHost age key only |
secrets/clochette.yaml | clochette age key + exampleHost age key |
secrets/RogueLeader.yaml | RogueLeader age key + exampleHost age key |
Critical: The private age key of exampleHost unseals all reliquaries across the Forge.
Loss of this key renders kuri_exampleHost.yaml irrecoverable.
Age Keys by Shrine
Section titled “Age Keys by Shrine”exampleHost
Section titled “exampleHost”- Type: Dedicated age key, manually managed
- Location:
/etc/sops/age/keys.txt - Permissions:
0640 root:users(readable byusersgroup) - Public key:
age1xr32hdvanup0zk63v8hrcv2u2c09wplz6fd42w47mkjrd49j39xqaqqckq
This is the only key that must be backed up offline. See procedure below.
clochette
Section titled “clochette”- Type: Age key derived from SSH host ed25519 key
- Source:
/etc/ssh/ssh_host_ed25519_key(auto-generated at install) - Public key:
age18594hnd4mk3736a36a5fqc5w55sanac86tv8du0hz67rfk558srs3y9jwa
The age private key does not exist as a file — sops-nix derives it on-the-fly from the SSH host key.
After reinstall, a new SSH host key is generated → age key changes → update .sops.yaml.
RogueLeader
Section titled “RogueLeader”- Type: Age key derived from SSH host ed25519 key
- Source:
/etc/ssh/ssh_host_ed25519_key(explicit in config) - Public key:
age1nttxr633hf6r43szc9ffl2a0avmtmhtl7hhnjjuyd3sc4au705nqffyfwe
Same behaviour as clochette.
What Is Already Backed Up
Section titled “What Is Already Backed Up”| Element | Where | Status |
|---|---|---|
Encrypted secret files (*.yaml) | git repo | ✅ Auto-versioned |
sops config (.sops.yaml) | git repo | ✅ Auto-versioned |
| exampleHost age private key | /etc/sops/age/keys.txt | ⚠️ Manual backup required |
| clochette/RogueLeader SSH host keys | /etc/ssh/ssh_host_ed25519_key | ⚠️ Regenerated at each reinstall |
Backup Procedure — exampleHost Age Key
Section titled “Backup Procedure — exampleHost Age Key”Display Public Key (Verification)
Section titled “Display Public Key (Verification)”From exampleHost:
age-keygen -y /etc/sops/age/keys.txtExpected output:
age1xr32hdvanup0zk63v8hrcv2u2c09wplz6fd42w47mkjrd49j39xqaqqckqIf this does not match the key in .sops.yaml, investigate immediately.
Display Private Key
Section titled “Display Private Key”sudo cat /etc/sops/age/keys.txtContent looks like:
# created: 2024-01-01T00:00:00+01:00# public key: age1xr32hdvanup0zk63v8hrcv2u2c09wplz6fd42w47mkjrd49j39xqaqqckqAGE-SECRET-KEY-1XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXWhere to Store the Backup
Section titled “Where to Store the Backup”Store the private key in at least two of the following:
- Password manager (Bitwarden/rbw): paste full content in a secure note
- Encrypted USB (LUKS) stored offsite
- Paper in a safe place (safe deposit box, etc.) — plain text sufficient
Never store the backup only on exampleHost itself.
Verification Procedure
Section titled “Verification Procedure”Regularly verify the backup can decrypt secrets.
From exampleHost, with the key in place:
# Decrypt clochette.yaml (displays plaintext — do not share terminal)sops -d secrets/clochette.yaml
# Decrypt kuri_exampleHost.yamlsops -d secrets/kuri_exampleHost.yaml
# Decrypt RogueLeader.yamlsops -d secrets/RogueLeader.yamlThese must execute without error. If sops returns could not decrypt, the key is missing or wrong.
Restoration Procedure — exampleHost Age Key
Section titled “Restoration Procedure — exampleHost Age Key”Situation: exampleHost was reinstalled, /etc/sops/age/keys.txt no longer exists.
1. Create the directory
Section titled “1. Create the directory”sudo mkdir -p /etc/sops/agesudo chmod 750 /etc/sops/age2. Restore the key from backup
Section titled “2. Restore the key from backup”Paste the complete backup content (full private key) into the file:
sudo micro /etc/sops/age/keys.txt# orsudo tee /etc/sops/age/keys.txt << 'EOF'# created: 2024-01-01T00:00:00+01:00# public key: age1xr32hdvanup0zk63v8hrcv2u2c09wplz6fd42w47mkjrd49j39xqaqqckqAGE-SECRET-KEY-1XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXEOF3. Correct permissions
Section titled “3. Correct permissions”sudo chmod 640 /etc/sops/age/keys.txtsudo chown root:users /etc/sops/age/keys.txt4. Verify
Section titled “4. Verify”age-keygen -y /etc/sops/age/keys.txt# Must display: age1xr32hdvanup0zk63v8hrcv2u2c09wplz6fd42w47mkjrd49j39xqaqqckq
sops -d secrets/kuri_exampleHost.yaml# Must display decrypted content without error5. Redeploy NixOS
Section titled “5. Redeploy NixOS”just install_examplehost --ask-sudo-passwordsops-nix re-deposits secrets in /run/secrets and /run/user/1000/secrets.
Post-Reinstall Procedure — clochette or RogueLeader
Section titled “Post-Reinstall Procedure — clochette or RogueLeader”When clochette or RogueLeader is reinstalled, a new SSH host key is generated.
The derived age key changes and no longer matches .sops.yaml.
Update .sops.yaml and re-encrypt the affected secrets.
1. Obtain the New Age Public Key
Section titled “1. Obtain the New Age Public Key”From the reinstalled shrine (via Tailscale or console):
# Convert SSH host key to age public keynix run nixpkgs#ssh-to-age -- -i /etc/ssh/ssh_host_ed25519_key.pubExample output:
age18594hnd4mk3736a36a5fqc5w55sanac86tv8du0hz67rfk558srs3y9jwa2. Update .sops.yaml
Section titled “2. Update .sops.yaml”In the git repo, replace the old public key with the new one.
For clochette, edit .sops.yaml:
keys: - &server_clochette age1NEW_PUBLIC_KEY_HEREFor RogueLeader:
keys: - &server_rogueleader age1NEW_PUBLIC_KEY_HERE3. Re-encrypt Secret Files
Section titled “3. Re-encrypt Secret Files”From exampleHost (which can still decrypt via its master key):
# For clochettesops updatekeys secrets/clochette.yaml
# For RogueLeadersops updatekeys secrets/RogueLeader.yamlupdatekeys re-encrypts with the keys now defined in .sops.yaml.
Confirm with y when sops asks.
4. Verify and Commit
Section titled “4. Verify and Commit”# Verify files are updatedgit diff secrets/
# Commitgit add .sops.yaml secrets/clochette.yaml # or secrets/RogueLeader.yamlgit commit -m "chore(secrets): rotate age key for clochette after reinstall"5. Deploy
Section titled “5. Deploy”just install_clochette --ask-sudo-passwordCatastrophe Scenario — Lost Master Key Without Backup
Section titled “Catastrophe Scenario — Lost Master Key Without Backup”If the exampleHost private age key is lost and no backup exists:
| File | Situation |
|---|---|
kuri_exampleHost.yaml | Irrecoverable — encrypted only with lost key |
clochette.yaml | Recoverable from clochette (via its SSH host key) |
RogueLeader.yaml | Recoverable from RogueLeader (via its SSH host key) |
For kuri_exampleHost.yaml: start from scratch
# Generate a new age keyage-keygen -o /etc/sops/age/keys.txt
# Display the new public keyage-keygen -y /etc/sops/age/keys.txt
# Update .sops.yaml with the new public key# Replace desktop_examplehost
# Recreate kuri_exampleHost.yaml from scratchsops secrets/kuri_exampleHost.yaml# Manually enter all secrets (passwords, etc.)
# Re-encrypt clochette.yaml and RogueLeader.yaml with new keysops updatekeys secrets/clochette.yamlsops updatekeys secrets/RogueLeader.yaml
# Commitgit add .sops.yaml secrets/git commit -m "chore(secrets): rotate all age keys after exampleHost key loss"