refactor(darwin): decrypt agenix secrets to /etc/agenix via path

agenix's darwin module honours age.secrets.<name>.path and applies owner and
mode itself, so the environment.etc links and the postActivation chown/chmod
that re-applied them go away.

Assisted-by: Claude Code (claude-opus-5-5)
This commit is contained in:
Ryan Yin authored and ryan4yin | 二花 committed 2026-11-01 11:55:14 -06:00
1 parent 3789a2a282
commit 6ea53e8dd7
3 files changed
+8 -48

No files matched your search

+3 -3
View File
@@ -268,9 +268,9 @@ export, credential, DNS record or firmware configuration was changed during the
desktops. Same-user agents are not isolated from these credentials by Unix file permissions. Mode
`0000` also does not stop privileged root. Other host/runtime ownership checks and recipient
membership were not completed; no private recipient repository or secret value was inspected.
- Darwin's activation now re-applies each secret's declared ownership explicitly instead of a
blanket `chown` over `/etc/agenix/*`, so the root-only `rclone.conf` stays root-owned. Runtime
ownership (`ls -l /etc/agenix`) on each Darwin host still needs a check after the next activation.
- Darwin's `/etc/agenix` entries are agenix `path` symlinks, so agenix applies each secret's
declared owner and mode and the root-only `rclone.conf` stays root-owned. Runtime ownership
(`ls -lL /etc/agenix`) on each Darwin host still needs a check after the next activation.
- PostgreSQL's loopback TCP listener still trusts every role except `postgres` without a password,
so any local process can log in as `immich` or `playground`. No service configured here uses that
path: Immich and the exporter connect over the Unix socket with peer authentication. `postgres`
+1 -2
View File
@@ -66,8 +66,7 @@ Placing a secret under `/etc/agenix/` with `environment.etc` has one trap: setti
`environment.etc` **copy** the file instead of symlinking it, and the copy is owned by root unless
`user` is set too. Widening the mode so the user can read a root-owned copy makes it readable by
every local account. Always set `user` together with `mode`. nix-darwin ignores both on
`environment.etc`, so `secrets/darwin.nix` re-applies each secret's owner and mode after activation;
a blanket chown over `/etc/agenix/*` would make the root-only secrets readable by the login user.
`environment.etc`, so `secrets/darwin.nix` sets agenix's `path` to `/etc/agenix/<name>` instead.
## Adding or Updating Secrets
+4 -43
View File
@@ -1,5 +1,4 @@
{
config,
pkgs,
agenix,
mysecrets,
@@ -50,6 +49,7 @@
# .age means the decrypted file is still encrypted by age(via a passphrase)
"ryan4yin-gpg-subkeys.priv.age" = {
file = "${mysecrets}/desktop/ryan4yin-gpg-subkeys-2024-01-27.priv.age.age";
path = "/etc/agenix/ryan4yin-gpg-subkeys.priv.age";
}
// noaccess;
@@ -59,6 +59,7 @@
"rclone.conf" = {
file = "${mysecrets}/desktop/rclone.conf.age";
path = "/etc/agenix/rclone.conf";
}
// high_security;
@@ -74,56 +75,16 @@
"ssh-key-romantic" = {
file = "${mysecrets}/desktop/ssh-key-romantic.age";
path = "/etc/agenix/ssh-key-romantic";
}
// user_readable;
# work git identity, symlinked to ~/work/.gitconfig by home-manager
"work-gitconfig" = {
file = "${mysecrets}/desktop/work-gitconfig.age";
path = "/etc/agenix/work-gitconfig";
}
// user_readable;
};
# place secrets in /etc/
# NOTE: this will fail for the first time. cause it's running before "activate-agenix"
environment.etc = {
"agenix/rclone.conf" = {
source = config.age.secrets."rclone.conf".path;
};
"agenix/ssh-key-romantic" = {
source = config.age.secrets."ssh-key-romantic".path;
};
"agenix/ryan4yin-gpg-subkeys.priv.age" = {
source = config.age.secrets."ryan4yin-gpg-subkeys.priv.age".path;
};
# The following secrets are used by home-manager modules
# But nix-darwin doesn't support environment.etc.<name>.mode
# So we need to change its mode manually
"agenix/work-gitconfig" = {
source = config.age.secrets."work-gitconfig".path;
};
};
# nix-darwin ignores environment.etc.<name>.mode/owner, and a blanket chown
# makes the root-only secrets readable by the login user. Re-apply each
# secret's declared policy instead.
system.activationScripts.postActivation.text = ''
if [ -d /etc/agenix ]; then
${pkgs.coreutils}/bin/chown ${myvars.username} \
/etc/agenix/ssh-key-romantic \
/etc/agenix/work-gitconfig
${pkgs.coreutils}/bin/chmod 0500 \
/etc/agenix/ssh-key-romantic \
/etc/agenix/work-gitconfig
${pkgs.coreutils}/bin/chown root /etc/agenix/rclone.conf
${pkgs.coreutils}/bin/chmod 0500 /etc/agenix/rclone.conf
${pkgs.coreutils}/bin/chown root /etc/agenix/ryan4yin-gpg-subkeys.priv.age
${pkgs.coreutils}/bin/chmod 0000 /etc/agenix/ryan4yin-gpg-subkeys.priv.age
fi
'';
}