mercury: join the tailnet

mercury was the only host with no tailscale at all -- no module import,
no secret, no key in its sops file. It had been enrolled before the NixOS
migration and silently dropped off the tailnet when it was reflashed with
a config that omitted it.

--accept-dns=false, as on neptun and for a sharper reason: headscale
pushes override_local_dns, so accepting MagicDNS would repoint the LAN's
own DNS server at 100.100.100.100 and make house-wide name resolution
depend on tailscaled being up. This host has already deadlocked once on
boot-time DNS (see CLAUDE.md).

darman_password is also rotated: the account had "!" in /etc/shadow,
because on mercury's first boot the secret wasn't readable yet and
update-users-groups.pl falls back to a locked account. mutableUsers is
true, so no later rebuild ever revisited it and the lock was permanent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-20 19:41:39 +02:00
co-authored by Claude Opus 4.8
parent 8aa3dac4de
commit d9ea6a9ecc
3 changed files with 16 additions and 3 deletions
+8
View File
@@ -9,6 +9,7 @@
./secrets.nix # sops-nix: darman password (age key on boot part.) ./secrets.nix # sops-nix: darman password (age key on boot part.)
../../services/network/unbound.nix # local recursive resolver (127.0.0.1:5335) ../../services/network/unbound.nix # local recursive resolver (127.0.0.1:5335)
../../services/network/pihole.nix # DNS adblock + DHCP (declarative static leases) ../../services/network/pihole.nix # DNS adblock + DHCP (declarative static leases)
../../services/vpn/tailscale.nix # tailnet node (headscale on neptun)
]; ];
networking.hostName = "mercury"; networking.hostName = "mercury";
@@ -33,6 +34,13 @@
# host resolves during boot without depending on its own pihole/unbound. # host resolves during boot without depending on its own pihole/unbound.
networking.nameservers = [ "1.1.1.1" "9.9.9.9" ]; networking.nameservers = [ "1.1.1.1" "9.9.9.9" ];
# Never take MagicDNS on THIS host. headscale pushes override_local_dns, so
# accepting it would repoint mercury's resolv.conf at 100.100.100.100 and
# make the LAN's DNS server depend on tailscaled to resolve anything — the
# same boot-time DNS deadlock this host already hit once (see CLAUDE.md),
# except a failure here takes the whole network's DNS down with it.
services.tailscale.extraUpFlags = [ "--accept-dns=false" ];
# ---- pihole web admin password (from sops) ---- # ---- pihole web admin password (from sops) ----
# The pihole container reads FTLCONF_* env vars. Render an env file from the # The pihole container reads FTLCONF_* env vars. Render an env file from the
# sops secret and feed it to the container — password stays out of repo/store. # sops secret and feed it to the container — password stays out of repo/store.
+4
View File
@@ -15,4 +15,8 @@
# host = different password per host. # host = different password per host.
sops.secrets.darman_password.neededForUsers = true; sops.secrets.darman_password.neededForUsers = true;
users.users.darman.hashedPasswordFile = config.sops.secrets.darman_password.path; users.users.darman.hashedPasswordFile = config.sops.secrets.darman_password.path;
# Pre-auth key for services/vpn/tailscale.nix. Root-owned 0400 is right:
# tailscaled runs as root and reads authKeyFile itself.
sops.secrets.tailscale_authkey = { };
} }
+4 -3
View File
@@ -1,5 +1,6 @@
darman_password: ENC[AES256_GCM,data:Wc7y/5QPUxD4mxDGBp9V2k6YNrbmehbpcltInIBSGk70cdqxSUOjHZIL0hzPS4ijrXPnR9gwSZbc7EmgbLZ2K96SJtz9+upDAQVVUFfNx0o+SfGEu3ai3Qi7tKa+1N9wZQW/+6gQOAMAGQ==,iv:K/GrcQFtYWgQAtDlNVaYS5jUADYfX6rMSIUM9niRcWQ=,tag:9dbiRlIzAkm382Bkc6LfJA==,type:str] darman_password: ENC[AES256_GCM,data:iZQERcXtyH+91yUc3r7U6jnFYrGQPFeCPk/9ZDfxOhPLlGMX3/iEZ+SzZ7a7rDKUeUAaQUsrqANLDLclRYm4Ngo09EkbDxBx5x2GpQwlqSAS45LHnTen9LTzisWghdy79Xnilq322eaB3g==,iv:ozx/BPLR8nZTKHZroKrrh2z6ZlVCuLydQ3aNY4XvcIg=,tag:CSrq5ZipYxtXTT8RintuHQ==,type:str]
pihole_webpassword: ENC[AES256_GCM,data:5iOTqD0CcbOCnM1b4+RbajMTyAU=,iv:2ZRW7dshnPzWkuudrn6n92y4Z2n/6fdnBB7BO5/ypS4=,tag:8UZSqJM6dVECQgrF6v5Fuw==,type:str] pihole_webpassword: ENC[AES256_GCM,data:5iOTqD0CcbOCnM1b4+RbajMTyAU=,iv:2ZRW7dshnPzWkuudrn6n92y4Z2n/6fdnBB7BO5/ypS4=,tag:8UZSqJM6dVECQgrF6v5Fuw==,type:str]
tailscale_authkey: ENC[AES256_GCM,data:CZe1wkh2DNF2g4wy30Wph0c4/3f1M2K9Up+3oAcLEVdZjJzLRJotAU/0Nw2PSGoDZTtqOSfDaEXsaa45DBIJj2EUvWKSYrkV4XkLCio6ZWoGhmxH9PYfkw==,iv:UqNZz7grRPT/d1a2Tv1PW4H2k5FeZCuDy/fK+jVou9E=,tag:cYbLk+7JqU/1by8j2ri0Xg==,type:str]
sops: sops:
age: age:
- enc: | - enc: |
@@ -20,7 +21,7 @@ sops:
x6FfYadcRfqvSX60l6+TGdzq6xDpxLIZOJ8q19qZsAvB0in50HW5gg== x6FfYadcRfqvSX60l6+TGdzq6xDpxLIZOJ8q19qZsAvB0in50HW5gg==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
recipient: age1cpty7zrgnn6l97upq00w5wa8zcvnkxkdt2jvhlj97jh83exure4slha43t recipient: age1cpty7zrgnn6l97upq00w5wa8zcvnkxkdt2jvhlj97jh83exure4slha43t
lastmodified: "2026-07-13T20:42:08Z" lastmodified: "2026-07-20T08:31:19Z"
mac: ENC[AES256_GCM,data:TWismb9lTPOp9RC0u7zlQPoJtql5G0obxFIcI2D4R43VCRKux6LPzZvVEwLe7KjkLC9c6p+ti1dy4lIL9lo57BJfyh1HV+u+RvVCTbVw0Cd8EoGCC3NWJ+jFJi6jWAwOdJ2SOgOavpxBaFObYpEGkJ4XZqJX7XCY/k4YuuFT/yo=,iv:XtHOSE2ZH3j3blSWkXUqxWmZOO1tVEKoWgHB7rt81qA=,tag:7JBmUyHgqSbrmNqPXfXMTQ==,type:str] mac: ENC[AES256_GCM,data:kdWGhCOENvnUAnwbLW58JH8Ur+g+f4Z1pr3seZGGOFa04xeXb5HOzegpIH+x7OT5OvsKZsMKWf7sBGgB/nx+m2ZKy4NLC39dLbV8V5hs18NhRKl5vKZBZHE1D2xAK4+REwRYT6LiXArQssPv9e2q5fcW6q3rtnlHMF0tUsWip9o=,iv:BkKv2ZBxZMX4agHTzF2Mcmasxpp+hqkiu9mH0mUeLS4=,tag:t0MeKRPikYR5MAmU8r77sg==,type:str]
unencrypted_suffix: _unencrypted unencrypted_suffix: _unencrypted
version: 3.13.1 version: 3.13.1