Compare commits
No commits in common. "fc1d31244ab19f05bdef85dbfb34c17c993ff0fe" and "8ebf16d06968de49829629fb91fda192bcffee63" have entirely different histories.
fc1d31244a
...
8ebf16d069
9 changed files with 1 additions and 465 deletions
8
.gitignore
vendored
8
.gitignore
vendored
|
|
@ -13,11 +13,3 @@ result-*
|
||||||
.#*
|
.#*
|
||||||
*.swp
|
*.swp
|
||||||
*.swo
|
*.swo
|
||||||
|
|
||||||
# Secrets — track only sops-encrypted .yaml files + the README;
|
|
||||||
# block plaintext keys and any other content under secrets/
|
|
||||||
*.key
|
|
||||||
*.pem
|
|
||||||
secrets/*
|
|
||||||
!secrets/*.yaml
|
|
||||||
!secrets/README.md
|
|
||||||
|
|
|
||||||
21
.sops.yaml
21
.sops.yaml
|
|
@ -1,21 +0,0 @@
|
||||||
# sops recipient declarations.
|
|
||||||
#
|
|
||||||
# Replace the placeholder below with YOUR age public key before
|
|
||||||
# encrypting any files. One-time setup on this machine:
|
|
||||||
# pragma: allowlist secret
|
|
||||||
# age-keygen -o ~/.config/sops/age/keys.txt # creates the private key
|
|
||||||
# age-keygen -y ~/.config/sops/age/keys.txt # prints the public key
|
|
||||||
#
|
|
||||||
# Paste the printed `age1...` string in place of the placeholder.
|
|
||||||
# See docs/secrets-management.md for the full walkthrough.
|
|
||||||
|
|
||||||
keys:
|
|
||||||
# pragma: allowlist secret
|
|
||||||
# PLACEHOLDER — overwrite with your real age public key.
|
|
||||||
- &admin age1REPLACEME_run_age_keygen_y_then_paste_the_real_key_here
|
|
||||||
|
|
||||||
creation_rules:
|
|
||||||
- path_regex: secrets/.*\.yaml$
|
|
||||||
key_groups:
|
|
||||||
- age:
|
|
||||||
- *admin
|
|
||||||
|
|
@ -291,12 +291,6 @@ top of the human-facing docs, not a replacement for them.
|
||||||
Vue/Quasar UMD traps in lnbits page templates: no self-closing
|
Vue/Quasar UMD traps in lnbits page templates: no self-closing
|
||||||
tags, CSS specificity vs Quasar's `!important` utilities, cache
|
tags, CSS specificity vs Quasar's `!important` utilities, cache
|
||||||
busting via `?v={server_startup_time}`, dark-mode color discipline.
|
busting via `?v={server_startup_time}`, dark-mode color discipline.
|
||||||
- [`docs/secrets-management.md`](docs/secrets-management.md) —
|
|
||||||
beginner-friendly walkthrough for getting secrets out of `.env`
|
|
||||||
and into sops-encrypted YAML files: generating an age key, adding
|
|
||||||
recipients, declaring secrets in NixOS, rotating, multi-host
|
|
||||||
server setups, and common pitfalls. The scaffold ships the sops-nix
|
|
||||||
wiring already (inert until you create your first encrypted file).
|
|
||||||
|
|
||||||
## Contributing to this scaffold
|
## Contributing to this scaffold
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,6 @@
|
||||||
# Option schema (lnbits-sensei.*).
|
# Option schema (lnbits-sensei.*).
|
||||||
./modules/core.nix
|
./modules/core.nix
|
||||||
|
|
||||||
# sops-nix wiring. Inert until secrets/<hostName>.yaml exists.
|
|
||||||
./modules/secrets.nix
|
|
||||||
|
|
||||||
# Git remote topology — upstream / fork / extras.
|
# Git remote topology — upstream / fork / extras.
|
||||||
./modules/git/remotes.nix
|
./modules/git/remotes.nix
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,313 +0,0 @@
|
||||||
# Secrets management with sops-nix
|
|
||||||
|
|
||||||
A beginner-friendly walkthrough of getting secrets out of your
|
|
||||||
`.env` files and into `git` safely, using
|
|
||||||
[sops-nix](https://github.com/Mic92/sops-nix). Assumes no prior
|
|
||||||
familiarity with sops, age, or NixOS secret management.
|
|
||||||
|
|
||||||
## Why bother
|
|
||||||
|
|
||||||
Most LNbits dev setups start with secrets in `.env`:
|
|
||||||
|
|
||||||
```env
|
|
||||||
LNBITS_ADMIN_KEY=changeme-real-key-goes-here
|
|
||||||
POSTGRES_PASSWORD=changeme-real-password-goes-here
|
|
||||||
```
|
|
||||||
|
|
||||||
This works, but `.env` files have two failure modes:
|
|
||||||
|
|
||||||
1. **They land in git accidentally.** A `git add -A` in the wrong
|
|
||||||
moment, a forgotten `.gitignore` line, and the key history-leaks
|
|
||||||
into a public repo. Rotating after the fact is painful — there's
|
|
||||||
no fixing what's already in `git log`.
|
|
||||||
2. **They live as plaintext on disk.** A backup of your dev box, a
|
|
||||||
shared filesystem snapshot, a forgotten copy in `~/Downloads/` —
|
|
||||||
all paths to the same compromise.
|
|
||||||
|
|
||||||
sops + age fixes both. Secret values get encrypted into a YAML file
|
|
||||||
checked into your repo. The encrypted file is safe to commit, push,
|
|
||||||
and back up. Decryption happens transparently at NixOS activation
|
|
||||||
time on the host that has the matching private key. Each secret
|
|
||||||
becomes a file under `/run/secrets/<name>` that your services read.
|
|
||||||
|
|
||||||
## What's in the box (lnbits-sensei scaffold)
|
|
||||||
|
|
||||||
This repo already wires sops-nix:
|
|
||||||
|
|
||||||
- **`flake.nix`** declares `sops-nix` as a flake input.
|
|
||||||
- **`modules/secrets.nix`** imports the NixOS module and points it at
|
|
||||||
`secrets/${hostName}.yaml` + your private key at
|
|
||||||
`~/.config/sops/age/keys.txt`.
|
|
||||||
- **`.sops.yaml`** declares the recipients (which public keys can
|
|
||||||
decrypt files under `secrets/`).
|
|
||||||
- **`secrets/`** is gitignored except for `*.yaml` (which is
|
|
||||||
encrypted) and `README.md`.
|
|
||||||
- **`configuration.nix`** imports `modules/secrets.nix`.
|
|
||||||
|
|
||||||
All of this is **inert until you create your first encrypted file**.
|
|
||||||
`nix flake check` stays green meanwhile because the module gates on
|
|
||||||
`builtins.pathExists`.
|
|
||||||
|
|
||||||
## Step-by-step
|
|
||||||
|
|
||||||
### 1. Install the tools
|
|
||||||
|
|
||||||
`sops` and `age` ship in nixpkgs:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
# in modules/packages.nix or home.nix
|
|
||||||
environment.systemPackages = with pkgs; [ sops age ];
|
|
||||||
```
|
|
||||||
|
|
||||||
After `nixos-rebuild switch`, `sops` and `age-keygen` are on PATH.
|
|
||||||
|
|
||||||
For an ad-hoc install without rebuilding:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
nix-shell -p sops age
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Generate your age key
|
|
||||||
|
|
||||||
The age private key is the one piece of state that lives outside git
|
|
||||||
— it's how this machine decrypts secrets at activation time. Generate
|
|
||||||
it once per host:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
mkdir -p ~/.config/sops/age
|
|
||||||
age-keygen -o ~/.config/sops/age/keys.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
The file looks like:
|
|
||||||
|
|
||||||
```
|
|
||||||
# created: 2026-05-26T...
|
|
||||||
# public key: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
||||||
AGE-SECRET-KEY-1YYYY...
|
|
||||||
```
|
|
||||||
|
|
||||||
The line starting with `AGE-SECRET-KEY-` is your **private key**.
|
|
||||||
**Back it up somewhere safe** (a password manager, a hardware key, a
|
|
||||||
trusted offline drive). If you lose it, you lose access to every
|
|
||||||
secret encrypted to it — there is no recovery.
|
|
||||||
|
|
||||||
Print just the **public key** (you'll paste this into `.sops.yaml`):
|
|
||||||
|
|
||||||
```sh
|
|
||||||
age-keygen -y ~/.config/sops/age/keys.txt
|
|
||||||
# age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Add your public key to `.sops.yaml`
|
|
||||||
|
|
||||||
Open `.sops.yaml` at the repo root. Replace the placeholder
|
|
||||||
`age1REPLACEME...` with your real public key from the previous step:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
keys:
|
|
||||||
- &admin age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
||||||
|
|
||||||
creation_rules:
|
|
||||||
- path_regex: secrets/.*\.yaml$
|
|
||||||
key_groups:
|
|
||||||
- age:
|
|
||||||
- *admin
|
|
||||||
```
|
|
||||||
|
|
||||||
What this says: any file matching `secrets/*.yaml` should be
|
|
||||||
encrypted for the recipients listed under `key_groups.age`. Right
|
|
||||||
now that's just `*admin` (a YAML anchor pointing at your key). When
|
|
||||||
you have collaborators, you'll add their public keys as additional
|
|
||||||
recipients here.
|
|
||||||
|
|
||||||
### 4. Create your first encrypted secrets file
|
|
||||||
|
|
||||||
`sops` is the editor wrapper. It opens your `$EDITOR` on a plaintext
|
|
||||||
view of the file; on save it encrypts in place.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
sops secrets/<hostName>.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
(Use the same `hostName` you put in `settings.nix` — that's what
|
|
||||||
`modules/secrets.nix` looks for.)
|
|
||||||
|
|
||||||
Your editor opens an empty buffer. Write your secrets as plain YAML:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
lnbits-admin-key: changeme-real-key-goes-here
|
|
||||||
postgres:
|
|
||||||
lnbits-password: changeme-real-password-goes-here
|
|
||||||
```
|
|
||||||
|
|
||||||
Save and exit. sops encrypts in place. Cat the file to see what
|
|
||||||
landed on disk:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cat secrets/<hostName>.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
You'll see the keys are now opaque base64 blobs, and a `sops:`
|
|
||||||
metadata block at the bottom describes which recipients can decrypt.
|
|
||||||
This file is **safe to commit and push**.
|
|
||||||
|
|
||||||
### 5. Declare each secret in your NixOS config
|
|
||||||
|
|
||||||
For each secret you want exposed to a service, add a
|
|
||||||
`sops.secrets.<name>` declaration in the consuming module:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
# in the module that consumes the secret
|
|
||||||
{ config, ... }:
|
|
||||||
{
|
|
||||||
sops.secrets.lnbits-admin-key = {
|
|
||||||
mode = "0400";
|
|
||||||
owner = config.lnbits-sensei.user;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The `<name>` matches the YAML key in your encrypted file. Dots in
|
|
||||||
the key become nested paths under `/run/secrets/`:
|
|
||||||
|
|
||||||
| YAML key | Runtime file |
|
|
||||||
|---|---|
|
|
||||||
| `lnbits-admin-key` | `/run/secrets/lnbits-admin-key` |
|
|
||||||
| `postgres/lnbits-password` (nested) | `/run/secrets/postgres/lnbits-password` |
|
|
||||||
|
|
||||||
### 6. Reference the secret from a service
|
|
||||||
|
|
||||||
Read the runtime path via `config.sops.secrets.<name>.path`:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
# example: passing the LNbits admin key file to a service
|
|
||||||
services.someThing.adminKeyFile =
|
|
||||||
config.sops.secrets.lnbits-admin-key.path;
|
|
||||||
```
|
|
||||||
|
|
||||||
Use a file-path reference (not the value directly) wherever the
|
|
||||||
service supports one — that way the secret never ends up in the
|
|
||||||
Nix store, just at `/run/secrets/<name>` on the running host.
|
|
||||||
|
|
||||||
### 7. Activate
|
|
||||||
|
|
||||||
```sh
|
|
||||||
sudo nixos-rebuild switch --flake .#<hostName>
|
|
||||||
```
|
|
||||||
|
|
||||||
At activation, sops-nix decrypts `secrets/<hostName>.yaml` using the
|
|
||||||
private key at `~/.config/sops/age/keys.txt`, writes each declared
|
|
||||||
secret as a file under `/run/secrets/`, and your service reads from
|
|
||||||
the file path. Done.
|
|
||||||
|
|
||||||
## Common operations
|
|
||||||
|
|
||||||
**Edit a secret:**
|
|
||||||
|
|
||||||
```sh
|
|
||||||
sops secrets/<hostName>.yaml
|
|
||||||
# editor opens with plaintext view; sops re-encrypts on save
|
|
||||||
```
|
|
||||||
|
|
||||||
**View a secret without editing:**
|
|
||||||
|
|
||||||
```sh
|
|
||||||
sops -d secrets/<hostName>.yaml | grep lnbits-admin-key
|
|
||||||
```
|
|
||||||
|
|
||||||
**Rotate to new recipients (e.g. add a collaborator):**
|
|
||||||
|
|
||||||
1. Add their public key to `.sops.yaml`:
|
|
||||||
```yaml
|
|
||||||
keys:
|
|
||||||
- &admin age1xxx...
|
|
||||||
- &alice age1zzz...
|
|
||||||
creation_rules:
|
|
||||||
- path_regex: secrets/.*\.yaml$
|
|
||||||
key_groups:
|
|
||||||
- age:
|
|
||||||
- *admin
|
|
||||||
- *alice
|
|
||||||
```
|
|
||||||
2. Re-encrypt every file to the new recipient set:
|
|
||||||
```sh
|
|
||||||
sops updatekeys secrets/<hostName>.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
**Remove a recipient:** edit `.sops.yaml`, then `sops updatekeys`.
|
|
||||||
**Also rotate the underlying secret values** — anything the removed
|
|
||||||
party could previously decrypt is now compromised.
|
|
||||||
|
|
||||||
## Multi-host / server deployment
|
|
||||||
|
|
||||||
When you have one repo deploying multiple machines, each machine
|
|
||||||
needs its own age private key, and each machine's secrets file
|
|
||||||
needs to be encrypted to that machine's public key in addition to
|
|
||||||
the operator's.
|
|
||||||
|
|
||||||
**On each NixOS host (one-time):**
|
|
||||||
|
|
||||||
```sh
|
|
||||||
sudo mkdir -p /var/lib/sops-nix
|
|
||||||
sudo age-keygen -o /var/lib/sops-nix/key.txt
|
|
||||||
sudo chmod 600 /var/lib/sops-nix/key.txt
|
|
||||||
sudo age-keygen -y /var/lib/sops-nix/key.txt
|
|
||||||
# copy this public key into .sops.yaml as a new recipient
|
|
||||||
```
|
|
||||||
|
|
||||||
In `modules/secrets.nix`, swap `age.keyFile` for the host-local path:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
sops.age.keyFile = "/var/lib/sops-nix/key.txt";
|
|
||||||
```
|
|
||||||
|
|
||||||
Then in `.sops.yaml`, list every host's public key alongside the
|
|
||||||
operator's, scoped via `path_regex` if you want per-host isolation:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
keys:
|
|
||||||
- &admin age1xxx... # operator (laptop / dev box)
|
|
||||||
- &host-a age1aaa... # server A
|
|
||||||
- &host-b age1bbb... # server B
|
|
||||||
creation_rules:
|
|
||||||
- path_regex: secrets/host-a\.yaml$
|
|
||||||
key_groups:
|
|
||||||
- age:
|
|
||||||
- *admin
|
|
||||||
- *host-a
|
|
||||||
- path_regex: secrets/host-b\.yaml$
|
|
||||||
key_groups:
|
|
||||||
- age:
|
|
||||||
- *admin
|
|
||||||
- *host-b
|
|
||||||
```
|
|
||||||
|
|
||||||
That way `host-a` can only decrypt its own secrets, `host-b` only
|
|
||||||
its own, and the operator can decrypt both.
|
|
||||||
|
|
||||||
## Pitfalls
|
|
||||||
|
|
||||||
- **Don't commit unencrypted YAML under `secrets/`.** The pre-commit
|
|
||||||
hook most consumers use catches obvious cases, but it's not
|
|
||||||
foolproof. Always verify with `cat secrets/<file>.yaml` that you
|
|
||||||
see `sops:` metadata + base64 blobs, not plaintext.
|
|
||||||
- **Don't lose the private key.** No recovery. Back up the file at
|
|
||||||
`~/.config/sops/age/keys.txt` (or `/var/lib/sops-nix/key.txt` on
|
|
||||||
servers) somewhere safe and offline.
|
|
||||||
- **`updatekeys` re-encrypts but doesn't rotate secret values.** If
|
|
||||||
you're removing a recipient because they shouldn't have access
|
|
||||||
anymore, also change the underlying secrets — they could've
|
|
||||||
cached the decrypted values while they had access.
|
|
||||||
- **`sops -d` prints plaintext.** Don't pipe it into anything that
|
|
||||||
logs (`tee`, journalctl, history-aware shells). Use the file path
|
|
||||||
via `config.sops.secrets.<name>.path` in NixOS config; never
|
|
||||||
hardcode the decrypted value.
|
|
||||||
- **`environment.etc` writes to the Nix store** — readable by every
|
|
||||||
user on the host. Use `sops.secrets.<name>` (writes to
|
|
||||||
`/run/secrets/` with mode-bits you control) instead.
|
|
||||||
- **`builtins.pathExists` is checked at eval time.** If you delete
|
|
||||||
`secrets/<hostName>.yaml` after a successful build, the next
|
|
||||||
rebuild silently drops the sops block — the failure surfaces only
|
|
||||||
when a service tries to read a missing `/run/secrets/<name>` file.
|
|
||||||
Don't delete a host's encrypted file unless you also remove every
|
|
||||||
`sops.secrets.<name>` referencing it.
|
|
||||||
23
flake.lock
generated
23
flake.lock
generated
|
|
@ -56,28 +56,7 @@
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"home-manager": "home-manager",
|
"home-manager": "home-manager",
|
||||||
"lnbits-src": "lnbits-src",
|
"lnbits-src": "lnbits-src",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs"
|
||||||
"sops-nix": "sops-nix"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"sops-nix": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1777944972,
|
|
||||||
"narHash": "sha256-VfGRo1qTBKOe3s2gOv8LSoA6Fk19PvBlwQ1ECN0Evn8=",
|
|
||||||
"owner": "Mic92",
|
|
||||||
"repo": "sops-nix",
|
|
||||||
"rev": "c591bf665727040c6cc5cb409079acb22dcce33c",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "Mic92",
|
|
||||||
"repo": "sops-nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
11
flake.nix
11
flake.nix
|
|
@ -21,17 +21,6 @@
|
||||||
url = "github:lnbits/lnbits";
|
url = "github:lnbits/lnbits";
|
||||||
flake = false;
|
flake = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
# sops-nix — declarative secrets via age-encrypted YAML files.
|
|
||||||
# Decryption happens at NixOS activation; values are exposed to
|
|
||||||
# services as files under /run/secrets/<name>. The host's age
|
|
||||||
# key lives at ~/.config/sops/age/keys.txt by default; recipients
|
|
||||||
# are declared in .sops.yaml. See modules/secrets.nix for wiring
|
|
||||||
# and docs/secrets-management.md for a walkthrough.
|
|
||||||
sops-nix = {
|
|
||||||
url = "github:Mic92/sops-nix";
|
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs =
|
outputs =
|
||||||
|
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
# sops-nix per-host wiring.
|
|
||||||
# pragma: allowlist secret start
|
|
||||||
#
|
|
||||||
# Imports the sops-nix NixOS module and points it at this host's
|
|
||||||
# encrypted file + the consumer's age private key.
|
|
||||||
#
|
|
||||||
# - Recipients (which age public keys can decrypt) are declared in
|
|
||||||
# `.sops.yaml` at the repo root.
|
|
||||||
# - The encrypted file for this host lives at
|
|
||||||
# `secrets/${settings.hostName}.yaml`. Create it with:
|
|
||||||
# sops secrets/${settings.hostName}.yaml
|
|
||||||
# sops auto-encrypts on save using the recipients from .sops.yaml.
|
|
||||||
# - The matching private key lives at
|
|
||||||
# `/home/${settings.user}/.config/sops/age/keys.txt`. Generate it
|
|
||||||
# one-time with `age-keygen -o ~/.config/sops/age/keys.txt`.
|
|
||||||
#
|
|
||||||
# The whole sops block is gated on `builtins.pathExists` so flake
|
|
||||||
# eval succeeds before the encrypted file exists — useful for the
|
|
||||||
# scaffold-bootstrap phase. See `docs/secrets-management.md` for a
|
|
||||||
# walkthrough.
|
|
||||||
# pragma: allowlist secret end
|
|
||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
inputs,
|
|
||||||
settings,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
|
|
||||||
let
|
|
||||||
sopsFile = ../secrets/${settings.hostName}.yaml;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
imports = [ inputs.sops-nix.nixosModules.sops ];
|
|
||||||
|
|
||||||
sops = lib.mkIf (builtins.pathExists sopsFile) {
|
|
||||||
defaultSopsFile = sopsFile;
|
|
||||||
defaultSopsFormat = "yaml";
|
|
||||||
age.keyFile = "/home/${settings.user}/.config/sops/age/keys.txt";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
# secrets/
|
|
||||||
|
|
||||||
Encrypted YAML files in this directory are decrypted at NixOS
|
|
||||||
activation time and exposed under `/run/secrets/<name>` for any
|
|
||||||
service that declares `sops.secrets.<name>` to consume.
|
|
||||||
|
|
||||||
Recipients are declared in `../.sops.yaml`. The matching age
|
|
||||||
private key lives at `~/.config/sops/age/keys.txt` on the host
|
|
||||||
machine (see `modules/secrets.nix`).
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# First-time: create + encrypt this host's secrets file
|
|
||||||
sops secrets/<hostName>.yaml
|
|
||||||
# sops auto-encrypts on save using recipients from .sops.yaml
|
|
||||||
|
|
||||||
# Later edits go through sops (auto-decrypts, re-encrypts on save)
|
|
||||||
sops secrets/<hostName>.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
See [`../docs/secrets-management.md`](../docs/secrets-management.md)
|
|
||||||
for the full walkthrough — generating the age key, adding a recipient,
|
|
||||||
declaring a secret in NixOS, and rotating keys.
|
|
||||||
|
|
||||||
## What goes here
|
|
||||||
|
|
||||||
One YAML file per host, named after the host. Inside each file, a
|
|
||||||
flat or nested map of secret names → values:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# secrets/<hostName>.yaml — encrypted in place
|
|
||||||
lnbits-admin-key: changeme-real-key-goes-here
|
|
||||||
postgres:
|
|
||||||
lnbits-password: changeme-real-password-goes-here
|
|
||||||
```
|
|
||||||
|
|
||||||
NixOS modules reference these by name via `sops.secrets.<name>`
|
|
||||||
and read the runtime path via `config.sops.secrets.<name>.path`.
|
|
||||||
Reference in a new issue