Security
Touch ID for sudo, even inside a multiplexer, plus lock behaviour, the firewall, and where this machine gets its secrets.
collar is the small auth room: it turns on Touch ID for sudo, and
(the part stock Touch-ID-for-sudo gets wrong) makes that work inside a
terminal multiplexer like zellij or tmux, where it would otherwise silently
fail.
Enable it
haus.collar.enable = true;
haus.collar.passwordlessRebuild = true;What it turns on
security.pam.services.sudo_local.touchIdAuth = true; # fingerprint for sudo
security.pam.services.sudo_local.reattach = true; # make it work in tmux/zellijreattach pulls in pam_reattach,
which reattaches the sudo process to your GUI login session. Without it,
sudo inside a multiplexer detaches from Aqua and the Touch ID prompt just
beachballs. Cancel the prompt and it falls back to a typed password.
collar also installs /etc/sudoers.d/darwin-rebuild, exempting activation
from authentication entirely:
<you> ALL=(ALL) NOPASSWD: /run/current-system/sw/bin/darwin-rebuild
<you> ALL=(ALL) NOPASSWD: /run/current-system/sw/bin/haus-activateActivating a build is the one privileged thing this desktop does constantly,
and a prompt per rebuild buys nothing: you already authenticated to build
it. darwin-rebuild is the classic route (and the only one for haus rollback); haus-activate is the faster path haus rebuild and bench try switch take, building as you and handing the result to root without a
second evaluation. Neither is a wider grant than darwin-rebuild switch --flake <anything> already was; haus.collar.passwordlessRebuild = false
drops both.
Why the stable path, not the store path
macOS 26.6 shipped sudo 1.9.17, which stopped dereferencing a command's
symlink before matching sudoers: a rule against a /nix/store/… path only
matches if you type that literal path, which nobody does. Matching
/run/current-system/sw/bin/darwin-rebuild is what survives a rebuild.
Yes, it works inside zellij
Type sudo -v in a zellij pane and the Touch ID dialog floats up right over
the multiplexer. Touch the sensor, no password typed. (darwin-rebuild is
the happy exception; it doesn't even ask.)
What it does not do
collar stays out of key management. YubiKey and GPG live outside Nix
entirely: key material, smartcard setup, and pinentry are handled by
gpg-agent + pinentry-mac at runtime, keeping secrets off the Nix store.
Commit signing itself is wired up in the Development room
from haus.git.signingKey; collar only handles sudo authentication.
Two switches
haus.collar.enable = true; # Touch ID for sudo, reattach and all
haus.collar.passwordlessRebuild = true; # activation never authenticatesBoth default on. Turn passwordlessRebuild off on a machine you don't
administer alone, and activation goes back to asking. Turn enable off and
macOS's stock password prompt comes back everywhere.
The rest of the room
Three more surfaces, each unset by default so a fresh Mac keeps macOS's own answer until you say otherwise:
haus.lock.requirePassword = true; # and .requirePasswordDelay
haus.security.firewall.enable = true; # the built-in application firewall
haus.secrets.provider = "keychain"; # where secret values come fromThe firewall is off on a fresh Mac; it is the setting to turn on for a laptop that joins networks you don't own. Secrets themselves never live in your config; haus declares which exist and fetches them at runtime.
Works with
- Development: commit signing is configured
there; this room is what stops
sudoasking for a password. - AI:
passwordlessRebuildis what lets an agent runhaus rebuildend to end without a prompt it can't answer.
Remove it
haus.collar.enable = false;sudo goes back to the password prompt. The firewall and lock settings stop
being written but keep whatever value they last had: unsetting an option stops
managing a macOS setting rather than restoring the one before it.
haus.secrets.provider is host-only: where a machine keeps its secrets is a
fact about that machine.
Options
Every setting, with types and defaults: Security.