Two changes to the control server, plus the fallout on the hosts. OIDC via Authentik, so `tailscale up --login-server ...` opens a browser instead of needing a pre-auth key. This is a second Authentik application, separate from headplane's, with headscale's own /oidc/callback redirect. Headless hosts keep using pre-auth keys. Note that headscale runs OIDC discovery at startup and a failure is FATAL -- pointing `issuer` at an application that does not exist yet means the control server will not boot, so verify the discovery document before deploying. override_local_dns = false, because the upstream default of true replaces resolv.conf with 100.100.100.100 on every node. That silently broke the LAN's `.sol` names -- pihole serves those and the global nameservers return NXDOMAIN for them -- and took ad blocking down with them. It also made each node's entire DNS depend on tailscaled, which is what had forced --accept-dns=false onto neptun and mercury individually; both of those workarounds are now removed, and with MagicDNS resolving properly again neptun no longer needs its hardcoded /etc/hosts pin for jupiter. Also serves jellyfin and seerr from jupiter, matching the ports they already use on its LAN vhosts, and rotates the tailnet pre-auth keys. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
58 lines
2.8 KiB
Nix
58 lines
2.8 KiB
Nix
{ config, ... }:
|
|
|
|
# sops-nix wiring for neptun (netcup VPS). Encrypted values in ../../secrets/neptun.yaml,
|
|
# decrypted with the VPS's own SSH host key (recipient in ../../.sops.yaml).
|
|
# The host key is pre-generated on the laptop and shipped at install
|
|
# (nixos-anywhere --extra-files -> /etc/ssh/ssh_host_ed25519_key).
|
|
{
|
|
sops.defaultSopsFile = ../../secrets/neptun.yaml;
|
|
sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
|
|
|
|
sops.secrets.tailscale_authkey = { };
|
|
|
|
# darman's console password (own hash = distinct from jupiter/mercury).
|
|
sops.secrets.darman_password.neededForUsers = true;
|
|
users.users.darman.hashedPasswordFile = config.sops.secrets.darman_password.path;
|
|
|
|
# Authentik takes a single systemd EnvironmentFile (services/identity/authentik.nix).
|
|
# No `owner` here on purpose: systemd reads EnvironmentFile as root before
|
|
# dropping to the service's DynamicUser, so root:root 0400 is what we want.
|
|
#
|
|
# AUTHENTIK_SECRET_KEY signs sessions/tokens — rotating it logs everyone out.
|
|
# The BOOTSTRAP_* vars only take effect on the very first start, where they
|
|
# create the `akadmin` superuser; they're inert on every boot after that.
|
|
sops.secrets.authentik_secret_key = { };
|
|
sops.secrets.authentik_bootstrap_password = { };
|
|
sops.secrets.authentik_bootstrap_email = { };
|
|
sops.templates."authentik.env".content = ''
|
|
AUTHENTIK_SECRET_KEY=${config.sops.placeholder.authentik_secret_key}
|
|
AUTHENTIK_BOOTSTRAP_PASSWORD=${config.sops.placeholder.authentik_bootstrap_password}
|
|
AUTHENTIK_BOOTSTRAP_EMAIL=${config.sops.placeholder.authentik_bootstrap_email}
|
|
'';
|
|
|
|
# Caddy's ACME account email. Same EnvironmentFile trick as authentik above,
|
|
# and root:root 0400 is likewise correct — systemd reads it before dropping
|
|
# to User=caddy. Wired up in configuration.nix.
|
|
sops.secrets.caddy_acme_email = { };
|
|
sops.templates."caddy.env".content = ''
|
|
ACME_EMAIL=${config.sops.placeholder.caddy_acme_email}
|
|
'';
|
|
|
|
# Headplane: cookie_secret_path takes a path natively (no store leak).
|
|
# oidc.client_secret + the headscale API key are still REPLACE_ME
|
|
# placeholders (see services/vpn/headplane.nix) until Authentik/headscale are
|
|
# actually deployed and those get created for real.
|
|
#
|
|
# owner: unlike authentik's EnvironmentFile above, headscale and headplane
|
|
# open these paths themselves, already running as the headscale user — so
|
|
# the root:root 0400 default would fail and each needs an explicit owner.
|
|
#
|
|
# headscale's OIDC client is a SEPARATE Authentik application from
|
|
# headplane's (services/vpn/headscale.nix), hence the second client secret.
|
|
sops.secrets.headscale_oidc_client_secret.owner = "headscale";
|
|
|
|
sops.secrets.headplane_cookie_secret.owner = "headscale";
|
|
sops.secrets.headplane_oidc_client_secret.owner = "headscale";
|
|
sops.secrets.headplane_headscale_api_key.owner = "headscale";
|
|
}
|