mirror of
https://github.com/ryan4yin/nix-config.git
synced 2026-11-13 12:13:36 +01:00
chore(secrets): refresh mysecrets and follow agenix-rules rename
Update the mysecrets lock to 7f93490, which renames secrets.nix to agenix-rules.nix, drops the deprecated ./ key prefixes for agenix 0.18, and re-encrypts the access-token secret. Update the docs and agenix skill to the new filename and path convention.
This commit is contained in:
1 parent
38d1d85e85
commit
01d2e76410
4 files changed
+39
-36
No files matched your search
@@ -19,7 +19,7 @@ Read [secrets/README.md](../../../secrets/README.md) for the concepts and the re
|
||||
|
||||
Two age flows live in `~/codes/nix-secrets`, and a file belongs to exactly one.
|
||||
|
||||
- **agenix** (`secrets.nix`): static and one-way, repository → host, decrypted at activation.
|
||||
- **agenix** (`agenix-rules.nix`): static and one-way, repository → host, decrypted at activation.
|
||||
Consumed as `/run/agenix/<name>` or an `environment.etc` copy; needs a `flake.lock` bump.
|
||||
- **dotfiles sync** (`dotfiles/`): changes on the host; `save`/`restore` are manual, outside Nix.
|
||||
Consumed as a real file under `$HOME`, edited by hand or by its tool; **no** lock bump.
|
||||
@@ -30,8 +30,8 @@ is a config file its tool keeps rewriting that happens to carry a few secrets in
|
||||
decides it, not the encryption: `flake.lock` fixes the agenix revision, so every edit costs a
|
||||
rebuild and switch on every desktop.
|
||||
|
||||
Nothing in this flake evaluates the sync flow: no `secrets.nix` entry, no `agenix -r`, no lock bump,
|
||||
so the three-step order in §2 does not apply to it. Its manifest and file list live in
|
||||
Nothing in this flake evaluates the sync flow: no `agenix-rules.nix` entry, no `agenix -r`, no lock
|
||||
bump, so the three-step order in §2 does not apply to it. Its manifest and file list live in
|
||||
`~/codes/nix-secrets/dotfiles/`; this repository carries the pointer, never the inventory. Do not
|
||||
list synced paths here or copy one into a Nix module. The flow covers the desktops only; do not set
|
||||
it up on a server or a cluster node.
|
||||
@@ -72,14 +72,14 @@ must not get one back.
|
||||
- Decryption key: `age.identityPaths` — the host's SSH host key; `/persistent/etc/ssh/...` on a
|
||||
preservation host
|
||||
- Secret-bearing dotfiles edited in place: `~/codes/nix-secrets/dotfiles/` — private, not a flake
|
||||
input, no entry in `secrets.nix`
|
||||
input, no entry in `agenix-rules.nix`
|
||||
|
||||
The private repository keeps its `.age` files in `desktop/` (only desktops decrypt them), `server/`
|
||||
(any server), and `certs/`; `public/` holds publishable plaintext, not `.age`.
|
||||
|
||||
## 2. Add or change a secret
|
||||
|
||||
Do the mechanical work yourself: edit `secrets.nix` in `~/codes/nix-secrets`, run the
|
||||
Do the mechanical work yourself: edit `agenix-rules.nix` in `~/codes/nix-secrets`, run the
|
||||
non-interactive steps, bump the lock, and add the declaration and consumer. For a new secret, or a
|
||||
full replacement, pipe the plaintext into the `replace` recipe: it removes the target first, so
|
||||
agenix only encrypts and needs no `sudo`. Hand back only what needs a human: the partial `edit` and
|
||||
@@ -88,8 +88,8 @@ value, so they handle key material, `$EDITOR`, and `sudo`) and anything else und
|
||||
and pushes follow the global git rules.
|
||||
|
||||
1. In `~/codes/nix-secrets`, add the file under `desktop/` or `server/` with a matching
|
||||
`secrets.nix` entry, keyed by that exact path (e.g. `"./desktop/xxx.age"`), and the recipient set
|
||||
from core rule 3. Then encrypt it with the `replace` recipe (§3); ask the user only when the
|
||||
`agenix-rules.nix` entry, keyed by that exact path (e.g. `"desktop/xxx.age"`), and the recipient
|
||||
set from core rule 3. Then encrypt it with the `replace` recipe (§3); ask the user only when the
|
||||
plaintext has to come from an interactive session.
|
||||
2. Here: `just upp mysecrets` (commits the lock) or `nix flake update mysecrets` (leaves it for you
|
||||
to commit). `git diff flake.lock` should show only `mysecrets` moving.
|
||||
@@ -106,18 +106,18 @@ Changing only a secret's value is steps 1, 2, and the deploy: use `replace` for
|
||||
The agenix operations run against `~/codes/nix-secrets`. Their single source is
|
||||
[`secrets/Justfile`](../../../secrets/Justfile), which pins the identity, option order, and
|
||||
`$EDITOR`; run them from this repository's root and keep each path identical to its key in
|
||||
`secrets.nix`:
|
||||
`agenix-rules.nix`:
|
||||
|
||||
```bash
|
||||
just -f secrets/Justfile replace ./desktop/xxx.age < plaintext # add or fully replace (no sudo)
|
||||
just -f secrets/Justfile edit ./desktop/xxx.age # partial edit (sudo, $EDITOR)
|
||||
just -f secrets/Justfile replace desktop/xxx.age < plaintext # add or fully replace (no sudo)
|
||||
just -f secrets/Justfile edit desktop/xxx.age # partial edit (sudo, $EDITOR)
|
||||
just -f secrets/Justfile rekey # re-encrypt after a recipient change
|
||||
```
|
||||
|
||||
`edit` and `rekey` decrypt the current value with the host key, so they need `sudo`; `replace` only
|
||||
encrypts to the recipients in `secrets.nix`, so it needs no `sudo`. `edit` passes `EDITOR=hx` to the
|
||||
root `agenix` process, because `sudo` resets the environment and the invoking user's `EDITOR` would
|
||||
not reach it; do not add `sudo -E` or set `EDITOR` yourself.
|
||||
encrypts to the recipients in `agenix-rules.nix`, so it needs no `sudo`. `edit` passes `EDITOR=hx`
|
||||
to the root `agenix` process, because `sudo` resets the environment and the invoking user's `EDITOR`
|
||||
would not reach it; do not add `sudo -E` or set `EDITOR` yourself.
|
||||
|
||||
## 4. Modes and ownership
|
||||
|
||||
@@ -152,7 +152,8 @@ you set, an old copy gone) instead of assuming activation did it.
|
||||
- Delete the `age.secrets` entry, its `environment.etc` placement, and every consumer in one change;
|
||||
a declaration whose file no longer exists breaks activation. On darwin also drop the path from the
|
||||
`chown`/`chmod` list in `system.activationScripts.postActivation`.
|
||||
- Remove it from `secrets.nix` and delete the file in the private repository, then bump the lock.
|
||||
- Remove it from `agenix-rules.nix` and delete the file in the private repository, then bump the
|
||||
lock.
|
||||
- A rename changes the attribute name and every consumer. The `.age` filename is separate.
|
||||
- Moving a secret **out** of agenix into the sync flow is that deletion plus what agenix used to
|
||||
guarantee: the consumer points at a `$HOME` path, and on a preservation host the directory joins
|
||||
@@ -164,7 +165,8 @@ you set, an old copy gone) instead of assuming activation did it.
|
||||
## 7. Failure modes
|
||||
|
||||
- **Decryption fails on one host:** its host key is not a recipient. Add its
|
||||
`/etc/ssh/ssh_host_ed25519_key.pub` to `secrets.nix`, rekey (§3), push, bump the lock, redeploy.
|
||||
`/etc/ssh/ssh_host_ed25519_key.pub` to `agenix-rules.nix`, rekey (§3), push, bump the lock,
|
||||
redeploy.
|
||||
- **Eval or activation cannot find the file:** the lock still points at a `mysecrets` revision
|
||||
without it (core rule 2).
|
||||
- **`permission denied` in a user service:** it reads a root-only secret. Fix that secret's owner;
|
||||
|
||||
Generated
+3
-3
@@ -695,10 +695,10 @@
|
||||
"mysecrets": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1790919428,
|
||||
"narHash": "sha256-04+A6Hmjj2lXGanEWfqoQkkAGiQgVT0CMY5BTOlfcBo=",
|
||||
"lastModified": 1793275857,
|
||||
"narHash": "sha256-Ut8ohwrRRiIsQdWEzVNtysY7g34uzYS/+sWnQK7c3O0=",
|
||||
"ref": "refs/heads/main",
|
||||
"rev": "7b78dbb128be0ca52ac2815d5d8a73c5f883dada",
|
||||
"rev": "7f93490f165543532f34f388f346af91db5715ac",
|
||||
"shallow": true,
|
||||
"type": "git",
|
||||
"url": "ssh://git@github.com/ryan4yin/nix-secrets.git"
|
||||
|
||||
@@ -218,7 +218,7 @@ reinstall or a key rotation:
|
||||
|
||||
1. `ssh aquamarine cat /etc/ssh/ssh_host_ed25519_key.pub`.
|
||||
2. Put that key in `vars/networking.nix` under `knownHosts` (the entry was removed with the old key)
|
||||
and, if this host should read agenix secrets, in `~/codes/nix-secrets/secrets.nix` under
|
||||
and, if this host should read agenix secrets, in `~/codes/nix-secrets/agenix-rules.nix` under
|
||||
`application_server_keys`.
|
||||
3. Rekey and bump the pin: `just -f secrets/Justfile rekey`, push `nix-secrets`, then
|
||||
`just upp mysecrets` here.
|
||||
|
||||
+18
-17
@@ -29,9 +29,10 @@ costs a lock bump plus a rebuild and switch on every host that reads it.
|
||||
|
||||
Anything else is a synced dotfile: Nix does not read it, it changes often, or it is a config file
|
||||
its tool keeps rewriting that happens to carry a few secrets inside. The private repository syncs
|
||||
those as age ciphertext under `dotfiles/`, by hand and outside Nix, so there is no `secrets.nix`
|
||||
entry and no lock bump. `nushell-secrets.nu` moved that way and is `~/.secrets/nushell-secrets.nu`
|
||||
now; do not re-add it to `age.secrets`. The file list stays in the private repository.
|
||||
those as age ciphertext under `dotfiles/`, by hand and outside Nix, so there is no
|
||||
`agenix-rules.nix` entry and no lock bump. `nushell-secrets.nu` moved that way and is
|
||||
`~/.secrets/nushell-secrets.nu` now; do not re-add it to `age.secrets`. The file list stays in the
|
||||
private repository.
|
||||
|
||||
## Which Keys Go on a Secret
|
||||
|
||||
@@ -70,13 +71,13 @@ a blanket chown over `/etc/agenix/*` would make the root-only secrets readable b
|
||||
|
||||
## Adding or Updating Secrets
|
||||
|
||||
> The encrypted `.age` files and `secrets.nix` live in my private `nix-secrets` repository. The
|
||||
> The encrypted `.age` files and `agenix-rules.nix` live in my private `nix-secrets` repository. The
|
||||
> `Justfile` referenced below lives in this repository and runs its recipes with `working-directory`
|
||||
> set to a local `~/codes/nix-secrets` checkout, so invoke it from this repository's root.
|
||||
|
||||
This task is accomplished using the [agenix](https://github.com/ryantm/agenix) CLI tool with the
|
||||
`./secrets.nix` file in the private `nix-secrets` repository, so you need to have it installed
|
||||
first:
|
||||
`agenix-rules.nix` file in the private `nix-secrets` repository, so you need to have it installed
|
||||
first. Rule keys are paths relative to that file and must not start with `./` (agenix 0.18+).
|
||||
|
||||
To use agenix temporarily, run:
|
||||
|
||||
@@ -93,8 +94,8 @@ nix shell github:ryan4yin/ragenix#ragenix
|
||||
Suppose you want to add a new secret file `xxx.age`. Follow these steps:
|
||||
|
||||
1. Navigate to your private `nix-secrets` repository.
|
||||
2. Edit `secrets.nix` and add a new entry for `xxx.age`, defining the encryption keys and the secret
|
||||
file path, for example:
|
||||
2. Edit `agenix-rules.nix` and add a new entry for `xxx.age`, defining the encryption keys and the
|
||||
secret file path, for example:
|
||||
|
||||
```nix
|
||||
# This file is not imported into your NixOS configuration. It is only used for the agenix CLI.
|
||||
@@ -121,7 +122,7 @@ let
|
||||
hosts = [ ];
|
||||
in
|
||||
{
|
||||
"./xxx.age".publicKeys = desktop_keys ++ hosts;
|
||||
"xxx.age".publicKeys = desktop_keys ++ hosts;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -129,20 +130,20 @@ in
|
||||
`replace` recipe, piping the plaintext on stdin:
|
||||
|
||||
```shell
|
||||
just -f secrets/Justfile replace ./xxx.age < plaintext
|
||||
just -f secrets/Justfile replace xxx.age < plaintext
|
||||
```
|
||||
|
||||
`replace` deletes the target first, so agenix only encrypts to the public keys in `secrets.nix` and
|
||||
never decrypts the old value — it needs no `sudo`. Use `edit` instead for a partial change to an
|
||||
`replace` deletes the target first, so agenix only encrypts to the public keys in `agenix-rules.nix`
|
||||
and never decrypts the old value — it needs no `sudo`. Use `edit` instead for a partial change to an
|
||||
existing secret: it decrypts the current value first with the host key
|
||||
(`/etc/ssh/ssh_host_ed25519_key`), so it needs `sudo`.
|
||||
|
||||
```shell
|
||||
just -f secrets/Justfile edit ./xxx.age
|
||||
just -f secrets/Justfile edit xxx.age
|
||||
```
|
||||
|
||||
`agenix` will encrypt the file with all the public keys we defined in `secrets.nix`, so all the
|
||||
users and systems defined in `secrets.nix` can decrypt it with their private keys.
|
||||
`agenix` will encrypt the file with all the public keys we defined in `agenix-rules.nix`, so all the
|
||||
users and systems defined in `agenix-rules.nix` can decrypt it with their private keys.
|
||||
|
||||
After pushing, run `just upp mysecrets` in this repository: `flake.lock` pins `mysecrets`, so a new
|
||||
or changed file is invisible here until the lock moves. The repo-side steps are in
|
||||
@@ -219,7 +220,7 @@ Then, create `./secrets/nixos.nix` (or `./secrets/darwin.nix` on macOS) with the
|
||||
# target path for decrypted file
|
||||
path = "/etc/xxx";
|
||||
# encrypted file path
|
||||
file = "${mysecrets}/xxx.age"; # refer to ./xxx.age located in `mysecrets` repo
|
||||
file = "${mysecrets}/xxx.age"; # refer to xxx.age located in `mysecrets` repo
|
||||
mode = "0400";
|
||||
owner = "root";
|
||||
group = "root";
|
||||
@@ -236,7 +237,7 @@ the `age.secrets.<name>.path` argument, which defaults to `/run/agenix/<name>`.
|
||||
1. `cat` the system-level public key(`/etc/ssh/ssh_host_ed25519_key.pub`) of the new host, and send
|
||||
it to an old host which has already been configured.
|
||||
2. On the old host:
|
||||
1. Add the public key to `secrets.nix`, then rekey all the secrets:
|
||||
1. Add the public key to `agenix-rules.nix`, then rekey all the secrets:
|
||||
`just -f secrets/Justfile rekey`.
|
||||
2. Commit and push the changes to `nix-secrets`.
|
||||
3. On the new host:
|
||||
|
||||
Reference in new issue
Block a user