Archived
Compare commits
17
Commits
@@ -6,12 +6,14 @@ This repository contains flake-based NixOS configurations for Wayne's LAN
|
||||
servers and workstation.
|
||||
|
||||
The flake exposes NixOS configurations named `<platform>-<buildtype>`
|
||||
(platforms: `linode`, `proxmox`, `lxc`; build types: `minimal`, `nix-cache`,
|
||||
`server`, `docker`, `gui`, `pxe-boot`, `tailscale-exit-node`, `tor-relay`), generated from `modules/platforms/*`
|
||||
and `modules/build-types/*` by the `mkTarget` function in `flake.nix`. Not
|
||||
every combination is built — `pxe-boot` has no `linode` variant. See
|
||||
`README.md` for the full current target list; treat `flake.nix` as the
|
||||
source of truth since this list can drift.
|
||||
(platforms: `linode`, `proxmox`, `lxc`, `baremetal`; build types: `minimal`,
|
||||
`nix-cache`, `server`, `docker`, `gui`, `pxe-boot`, `tailscale-router`,
|
||||
`tor-relay`, `ha-server`), generated from `modules/platforms/*` and
|
||||
`modules/build-types/*` by the `mkTarget` function in `flake.nix`. Not every
|
||||
combination is built — `pxe-boot` has no `linode` variant, `ha-server` only
|
||||
exists on `proxmox`, and `tor-relay` only exists on `lxc`. See `README.md`
|
||||
for the full current target list; treat `flake.nix` as the source of truth
|
||||
since this list can drift.
|
||||
|
||||
Do not deploy, switch, reboot, repartition, format disks, or run destructive
|
||||
install commands from this repository unless explicitly asked.
|
||||
|
||||
@@ -10,13 +10,13 @@ pieces composed in `flake.nix`:
|
||||
|
||||
- **Platforms** (what it runs on): `linode`, `proxmox`, `lxc`, `baremetal`
|
||||
- **Build types** (what it's for): `minimal`, `nix-cache`, `server`, `docker`,
|
||||
`gui`, `pxe-boot`, `tailscale-exit-node`, `tor-relay`
|
||||
`gui`, `pxe-boot`, `tailscale-router`, `tor-relay`, `ha-server`
|
||||
|
||||
Not every combination exists — `pxe-boot` has no `linode` variant, since
|
||||
PXE/DHCP/TFTP need LAN L2 adjacency that a Linode VPS doesn't have,
|
||||
`tor-relay` currently only exists as `lxc-tor-relay`, and `baremetal`
|
||||
currently only exists as `baremetal-gui` (the real gui-host hardware). The
|
||||
full list:
|
||||
`tor-relay` and `ha-server` currently only exist on `lxc`/`proxmox`, and
|
||||
`baremetal` currently only exists as `baremetal-gui` (the real gui-host
|
||||
hardware). The full list:
|
||||
|
||||
| Target | Purpose |
|
||||
| --- | --- |
|
||||
@@ -29,8 +29,9 @@ full list:
|
||||
| `linode-gui` / `proxmox-gui` / `lxc-gui` | Cinnamon desktop workstation — previously the flat `nixos` target |
|
||||
| `baremetal-gui` | Same Cinnamon desktop workstation, on the real gui-host hardware — ZFS RAID0 root, systemd-boot |
|
||||
| `proxmox-pxe-boot` / `lxc-pxe-boot` | HTTP/iPXE boot asset host — previously the flat `pxe-boot` target |
|
||||
| `linode-tailscale-exit-node` / `proxmox-tailscale-exit-node` / `lxc-tailscale-exit-node` | Tailscale exit node |
|
||||
| `linode-tailscale-router` / `proxmox-tailscale-router` / `lxc-tailscale-router` | Tailscale subnet router + MagicDNS forwarder for the LAN |
|
||||
| `lxc-tor-relay` | Tor middle relay |
|
||||
| `proxmox-ha-server-1` / `proxmox-ha-server-2` | HA file-server cluster nodes — DRBD + XFS + iSCSI + NFS, managed by Corosync + Pacemaker |
|
||||
|
||||
Which variant of a given buildtype is actually deployed isn't tracked
|
||||
anywhere in this repo — that's live infrastructure state, not something a
|
||||
@@ -47,8 +48,7 @@ section for which is which.
|
||||
|
||||
Each buildtype's `hosts/<name>/host.nix` carries the per-machine identity
|
||||
(hostname, hostId, per-machine secrets, `system.stateVersion`) that must stay
|
||||
fixed regardless of which platform it's built for — see
|
||||
`flake-target-refactor-spec.md` for the full rationale. Every deployed host
|
||||
fixed regardless of which platform it's built for. Every deployed host
|
||||
stamps its own active target name into `/etc/flake-target` at build time, so
|
||||
`nixos-rebuild switch --flake .#$(cat /etc/flake-target)` always picks up the
|
||||
right one even after a platform migration changes the flake attribute name.
|
||||
@@ -167,7 +167,6 @@ per-boot host key for sops-nix to derive from on ephemeral media) — see
|
||||
(`vars/per-machine/<target>/openssh/`, committed and sops-encrypted) for
|
||||
their SSH host keys.
|
||||
|
||||
This repository's git *history* still contains secrets committed before this
|
||||
migration (see `remove-sensetive-info-refactor.md`) — those are being
|
||||
scrubbed and rotated separately; don't treat the repo as safe to make public
|
||||
until that's finished.
|
||||
This repository's git *history* still contains secrets committed before the
|
||||
sops-nix migration — those are being scrubbed and rotated separately; don't
|
||||
treat the repo as safe to make public until that's finished.
|
||||
|
||||
@@ -22,7 +22,7 @@ see "LXC hosts" immediately below for why those are different.**
|
||||
## LXC hosts
|
||||
|
||||
`lxc-*` targets (`lxc-minimal`, `lxc-nix-cache`, `lxc-server`, `lxc-docker`,
|
||||
`lxc-gui`, `lxc-pxe-boot`, `lxc-tailscale-exit-node`, `lxc-tor-relay`) are **not** installed via `auto-install.sh` — the
|
||||
`lxc-gui`, `lxc-pxe-boot`, `lxc-tailscale-router`, `lxc-tor-relay`) are **not** installed via `auto-install.sh` — the
|
||||
interactive menu deliberately excludes them. Don't try to select one there;
|
||||
`nixos-install` would bind-mount `/` onto `/mnt` (LXC containers have no raw
|
||||
disk to partition) and then refuse to touch the filesystem it's currently
|
||||
@@ -133,13 +133,15 @@ Flake outputs:
|
||||
```nix
|
||||
nixosConfigurations.installer # ISO/netboot installer image
|
||||
|
||||
packages.x86_64-linux.iso # installer ISO/netboot image
|
||||
packages.x86_64-linux.pxe # netboot-ipxe + netboot-initrd + netboot-kernel, bundled
|
||||
packages.x86_64-linux.iso # installer ISO/netboot image
|
||||
packages.x86_64-linux.pxe # auto-installer netboot bundle (kernel + initrd + ipxe script)
|
||||
packages.x86_64-linux.pxe-minimal # vanilla NixOS minimal netboot bundle (no installer wiring)
|
||||
```
|
||||
|
||||
```sh
|
||||
nix build .#iso
|
||||
nix build .#pxe
|
||||
nix build .#pxe-minimal
|
||||
```
|
||||
|
||||
There's no `nixosConfigurations.proxmox-lxc` (installer-boots-as-an-LXC-
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
};
|
||||
boot.zfs.forceImportRoot = false;
|
||||
|
||||
# Only advertise the LAN interface to IPA DNS. Without this, SSSD registers
|
||||
# every Docker bridge (172.x.x.x) as an A record for docker.sweet.home —
|
||||
# the default dyndns.interface = "*" catches them all.
|
||||
security.ipa.dyndns.interface = vars.lxcLanInterface; # eth0
|
||||
|
||||
# Preserved from the pre-refactor `docker` target — stateVersion must never
|
||||
# be bumped on an already-installed machine.
|
||||
system.stateVersion = "25.05";
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
};
|
||||
|
||||
services.beszel.agent.environment = {
|
||||
#DOCKER_HOST = "tcp://docker-socket-proxy:2375";
|
||||
KEY = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFPR9kwtC4TAeTRu46A7+opZsYpxqkRJ+x/ZyB2GWCeG";
|
||||
};
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
};
|
||||
|
||||
services.beszel.agent.environment = {
|
||||
#DOCKER_HOST = "tcp://docker-socket-proxy:2375";
|
||||
KEY = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFPR9kwtC4TAeTRu46A7+opZsYpxqkRJ+x/ZyB2GWCeG";
|
||||
EXTRA_FILESYSTEMS = "${vars.storageRoot}/${vars.nfsShares.dockerVolumes.subpath}";
|
||||
LOG_LEVEL = "debug";
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
];
|
||||
|
||||
users.users.${vars.primaryUser}.extraGroups = [ "docker" ];
|
||||
# Grant the IPA domain user docker access via the local group so that
|
||||
# `wayne` can manage containers without sudo.
|
||||
users.groups.docker.members = [ "wayne" ];
|
||||
services.openssh.settings.PermitRootLogin = "yes";
|
||||
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
|
||||
@@ -15,6 +15,16 @@
|
||||
# under services.beszel.agent.environment.KEY once the hub accepts the
|
||||
# new agents, following the pattern in hosts/server/host.nix.
|
||||
{ lib, vars, ... }:
|
||||
|
||||
let
|
||||
# Generates /etc/exports lines for all nfsShares data entries. Shared
|
||||
# pattern with modules/build-types/server.nix — both export the same
|
||||
# set of shares, differing only in the storage root they serve from.
|
||||
mkNfsExports = storageRoot:
|
||||
lib.concatMapStrings
|
||||
(share: " ${storageRoot}/${share.subpath} ${vars.lanCidr}${vars.nfsShares.options}\n")
|
||||
(lib.filter builtins.isAttrs (lib.attrValues vars.nfsShares));
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
../ha/pacemaker-stack.nix
|
||||
@@ -25,16 +35,7 @@
|
||||
|
||||
services.nfs.server = {
|
||||
enable = true;
|
||||
exports = ''
|
||||
${vars.haStorageRoot}/${vars.nfsShares.dockerConfig.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
||||
${vars.haStorageRoot}/${vars.nfsShares.dockerVolumes.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
||||
${vars.haStorageRoot}/${vars.nfsShares.dockerDatabases.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
||||
${vars.haStorageRoot}/${vars.nfsShares.nextcloudData.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
||||
${vars.haStorageRoot}/${vars.nfsShares.raspiVolumes.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
||||
${vars.haStorageRoot}/${vars.nfsShares.proxmoxIsos.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
||||
${vars.haStorageRoot}/${vars.nfsShares.proxmoxLxcImages.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
||||
${vars.haStorageRoot}/${vars.nfsShares.pxebootImages.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
||||
'';
|
||||
exports = mkNfsExports vars.haStorageRoot;
|
||||
};
|
||||
|
||||
# Pacemaker controls nfs-server — prevent systemd from starting it at boot
|
||||
|
||||
@@ -13,6 +13,15 @@ let
|
||||
lib.concatMap (share: ancestors share.subpath)
|
||||
(lib.filter builtins.isAttrs (lib.attrValues vars.nfsShares))
|
||||
);
|
||||
|
||||
# Generates /etc/exports lines for all nfsShares data entries (every
|
||||
# attrset value — excludes the bare `options` string). Both server and
|
||||
# ha-server export the same share set from different storage roots, so
|
||||
# this helper is the single source of truth for the export line format.
|
||||
mkNfsExports = storageRoot:
|
||||
lib.concatMapStrings
|
||||
(share: " ${storageRoot}/${share.subpath} ${vars.lanCidr}${vars.nfsShares.options}\n")
|
||||
(lib.filter builtins.isAttrs (lib.attrValues vars.nfsShares));
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
@@ -95,16 +104,7 @@ in
|
||||
|
||||
services.nfs.server = {
|
||||
enable = true;
|
||||
exports = ''
|
||||
${vars.storageRoot}/${vars.nfsShares.dockerConfig.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
||||
${vars.storageRoot}/${vars.nfsShares.dockerVolumes.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
||||
${vars.storageRoot}/${vars.nfsShares.dockerDatabases.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
||||
${vars.storageRoot}/${vars.nfsShares.nextcloudData.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
||||
${vars.storageRoot}/${vars.nfsShares.raspiVolumes.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
||||
${vars.storageRoot}/${vars.nfsShares.proxmoxIsos.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
||||
${vars.storageRoot}/${vars.nfsShares.proxmoxLxcImages.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
||||
${vars.storageRoot}/${vars.nfsShares.pxebootImages.subpath} ${vars.lanCidr}${vars.nfsShares.options}
|
||||
'';
|
||||
exports = mkNfsExports vars.storageRoot;
|
||||
};
|
||||
|
||||
# mountd (20048) is needed for showmount/NFSv3 mount protocol — without it
|
||||
|
||||
@@ -1,50 +1,7 @@
|
||||
{ config, pkgs, lib, vars, ... }:
|
||||
_:
|
||||
|
||||
let
|
||||
# Flake attribute names are now <platform>-<buildtype> (e.g. proxmox-docker)
|
||||
# and no longer match networking.hostName, since a host's hostname stays
|
||||
# fixed while the platform backing it can change. Each nixosConfiguration
|
||||
# stamps its own active target name into /etc/flake-target at build time.
|
||||
mySwitchCmd = ''
|
||||
sudo nixos-rebuild switch \
|
||||
--no-write-lock-file \
|
||||
--refresh \
|
||||
--flake git+https://${vars.lanDomain}/beatzaplenty/nixos.git#$(cat /etc/flake-target)
|
||||
'';
|
||||
myTestCmd = ''
|
||||
sudo nixos-rebuild test \
|
||||
--no-write-lock-file \
|
||||
--refresh \
|
||||
--flake git+https://${vars.lanDomain}/beatzaplenty/nixos.git#$(cat /etc/flake-target)
|
||||
'';
|
||||
|
||||
# lxc-* hosts pre-seed their SSH host key at build time (see
|
||||
# modules/platforms/lxc.nix) so sops-nix's .sops.yaml recipient matches on
|
||||
# first boot -- without it, secrets permanently fail to decrypt (see that
|
||||
# file's comment for the confirmed failure). That requires --impure plus
|
||||
# NIXOS_HOST_KEYS_DIR pointing at the repo's host-keys/ dir, same pattern
|
||||
# docs/auto-installer.md uses for the installer ISO. A function, not a
|
||||
# shellAlias, since the target name has to interpolate into the middle of
|
||||
# the flake attribute path, not just append after it. Must be run from the
|
||||
# repo root, same as every other host-keys/ command in this repo.
|
||||
buildImageFn = ''
|
||||
buildImage() {
|
||||
if [ -z "$1" ]; then
|
||||
echo "usage: buildImage <flake-target> (e.g. lxc-docker)" >&2
|
||||
return 1
|
||||
fi
|
||||
NIXOS_HOST_KEYS_DIR="$(pwd)/host-keys" nix build --impure \
|
||||
".#nixosConfigurations.$1.config.system.build.tarball"
|
||||
}
|
||||
'';
|
||||
in
|
||||
{
|
||||
programs.bash = {
|
||||
enable = true;
|
||||
shellAliases = {
|
||||
"Switch-nix" = mySwitchCmd;
|
||||
"Test-nix" = myTestCmd;
|
||||
};
|
||||
initExtra = buildImageFn;
|
||||
};
|
||||
# Switch-nix, Test-nix, and buildImage are defined system-wide in
|
||||
# modules/common/configuration.nix so all users (including IPA accounts)
|
||||
# get them. Add any Home-Manager-only per-user shell config here.
|
||||
}
|
||||
|
||||
@@ -1,18 +1,45 @@
|
||||
{ config, lib, pkgs, vars, ... }:
|
||||
|
||||
let
|
||||
switchCmd = ''
|
||||
sudo nixos-rebuild switch \
|
||||
--no-write-lock-file \
|
||||
--refresh \
|
||||
--flake git+https://${vars.lanDomain}/beatzaplenty/nixos.git#$(cat /etc/flake-target)
|
||||
'';
|
||||
testCmd = ''
|
||||
sudo nixos-rebuild test \
|
||||
--no-write-lock-file \
|
||||
--refresh \
|
||||
--flake git+https://${vars.lanDomain}/beatzaplenty/nixos.git#$(cat /etc/flake-target)
|
||||
'';
|
||||
buildImageFn = ''
|
||||
buildImage() {
|
||||
if [ -z "$1" ]; then
|
||||
echo "usage: buildImage <flake-target> (e.g. lxc-docker)" >&2
|
||||
return 1
|
||||
fi
|
||||
NIXOS_HOST_KEYS_DIR="$(pwd)/host-keys" nix build --impure \
|
||||
".#nixosConfigurations.$1.config.system.build.tarball"
|
||||
}
|
||||
'';
|
||||
in
|
||||
{
|
||||
imports =
|
||||
[
|
||||
# Include the results of the hardware scan.
|
||||
# ./hardware-configuration.nix
|
||||
./set-locale.nix
|
||||
../ipa/client.nix
|
||||
];
|
||||
# Use the GRUB 2 boot loader.
|
||||
# boot.loader.grub.enable = true;
|
||||
#boot.loader.grub.device = "/dev/sda"; # or "nodev" for efi only
|
||||
imports = [
|
||||
./set-locale.nix
|
||||
../ipa/client.nix
|
||||
];
|
||||
|
||||
networking.networkmanager.enable = true; # Easiest to use and most distros use this by default.
|
||||
# System-wide shell config so all users (including IPA accounts) get the
|
||||
# same management aliases as the local nixos user's Home Manager provides.
|
||||
programs.bash = {
|
||||
shellAliases = {
|
||||
"Switch-nix" = switchCmd;
|
||||
"Test-nix" = testCmd;
|
||||
};
|
||||
interactiveShellInit = buildImageFn;
|
||||
};
|
||||
networking.networkmanager.enable = true;
|
||||
|
||||
# Recommended over the true default (bypasses ZFS's own import safeguards)
|
||||
# per the option's own docs; matches hosts/docker/host.nix and
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# Shared activation-script logic to preserve the SSH host key across
|
||||
# nixos-rebuild on platforms that embed the key via environment.etc (lxc and
|
||||
# proxmox). When NIXOS_HOST_KEYS_DIR is not set the key is absent from
|
||||
# environment.etc, and NixOS's etc activation removes any /etc file not in
|
||||
# the new generation — which would destroy the live key and break sops-nix
|
||||
# decryption permanently. These scripts save the key to /run before etc
|
||||
# removes it, then restore it afterward.
|
||||
#
|
||||
# Explicit deps enforce the correct ordering: without them the topological
|
||||
# sort places preserveSshHostKey after etc (confirmed live on lxc-tor-relay:
|
||||
# position 7 vs etc's position 5), so the key is gone before it can be saved.
|
||||
_: {
|
||||
system.activationScripts = {
|
||||
preserveSshHostKey = ''
|
||||
if [ -f /etc/ssh/ssh_host_ed25519_key ]; then
|
||||
cp /etc/ssh/ssh_host_ed25519_key /run/sshd-host-key-preserve.tmp
|
||||
cp /etc/ssh/ssh_host_ed25519_key.pub /run/sshd-host-key-preserve.pub.tmp
|
||||
fi
|
||||
'';
|
||||
|
||||
restoreSshHostKey = {
|
||||
deps = [ "etc" ];
|
||||
text = ''
|
||||
if [ ! -f /etc/ssh/ssh_host_ed25519_key ] && [ -f /run/sshd-host-key-preserve.tmp ]; then
|
||||
install -m 0600 /run/sshd-host-key-preserve.tmp /etc/ssh/ssh_host_ed25519_key
|
||||
install -m 0644 /run/sshd-host-key-preserve.pub.tmp /etc/ssh/ssh_host_ed25519_key.pub
|
||||
fi
|
||||
rm -f /run/sshd-host-key-preserve.tmp /run/sshd-host-key-preserve.pub.tmp
|
||||
'';
|
||||
};
|
||||
|
||||
etc = { deps = [ "preserveSshHostKey" ]; };
|
||||
setupSecrets = { deps = [ "restoreSshHostKey" ]; };
|
||||
};
|
||||
}
|
||||
@@ -1,19 +1,9 @@
|
||||
{ pkgs, vars, ... }:
|
||||
|
||||
{
|
||||
# virtualisation.docker.enable = true;
|
||||
virtualisation.docker = {
|
||||
enable = true;
|
||||
package = pkgs.docker;
|
||||
# listenOptions = [
|
||||
# "unix:///var/run/docker.sock"
|
||||
# "tcp://0.0.0.0:2375"
|
||||
#];
|
||||
|
||||
# daemon.settings = {
|
||||
# metrics-addr = "0.0.0.0:9323";
|
||||
# experimental = true;
|
||||
# };
|
||||
};
|
||||
users.users.${vars.primaryUser}.extraGroups = [ "docker" ];
|
||||
environment.systemPackages = with pkgs; [
|
||||
|
||||
+102
-3
@@ -19,7 +19,7 @@
|
||||
# sops -e --input-type binary -i secrets/<host>.keytab
|
||||
# d. Commit secrets/<host>.keytab and the updated .sops.yaml, then deploy.
|
||||
#
|
||||
# vars dependencies: homeDomain, ipaServer, domainControllerIp
|
||||
# vars dependencies: homeDomain, ipaServer, domainControllerIp, ipaUser
|
||||
|
||||
{ config, lib, pkgs, vars, ... }:
|
||||
|
||||
@@ -41,10 +41,10 @@ lib.mkIf enabled {
|
||||
security.ipa = {
|
||||
enable = true;
|
||||
domain = vars.homeDomain;
|
||||
realm = realm;
|
||||
inherit realm;
|
||||
server = vars.ipaServer;
|
||||
certificate = caCertPkg;
|
||||
basedn = basedn;
|
||||
inherit basedn;
|
||||
ipaHostname = fqdn;
|
||||
offlinePasswords = true;
|
||||
cacheCredentials = true;
|
||||
@@ -62,6 +62,11 @@ lib.mkIf enabled {
|
||||
"d /usr/local 0755 root root - -"
|
||||
"d /usr/local/bin 0755 root root - -"
|
||||
"C+ /usr/local/bin/sss_ssh_authorizedkeys 0555 root root - ${pkgs.sssd}/bin/sss_ssh_authorizedkeys"
|
||||
# Pre-create the IPA user's home dir so Home Manager activation succeeds
|
||||
# even before their first login. On a fresh system SSSD may not have
|
||||
# resolved the user yet — tmpfiles warns and skips in that case (non-fatal),
|
||||
# and pam_mkhomedir covers the first-login path as a fallback.
|
||||
"d /home/${vars.ipaUser} 0700 ${vars.ipaUser} ${vars.ipaUser} - -"
|
||||
];
|
||||
|
||||
services.openssh.extraConfig = ''
|
||||
@@ -86,4 +91,98 @@ lib.mkIf enabled {
|
||||
mode = "0600";
|
||||
restartUnits = [ "sssd.service" ];
|
||||
};
|
||||
|
||||
# security.ipa enables Kerberos (security.krb5) which causes systemd to
|
||||
# start auth-rpcgss-module.service and rpc-gssd.service for Kerberos NFS
|
||||
# authentication. LXC containers can't load the auth_rpcgss kernel module
|
||||
# and don't have /var/lib/nfs/rpc_pipefs, so both services fail.
|
||||
#
|
||||
# The NixOS IPA module already adds a drop-in for auth-rpcgss-module.service
|
||||
# with ConditionPathExists=/etc/krb5.keytab. We use lib.mkForce to win the
|
||||
# text conflict and add ConditionVirtualization=!container alongside it so
|
||||
# the service is skipped (not failed) in containers that do have a keytab.
|
||||
# Same fix for rpc-gssd.service which also fails in containers.
|
||||
systemd.units = lib.mkIf config.boot.isContainer {
|
||||
"auth-rpcgss-module.service" = {
|
||||
overrideStrategy = "asDropinIfExists";
|
||||
text = lib.mkForce ''
|
||||
[Unit]
|
||||
ConditionPathExists=
|
||||
ConditionPathExists=/etc/krb5.keytab
|
||||
ConditionVirtualization=!container
|
||||
'';
|
||||
};
|
||||
# rpc-gssd also has ConditionPathExists from the NixOS IPA module (and an
|
||||
# X-Restart-Triggers store path from systemd.nix). Use mkForce to win;
|
||||
# omit X-Restart-Triggers since this service is skipped in containers anyway.
|
||||
"rpc-gssd.service" = {
|
||||
overrideStrategy = "asDropinIfExists";
|
||||
text = lib.mkForce ''
|
||||
[Unit]
|
||||
ConditionPathExists=
|
||||
ConditionPathExists=/etc/krb5.keytab
|
||||
ConditionVirtualization=!container
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
# Home Manager config for the IPA primary user, applied on every enrolled
|
||||
# host. Manages what IPA doesn't: dotfiles, user-scoped packages, session
|
||||
# variables. Switch-nix/Test-nix/buildImage are system-wide (configuration.nix)
|
||||
# so they don't need to be repeated here.
|
||||
# NixOS requires isNormalUser/isSystemUser + group on any entry in
|
||||
# users.users. HM with useUserPackages = true (set in flake.nix) adds a stub
|
||||
# entry for each HM user so it can install packages to
|
||||
# /etc/profiles/per-user/<name>/. This definition satisfies those assertions.
|
||||
# With security.ipa setting "passwd: sss files" in nsswitch, SSSD's IPA entry
|
||||
# takes priority for NSS lookups — this local stub is only a fallback when
|
||||
# SSSD is unreachable (at which point auth fails anyway).
|
||||
# HM with useUserPackages = true (flake.nix) sets users.users.${ipaUser}.packages,
|
||||
# which forces the stub into /etc/passwd. pam_sss.so with the "localusers" flag
|
||||
# (added by NixOS when SSSD is enabled) then skips SSSD for any user it finds in
|
||||
# local /etc/passwd — including this stub — falling through to pam_unix, which has
|
||||
# no password for the stub → sudo auth always fails.
|
||||
#
|
||||
# Fix: NOPASSWD for the IPA user. The IPA user already authenticated to reach a
|
||||
# shell (SSH public key from IPA or Kerberos), so re-prompting via a broken PAM
|
||||
# path is security theater on a single-admin homelab.
|
||||
users.users.${vars.ipaUser} = {
|
||||
isNormalUser = true;
|
||||
group = "users";
|
||||
extraGroups = [ "wheel" ];
|
||||
createHome = false;
|
||||
};
|
||||
|
||||
# home-manager-<user>.service fails on first enrollment because /home/wayne
|
||||
# doesn't exist until the user's first login (pam_mkhomedir creates it then).
|
||||
# ConditionPathExists makes systemd skip the service (exit 0, condition not
|
||||
# met) instead of failing. After first login the dir exists and subsequent
|
||||
# rebuilds activate HM normally.
|
||||
systemd.services."home-manager-${vars.ipaUser}".unitConfig.ConditionPathExists =
|
||||
"/home/${vars.ipaUser}";
|
||||
|
||||
security.sudo.extraRules = [{
|
||||
users = [ vars.ipaUser ];
|
||||
commands = [{ command = "ALL"; options = [ "NOPASSWD" ]; }];
|
||||
}];
|
||||
|
||||
# Home Manager config for the IPA primary user, applied on every enrolled
|
||||
# host. Manages what IPA doesn't: dotfiles, user-scoped packages, session
|
||||
# variables. Switch-nix/Test-nix/buildImage are system-wide (configuration.nix)
|
||||
# so they don't need to be repeated here.
|
||||
#
|
||||
# homeDirectory uses mkForce because HM's NixOS integration module sets it to
|
||||
# "/var/empty" for users not found in config.users.users at eval time (SSSD
|
||||
# users aren't visible there).
|
||||
home-manager.users.${vars.ipaUser} = { pkgs, ... }: {
|
||||
home = {
|
||||
username = vars.ipaUser;
|
||||
homeDirectory = lib.mkForce "/home/${vars.ipaUser}";
|
||||
stateVersion = "26.05";
|
||||
packages = with pkgs; [ tmux sshfs ];
|
||||
sessionVariables.EDITOR = "nano";
|
||||
};
|
||||
programs.home-manager.enable = true;
|
||||
programs.bash.enable = true;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ in
|
||||
# LXC container does).
|
||||
imports = [
|
||||
(modulesPath + "/virtualisation/proxmox-lxc.nix")
|
||||
../common/preserve-ssh-host-key.nix
|
||||
];
|
||||
|
||||
proxmoxLXC = {
|
||||
@@ -105,49 +106,6 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
# NixOS's etc activation removes any /etc file that was in the previous
|
||||
# generation's environment.etc but is absent from the current one — even
|
||||
# real (non-symlink) copies. On every routine nixos-rebuild switch/test that
|
||||
# lacks NIXOS_HOST_KEYS_DIR the key is absent from environment.etc, so it
|
||||
# gets removed as "obsolete". sops-nix derives its age decryption key from
|
||||
# /etc/ssh/ssh_host_ed25519_key; deletion cascades into every sops secret
|
||||
# failing with "Error getting data key: 0 successful groups required, got 0".
|
||||
#
|
||||
# Fix: activation scripts that bracket the etc step, with explicit deps
|
||||
# to enforce the correct ordering. Without deps the topological sort places
|
||||
# preserveSshHostKey AFTER etc (confirmed live on a deployed lxc-tor-relay:
|
||||
# position 7 vs etc's position 5) -- the key is already gone by the time it
|
||||
# tries to save it. The etc/setupSecrets entries ADD to existing deps
|
||||
# (types.listOf concatenates across module definitions).
|
||||
system.activationScripts = {
|
||||
# Saves the live key to /run before etc can delete it.
|
||||
preserveSshHostKey = ''
|
||||
if [ -f /etc/ssh/ssh_host_ed25519_key ]; then
|
||||
cp /etc/ssh/ssh_host_ed25519_key /run/sshd-host-key-preserve.tmp
|
||||
cp /etc/ssh/ssh_host_ed25519_key.pub /run/sshd-host-key-preserve.pub.tmp
|
||||
fi
|
||||
'';
|
||||
|
||||
# Reinstalls the key after etc runs if it was removed as "obsolete".
|
||||
# The resulting file is not registered in environment.etc for either
|
||||
# generation, so subsequent rebuilds leave it alone permanently.
|
||||
restoreSshHostKey = {
|
||||
deps = [ "etc" ];
|
||||
text = ''
|
||||
if [ ! -f /etc/ssh/ssh_host_ed25519_key ] && [ -f /run/sshd-host-key-preserve.tmp ]; then
|
||||
install -m 0600 /run/sshd-host-key-preserve.tmp /etc/ssh/ssh_host_ed25519_key
|
||||
install -m 0644 /run/sshd-host-key-preserve.pub.tmp /etc/ssh/ssh_host_ed25519_key.pub
|
||||
fi
|
||||
rm -f /run/sshd-host-key-preserve.tmp /run/sshd-host-key-preserve.pub.tmp
|
||||
'';
|
||||
};
|
||||
|
||||
# Force etc to wait until the key is saved, and sops to wait until the
|
||||
# key is restored. Without these the topological sort breaks the chain.
|
||||
etc = { deps = [ "preserveSshHostKey" ]; };
|
||||
setupSecrets = { deps = [ "restoreSshHostKey" ]; };
|
||||
};
|
||||
|
||||
# virtualisation/proxmox-lxc.nix (imported above) registers the Nix
|
||||
# store DB via a systemd service (register-nix-paths) -- it never runs
|
||||
# an activation script at all. Confirmed live this means neither
|
||||
|
||||
@@ -34,6 +34,7 @@ in
|
||||
../hardware-configuration/vm/proxmox.nix
|
||||
../boot/efi.nix
|
||||
../disko/proxmox.nix
|
||||
../common/preserve-ssh-host-key.nix
|
||||
];
|
||||
|
||||
environment.etc = lib.mkIf hasKeyForThisTarget {
|
||||
@@ -46,36 +47,4 @@ in
|
||||
mode = "0644";
|
||||
};
|
||||
};
|
||||
|
||||
# NixOS's etc activation removes any /etc file that was in the previous
|
||||
# generation's environment.etc but is absent from the current one. Since
|
||||
# the SSH key is only in environment.etc during the --impure build (when
|
||||
# NIXOS_HOST_KEYS_DIR is set), normal rebuilds would remove it as
|
||||
# "obsolete". These scripts mirror lxc.nix's approach: save the live key
|
||||
# before etc runs, restore it after. Without the explicit deps, the
|
||||
# topological sort places preserveSshHostKey after etc (confirmed live on
|
||||
# lxc-tor-relay: position 7 vs etc's position 5), so the key is gone
|
||||
# before it can be saved.
|
||||
system.activationScripts = {
|
||||
preserveSshHostKey = ''
|
||||
if [ -f /etc/ssh/ssh_host_ed25519_key ]; then
|
||||
cp /etc/ssh/ssh_host_ed25519_key /run/sshd-host-key-preserve.tmp
|
||||
cp /etc/ssh/ssh_host_ed25519_key.pub /run/sshd-host-key-preserve.pub.tmp
|
||||
fi
|
||||
'';
|
||||
|
||||
restoreSshHostKey = {
|
||||
deps = [ "etc" ];
|
||||
text = ''
|
||||
if [ ! -f /etc/ssh/ssh_host_ed25519_key ] && [ -f /run/sshd-host-key-preserve.tmp ]; then
|
||||
install -m 0600 /run/sshd-host-key-preserve.tmp /etc/ssh/ssh_host_ed25519_key
|
||||
install -m 0644 /run/sshd-host-key-preserve.pub.tmp /etc/ssh/ssh_host_ed25519_key.pub
|
||||
fi
|
||||
rm -f /run/sshd-host-key-preserve.tmp /run/sshd-host-key-preserve.pub.tmp
|
||||
'';
|
||||
};
|
||||
|
||||
etc = { deps = [ "preserveSshHostKey" ]; };
|
||||
setupSecrets = { deps = [ "restoreSshHostKey" ]; };
|
||||
};
|
||||
}
|
||||
|
||||
@@ -81,6 +81,14 @@ if [[ -z "${TARGET}" ]]; then
|
||||
usage 1
|
||||
fi
|
||||
|
||||
# Reject FQDNs passed by mistake — the script appends HOME_DOMAIN itself.
|
||||
# "nixos.sweet.home" → FQDN would become "nixos.sweet.home.sweet.home".
|
||||
if [[ "${TARGET}" == *"."* ]]; then
|
||||
echo "Error: <hostname> must be the short name (e.g. 'nixos'), not a FQDN." >&2
|
||||
echo " The FQDN is derived automatically as ${TARGET}.${HOME_DOMAIN}." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
FQDN="${TARGET}.${HOME_DOMAIN}"
|
||||
KEYTAB_SECRET="${REPO_ROOT}/secrets/${TARGET}.keytab"
|
||||
# Temp path on the domain controller — use a name that won't collide.
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data://9IEHIVCfHjyMNao5sCu2zNlZ/CaW+JyxVpGpD/vab2qvURunCUY7eMfSOyvOx/2WPXnWWlkoVJPCR1ec/yUg09EaSMfxrvqlu4UJI3Sxvu9xNuDszMwMMD/sCulJDiMWFNLp8qaYt7UGzexp4+GlGiqWDxk3ZEu/iLmSApzBrpciTF0lfehT4qblDovo9QXG2KDWFhCt2SwEKmHJ61Yl3pVAQnPLyTWaNhwWD/mYL76mIiDVKq7DJlvi9MBxzi3aYh/ttuHgRCvnCL0C9oUvOyT2cljwra0LXuOrum7FhPIXXboA7WTEbTHJm1LB5yLfxDrnWCrGxQzFQAwNixVHIcjuvjjvA/LifTvbj5FYM8x7an+DwXPfPhruFrDew1paAWsEGNNYXSmAlju2QLI/OwLHFFLuDyLnBKQ6RLtZbCEAOUKf2h4iZj7nH86eb/aGU=,iv:rj76+MJBCpiYyx2Ogut5UxJj3Gn+bygvu2mtuY5hFLA=,tag:yQmTvWVu8ZLug/7fo6RnwA==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqcURBS2tIMGl1aWxLMHFQ\nS3ZGVTE0cnYzTmpnQ0daL1F3QnlpemRCMmtjClJiZzIrc2syN29sRXVoaXlPRUNF\nakw4RndmbEduTFg5ZVRKUTVwRWpGRjgKLS0tIHZ5ZFlyODlGWTJoNGpXR3RhY0ZH\nOGpPdDZQVmt6UWZXbHkxQTBoeW1JencKbsfH1V1lUj8mmHyLNj36VaRDgaBojcDU\ndoQWmSEXxjticJqdadbVKb3UABpvzAZxASCy81sa3wH0gT+7zLaNyQ==\n-----END AGE ENCRYPTED FILE-----\n",
|
||||
"recipient": "age1njap586hc0q43kr03g6c8eqhdsmk8zcafkl3f83xwlc2gqhlmfgs4tmwad"
|
||||
},
|
||||
{
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBrbFdaMmRjcHgyV3Y0eWZL\neG1uMEtpQVUxQmNTU0Z3aC95Zi9uQlgvMEhRCmJiVlRTR2NocGlnbVU1UmlLVVA2\neERiMXpiQlVPNVhRU09XVGxrY0Ixa2sKLS0tIFRuOHdoelJxOXNRRHBJNnlhSE9j\nUUZHZmQzOVFwRmhFV3pvdnpRMTMraGcKRHBuSUpbHaEzH2tuSBE5MsLJDCuH3vUx\nO0jnDldCWkCw7Wvr/tQAkaDI8axZcYVDUkCEk+xqAdxDozLCPhEO6g==\n-----END AGE ENCRYPTED FILE-----\n",
|
||||
"recipient": "age17e89ty6p0fw24daanen57wg8uald9s025t3wwxsw269svwpmgvrshfvfvt"
|
||||
},
|
||||
{
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBZMW5taXh2QkJkT0JjaVpq\nQlBjVFpFYUhXTHhOT3prbFcvUFB0YnRGUzMwCjhHT01lY3dPWDE2dDZWZnJza1hN\nS1AvZWIvdjZoYmRjWlliK1hiOEdrT00KLS0tIDljWWY0NlQveS9VR2hOSUNyTUtH\nK2gvbEVibmZSdktPemdEQ2p5U0Y4d2MKKitoTi2vbxJ41IoWMlj4vO91Ahpj0hHP\nrKCPyx7ws/IUMmKGyvDLpZ3pYqHD9jl5pLfB05Hh4Emhv4lA1qtwwQ==\n-----END AGE ENCRYPTED FILE-----\n",
|
||||
"recipient": "age17jqc66x9yeshfgd9v78mj483r4zzarqdtuxtrkxe4x5mw679gphshd94th"
|
||||
},
|
||||
{
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3K2dVV1BHbDk2Z3FhNmdV\nZEN2Um94K0pma1k4b1V5ZUJxQ1hWU1grZjJNCi9iRVVqOVpEMmtBUi80NThlYldY\nTUtZOVErT2VSWk43NndpVzBlL1lQaTgKLS0tIEpCM3Q4NjM3N1lpUE56N04rTXN0\nZkZ6TkV1TU9OV3dpc25RNWRpVnprM00KItUzKBdShakOfX8Sr+k906nsvYPl8QLb\nge//1GA+ukGsaS9rcChOY89vFdm61JDmj1jXSJ0CN4wLMW9/eblZRw==\n-----END AGE ENCRYPTED FILE-----\n",
|
||||
"recipient": "age1arhf2q45zw6wf2uevju4savp575x3m2tfvved5zzq3ay92ynua9s3cm92c"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2026-07-28T01:44:28Z",
|
||||
"mac": "ENC[AES256_GCM,data:efFXIqbauOURR7lrVpK7kqRIPgYjgWfenBYoX7mUrQ/thFc+ApcAx58Fi1zg4biwIs7NarJAgDqAxZi+yKb2Sll8H/wlsEjWDU4iQlLJdIQw7wey9eDW8pgBLd+6E7FXrgn1Vh49dS5GXlC6clAYk1lCiB4NvfzPDy5Ktpl+Chs=,iv:+zCqj5I1MLJfRRiIrqgocYB49PZnlV45PUTH4gYlfrQ=,tag:WxY1sF4kFOTEzbSFcfJFbQ==,type:str]",
|
||||
"version": "3.13.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data:apiijrtrqd77CTizITg0R35BfCi8PBnufpxIyC+hLYqwoBzP//3z/yjFyHPLG98m/c/qywoi3Kn+zsaTT7MjP++9OMhhX94YKlSHV1/cHB76OkwsNc+ClqWxl6vpaFX29Qvh3gFX9c/NR3xvYQutYwrIrQ9NR+t/M52IMC8hvtR1LQy0ak3VIuXJlSnG2r4kF2Ym1iP7phjuq39Gd245Axzw8OB7yGvOjNxSdTPxW/qL0fMlzNcMrjr9hw15WlqnZfWPOsB1+gZjHXpGfPD5BCbAAMoTRJd75vhKKXP/ERhIffewuuH2x/QHfSFvXVB3QyhBQMxd2b8QEEE5cjvcExOST3tkj6QARkzoUpRT7AE3jhl3XZ0uA2qu9SwyrSvbr0tBRKxCdK0g2E2/hqwcK/Tck5GB1eKb4aN+UkqxOblNDH+B1RfDoyNAuN+KEg==,iv:0p+ScrKpP4kQvO52gBAlwAis6oAzZ0EHFnU74hYPrn4=,tag:ON7qOjztF52xsJWAou7ogg==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlYXB3cVAzb2xEZ2pGa1RJ\nbS9ZVTc4Ums5eUZJUjEvd1g1aGVyNUNramowCnptZXFOZVB3MFRFcUtzSXBEZk1B\neEtKcDdLS0h0b1h3VjRjRXRvV3V5V3MKLS0tIHBDemkyUnV6ZXhTeE5VOVVOMlky\nWWMzVGVzZlAxMjZYUGpQUCs5QmxiYkkKcuBshCgWX4TwfVlQ5lHikzvwWdLEXWD1\n/uSiy0J6yMSiu8u6cg2SxeFrlKJ3j47dDlT6WHCxS0PfeEA0bJb3LA==\n-----END AGE ENCRYPTED FILE-----\n",
|
||||
"recipient": "age1njap586hc0q43kr03g6c8eqhdsmk8zcafkl3f83xwlc2gqhlmfgs4tmwad"
|
||||
},
|
||||
{
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGa2VTc2NWdkFRNUJxelVR\nWFk4RWxoelYzNHo1UFVhU2ZkLzEySlRWN2xNCmNmcmJod2crL3NMRlVsSmpmVkU2\nMjlXMktjc3piUVNhUXlTdnVGTWJkUTQKLS0tIGQrMUxrNDlNTkRCSUtFWkxRdXgw\nRlV4ZmtYSGhPQU84eWtiQXVqTmxUK3cKk5fn72UZPH68t5ZappfAhZJwzpLkfKmT\ny9TbUPIr4Pbrexau6YiH43QIbDQFdwYPfkBjGkd57zCg8AVo1+MBRw==\n-----END AGE ENCRYPTED FILE-----\n",
|
||||
"recipient": "age1adur9g330gua4l6ndk8cqjg35qc8yxwgme6wrl2hpylcc7vxm38q05ejuy"
|
||||
},
|
||||
{
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArNWkwQXFWT1RpaDNvbzYy\nQWc1aHhmNHFEUXVsQjZqb0EzM0wrV0dwN1hnCjFsUFJiT3REK05uSGRWTEw2SFE4\nY1FleE1XVjhBbndiMmZxTWNTYmhYeVEKLS0tIEJiZzJvS3BsYzB3cHIxa2k5N1Ro\nenFFZDVaODNnVGdBZTBOYWJwRjQzc1kKlXJgee8wTSN4Beq4P0t9cYbk0BWHCseQ\nyaWpiPT9aZBEGLFmuEd3zKABc8lrilX/ySTmOG49vRg6CPmr7cT0Wg==\n-----END AGE ENCRYPTED FILE-----\n",
|
||||
"recipient": "age1rrxqea6q6pn39sw8y5te63h2py8jgjl9v0jyper86w3ggtn67upqg3ah39"
|
||||
},
|
||||
{
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBEa0JYenFMNmNzWnVmcXdz\ndG90ZUZ0WWlIU0FCZG9OaWpBM3ZDWnFhZFhNCjhuV1FTOTJ2WVJGa2RuNVV2MjR0\naVNXa3diaWxWUlJtdkNOQXZ2R2NsQkUKLS0tIDcyYXh3N3B2QmNiK3dzemFFMGV1\nNTZpTk5yNGV5YVo3cGswK0NLWFQxQlEKIe0N5OxooWXzt1cUViBmjihmGEe3G6/f\nkz2/IscnG78ZvNgYKjdoG1jlsyje/3zI4C8aWXLq2DnIyxUyAhPgsQ==\n-----END AGE ENCRYPTED FILE-----\n",
|
||||
"recipient": "age19mn8zrxl8zpps9yvrh4euquvygpp4fp8queg7xc6qhtnl4ng8c9qx02qwn"
|
||||
},
|
||||
{
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2b0NVVm9QNm9waUUzcXBi\nWnZWU0JETjZRZmprZVRUL1h6ZHB4cXkrdm5rCm9GZ0VnTXB3S1BYSmlGWFJVcDhJ\naUl3RjR0ak9BRmQvVk1GRnQxNmtYM00KLS0tIFlTU1p2OHhWUGlOWngwbE56NEhF\nRW5QSkVVUWZpdDZXWEIxZ1BkbzVwclEK2P25nBgf8255vaKW/+T97aNTecRgNjLu\nedIUiPdXbFATCe3v/YRo6sqzFwIsvM6Bl9yHh/SXo6Ftc7eWZZd8zQ==\n-----END AGE ENCRYPTED FILE-----\n",
|
||||
"recipient": "age1hrx8qj02fj2ea6d4g9vqhyj9hl7fppkjqfdx2l37py3h6pdkr95s8n8rvs"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2026-07-28T01:44:24Z",
|
||||
"mac": "ENC[AES256_GCM,data:J0D8bEs5mHLraLS6TvYuCgfiNU1xKM2Yfb5Y0f/q/4wM4LzXufNzv3+SWDHumTe328U8UnNXLqjNHEKL0bZi0coxpU5hVM+BvPcmqD72vscETzbQ2hnU05sfW+XjfZhcN8/ke0bpLt7nP0crD5hsZv3esV1E2UWvzjEiYtWzFHY=,iv:lcmXYG2H469UKBYDndWKMO+GP0mSGLztenm+kBaUdYI=,tag:ujiXbLM9CUsuoFwQQWI84Q==,type:str]",
|
||||
"version": "3.13.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data:aqlMnoVkGtH9z3fJRweeC0OYf7LGqJU2sWA9Q25dKK6NuNyJd4BvjPtpfeg/WhVtJsaOtcbwVm4WAhVK9FARE8g8j+vmq0f6BAU4s6mx0ZIhl+mP+/hIpt//LOdd+9YezelJxdpzUyZbdAngU99rsTluLRe2XmZ7Fquxd8yH/OHenSDY6dizp9+5jfEi8EU+EmuXvuWMPY59xnlnqYNPfSFxs43/pS402LzJoJ5H+cBPprddkUBVzy4cBQvMnrRFUSjnqp74ovZkfIWFqDWQ5YgSU2PjatBg18oulZ7wNRhQ6OLqj6gsu+xrMjNFwnp7rMlA3X//hIidxTkVcYITycXd8KzuMIaofUpnwoyT34fy6+H35/39iiEyG4LRTrOOKRDzXkY2rhJUxFSZ8GlhNhMd0RlkmLngVYrtjsswJ9meIwoAFLPYt7BC61PJf0TXdtk=,iv:mCA819J9LpAOj8QxFAkrHI9wFJIy8qVxv31D6IwWFnk=,tag:qqMtM0eyHbQEyl6ND/wf7g==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOZVpRYmNMQ1E4ZlFXMDVq\nbW1FcnYzWTBHQmdhSjlsZUtZK3dzNUZjY1FvCkV4VXU4MTcwNVZoZUpVVS9JeHE5\nbGk3UzE3YmpZQ1JISHV0RHJqSG9ZNXcKLS0tIHhBdnIvMjJkeWlVRE9Fb0FhWjNX\nUjBVWDltK2w0akkwOTJaTGNSWWNrRXMKqZRNnHiXvn1QBoSGdABp7vOqNlsEN6Xr\nDp3NByXow6PuRuWvQXHzd+WC+ADkwNaaiT6TUrbZcd/Pl8Ges9kcZg==\n-----END AGE ENCRYPTED FILE-----\n",
|
||||
"recipient": "age1njap586hc0q43kr03g6c8eqhdsmk8zcafkl3f83xwlc2gqhlmfgs4tmwad"
|
||||
},
|
||||
{
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA2VFBxc2ZMUFp0YkJhVFhW\nc0ZNbnJUcGtkT1VLR2YrVGhRRFVTZFlyZXlJCmVnblNBNGxIdHh4Q0IweWR1b0dq\nRWFyOURuWkdkRE1RTnJRMEpXdk9HaUUKLS0tIFhKV3FoWW1zRk1pMlhuWWlhV2E5\nQzJTRHAyc0JtSjd2NHlJODZVbndaVDgKFA4565X/4FqNq/fZDZTg81/55hZi4c7b\nTti2AnyE3OcY/kurXJFHRinVMqURQf1fx9MxqUYRitiCz4qe5zFF+A==\n-----END AGE ENCRYPTED FILE-----\n",
|
||||
"recipient": "age1sweerhrga9yf8x6sv0apz4ed4g48rnlcq34rpv20t0rcelwgpgeqwvndzz"
|
||||
},
|
||||
{
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwRWlKTFNocnBRN01pZ0hm\na3pyRUkxMWM3dE1iTkZZcGRYUFcyb1RDb2h3Ckt4blpGZHBjcnZ4SVE5UnF4cmY4\nWW0rZG5wUkZINVk5a2lmSzN2L3JJY1kKLS0tIExpWGlBRFZJVGpGbFhxRE5ZYjBo\nQVliTlFIZ1U5dE9xbDhHMUtxenpBSm8KY6sIFEfK8p+70IXsC4Jwb9Lm/pd9+V6K\n4JAzGrpA6mAuIwwSNnbdcA5j8FmBhCpK6nLBWmFhGm9Y+MRTaM7Jrw==\n-----END AGE ENCRYPTED FILE-----\n",
|
||||
"recipient": "age1nruncs4l0ufk7yuc4des8p99c0alfndl0lhsws8tycl5pplfp56s30af5f"
|
||||
},
|
||||
{
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoV0pIUXlyOFFTUHVTdllu\neG10VENOYWl5Wk0ycnpLUytTbnlrQ25pMkFRCnhyRU5xWW9vQXJJOHdFMGZqMkR1\nSktqT3lOdVVPRUN4YTlveGp0NXpqd0kKLS0tIGRaTktra0ZtSVpzSHBrY3VSSUph\nRVRZOSsxTTNmMmltMlJnVy9oT2VEWU0Krxf49B1BsrWn05fqg+cZ0k0PtfJJNfn0\nUL44RUWXWbK2igQHaIct9DfYe7DEonBJeROuxDYm8g7yNOv15S+P4Q==\n-----END AGE ENCRYPTED FILE-----\n",
|
||||
"recipient": "age1529taqdwr6t0w7cvzmty0d5y5593wffl0krt48j6uc4u39k56g2qf6ywtp"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2026-07-28T01:44:26Z",
|
||||
"mac": "ENC[AES256_GCM,data:eyOSn03dzHSgkshPzLVwc95382eEFaDQarHs9l83dtcsb1Ui9CjkKipl2DVSUb6bdMUH1qKYmXqJhwFnAZbFZFjT4VTKtutNtM+OkhVXfT+fJs+1+u7k+ZUYFL9HuxKA6AWpwX3eJ8vmJDJZaAayJbm4PRzOyJywvKeneQqdUS0=,iv:QRKltR4qzVofo/Elt2Us/lrHlD7BenX605X31x+Ng78=,tag:SZ97CcfgMJeu3yqNk8Y/cA==,type:str]",
|
||||
"version": "3.13.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data:QvViw/s1N7eIN3CoD27llEjriuSrohOou4Cv310nigcW8xMnA2SDN2id3H3AoKii1JlJ+qWpKn+gUmt5HOM0UlbeNe3os2RVwiX38O7eN9xFH9F5kA3TFs6Umqq3EoI586PwIVmB2LyxDnTeEEXVd7v5PFkBcfu7u8YIcNF7lpcj+6rOyHMB8uxPhrGep3yiKawFd9c9wWD0hlSSatV5tMHA1qmdK8VmDbCU/iuGwIoMzN1eZwGAXzG6LkCA63bUfdxU6yGuTboD+kN2Wbo+GZB0EACmiZoofl2wqlXuiw6qwTvlXkyauc9O5EG//PUkIECzDwiXcX+qSOM9DIBlZNth4ebhtic/PskyF09etL/gICz5YvV4ph5lyrWHq41KxljSU7QXOkGhzagruuMrYzhZb35wFH4Tie1ee2DXbGhreJr8V3Zse/zTMaD+iM57V8bvNcarTzOFXyKfp7Y=,iv:XBPhj2wT0k/yRCRHU4d+BQA/k00ZHWSKOucnZ5+PGys=,tag:Nh5MOxZIUXAYVZY5SZh/JA==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0aUtETXlBMmRlTC9vK3NF\nRW4zS1FrSmo1dDN0OGN4SmV5ODd5MTRVejFJCnpPQkM2MVJ5WFlYRW1NVjduV1hv\nUWUzY0hHV05LV1BROVZVUlM2NldsTlEKLS0tIHFsTzI2SVZzYUtJWTM0MmFiUlVQ\neHEvUXgzc1pxSU1OZFo0cXhSZDdGUVEKpLVfzQEnntluUGsblnkHZJ9Jezu8tFte\nxEoV96GVHxUca6TFWpTLMqdR7NtuQGCkx295W3i1tkp58DP1OzRTUA==\n-----END AGE ENCRYPTED FILE-----\n",
|
||||
"recipient": "age1njap586hc0q43kr03g6c8eqhdsmk8zcafkl3f83xwlc2gqhlmfgs4tmwad"
|
||||
},
|
||||
{
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA4ZW5ybVBvTkxibWJMWGRL\nZ1lnWEkxZ3l6d0FWbmxMY2VsTVlzOHJJM3owClNYd3BlQi9pL1lIdzJmekJUVEVi\ncWhSK3ZkZEMyeTNoZlpTT0NMUXZFWVEKLS0tIHVkVlhmQXdRQktTK3J5dXZ4aTNt\ncUw3WCt5dXJhTkdUbVpmeWoxWkoxNnMKj4XtdwmgFVOiVsIJs2Du7QJ09A9tv/Lf\nkFOq8y4tlZe0nCwRjq43sVz7hdCTdQ0rsaWjBGY90LLkJbOA+f+Wrw==\n-----END AGE ENCRYPTED FILE-----\n",
|
||||
"recipient": "age16kqfmvz4e23hmdlqresnyw69ej604s320mmd49h4hm3fhqchtgyqrws0k2"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2026-07-28T01:44:30Z",
|
||||
"mac": "ENC[AES256_GCM,data:zR2WLWX7NaHA15gi4kX0jDvzUIe9jtz5bMCAggbPW+IXOEedPrddAHZ8OfPErVMfx8O1pJKkAKSzoPTAbEle54FisSLMHXp8fI0297MByJrF9pOsMFpVcDy/L4Q+pBzmB7aS9r7+u7KRVVTZT3QwG1rFWZaDs5dFTP80RhtCbWQ=,iv:ZzPoO+h7ebS+jsSH7tWMx6QK8umpa2/HFQmx9dnJN+Y=,tag:vG9+ifxw4HaBE6YsmOwXcg==,type:str]",
|
||||
"version": "3.13.2"
|
||||
}
|
||||
}
|
||||
+6
-1
@@ -16,7 +16,7 @@
|
||||
serverIp = "192.168.2.226"; # server (NFS/ZFS) Proxmox VM LAN IP
|
||||
dockerIp = "192.168.2.225"; # docker Proxmox VM LAN IP
|
||||
pbsIp = "192.168.2.244"; # Proxmox Backup Server LAN IP (not NixOS-managed)
|
||||
domainControllerIp = "192.168.2.253"; # FreeIPA domain controller / primary DNS (not NixOS-managed)
|
||||
domainControllerIp = "192.168.2.253"; # FreeIPA domain controller — authoritative DNS for sweet.home (not NixOS-managed)
|
||||
ipaServer = "domain-controller.sweet.home"; # FreeIPA server hostname (used by security.ipa and Kerberos; must be a resolvable FQDN, not an IP)
|
||||
|
||||
# Cross-host references (LAN hostnames/users other hosts reach over the network)
|
||||
@@ -80,6 +80,11 @@
|
||||
# one-line change.
|
||||
primaryUser = "nixos";
|
||||
|
||||
# Primary IPA/domain user. Home Manager is configured for this user on every
|
||||
# IPA-enrolled host (see modules/ipa/client.nix) to manage the environment
|
||||
# that IPA itself doesn't cover: dotfiles, user packages, session variables.
|
||||
ipaUser = "wayne";
|
||||
|
||||
# HA file server cluster
|
||||
# LAN IPs (vmbr0 / ens18) — client-facing: iSCSI initiators, NFS, management.
|
||||
# Storage IPs (vmbr1 / ens19) — isolated internal bridge, used for DRBD
|
||||
|
||||
Reference in New Issue
Block a user