Archived
Compare commits
13
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
720399b00d | ||
|
|
fc8f7baf3e | ||
|
|
a960c662f0 | ||
|
|
6f602b2245 | ||
|
|
e62e9c9a6a | ||
|
|
5beed2d75c | ||
|
|
fe7fc55c04 | ||
|
|
6cdae391f4 | ||
|
|
95eb494370 | ||
|
|
5c2d61d35a | ||
|
|
e6f15404f5 | ||
|
|
1fc6e63178 | ||
|
|
232d0e7c40 |
@@ -6,12 +6,14 @@ This repository contains flake-based NixOS configurations for Wayne's LAN
|
|||||||
servers and workstation.
|
servers and workstation.
|
||||||
|
|
||||||
The flake exposes NixOS configurations named `<platform>-<buildtype>`
|
The flake exposes NixOS configurations named `<platform>-<buildtype>`
|
||||||
(platforms: `linode`, `proxmox`, `lxc`; build types: `minimal`, `nix-cache`,
|
(platforms: `linode`, `proxmox`, `lxc`, `baremetal`; build types: `minimal`,
|
||||||
`server`, `docker`, `gui`, `pxe-boot`, `tailscale-exit-node`, `tor-relay`), generated from `modules/platforms/*`
|
`nix-cache`, `server`, `docker`, `gui`, `pxe-boot`, `tailscale-router`,
|
||||||
and `modules/build-types/*` by the `mkTarget` function in `flake.nix`. Not
|
`tor-relay`, `ha-server`), generated from `modules/platforms/*` and
|
||||||
every combination is built — `pxe-boot` has no `linode` variant. See
|
`modules/build-types/*` by the `mkTarget` function in `flake.nix`. Not every
|
||||||
`README.md` for the full current target list; treat `flake.nix` as the
|
combination is built — `pxe-boot` has no `linode` variant, `ha-server` only
|
||||||
source of truth since this list can drift.
|
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
|
Do not deploy, switch, reboot, repartition, format disks, or run destructive
|
||||||
install commands from this repository unless explicitly asked.
|
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`
|
- **Platforms** (what it runs on): `linode`, `proxmox`, `lxc`, `baremetal`
|
||||||
- **Build types** (what it's for): `minimal`, `nix-cache`, `server`, `docker`,
|
- **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
|
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,
|
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`
|
`tor-relay` and `ha-server` currently only exist on `lxc`/`proxmox`, and
|
||||||
currently only exists as `baremetal-gui` (the real gui-host hardware). The
|
`baremetal` currently only exists as `baremetal-gui` (the real gui-host
|
||||||
full list:
|
hardware). The full list:
|
||||||
|
|
||||||
| Target | Purpose |
|
| Target | Purpose |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
@@ -29,8 +29,9 @@ full list:
|
|||||||
| `linode-gui` / `proxmox-gui` / `lxc-gui` | Cinnamon desktop workstation — previously the flat `nixos` target |
|
| `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 |
|
| `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 |
|
| `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 |
|
| `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
|
Which variant of a given buildtype is actually deployed isn't tracked
|
||||||
anywhere in this repo — that's live infrastructure state, not something a
|
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
|
Each buildtype's `hosts/<name>/host.nix` carries the per-machine identity
|
||||||
(hostname, hostId, per-machine secrets, `system.stateVersion`) that must stay
|
(hostname, hostId, per-machine secrets, `system.stateVersion`) that must stay
|
||||||
fixed regardless of which platform it's built for — see
|
fixed regardless of which platform it's built for. Every deployed host
|
||||||
`flake-target-refactor-spec.md` for the full rationale. Every deployed host
|
|
||||||
stamps its own active target name into `/etc/flake-target` at build time, so
|
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
|
`nixos-rebuild switch --flake .#$(cat /etc/flake-target)` always picks up the
|
||||||
right one even after a platform migration changes the flake attribute name.
|
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
|
(`vars/per-machine/<target>/openssh/`, committed and sops-encrypted) for
|
||||||
their SSH host keys.
|
their SSH host keys.
|
||||||
|
|
||||||
This repository's git *history* still contains secrets committed before this
|
This repository's git *history* still contains secrets committed before the
|
||||||
migration (see `remove-sensetive-info-refactor.md`) — those are being
|
sops-nix migration — those are being scrubbed and rotated separately; don't
|
||||||
scrubbed and rotated separately; don't treat the repo as safe to make public
|
treat the repo as safe to make public until that's finished.
|
||||||
until that's finished.
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ see "LXC hosts" immediately below for why those are different.**
|
|||||||
## LXC hosts
|
## LXC hosts
|
||||||
|
|
||||||
`lxc-*` targets (`lxc-minimal`, `lxc-nix-cache`, `lxc-server`, `lxc-docker`,
|
`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;
|
interactive menu deliberately excludes them. Don't try to select one there;
|
||||||
`nixos-install` would bind-mount `/` onto `/mnt` (LXC containers have no raw
|
`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
|
disk to partition) and then refuse to touch the filesystem it's currently
|
||||||
@@ -133,13 +133,15 @@ Flake outputs:
|
|||||||
```nix
|
```nix
|
||||||
nixosConfigurations.installer # ISO/netboot installer image
|
nixosConfigurations.installer # ISO/netboot installer image
|
||||||
|
|
||||||
packages.x86_64-linux.iso # installer ISO/netboot 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.pxe # auto-installer netboot bundle (kernel + initrd + ipxe script)
|
||||||
|
packages.x86_64-linux.pxe-minimal # vanilla NixOS minimal netboot bundle (no installer wiring)
|
||||||
```
|
```
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
nix build .#iso
|
nix build .#iso
|
||||||
nix build .#pxe
|
nix build .#pxe
|
||||||
|
nix build .#pxe-minimal
|
||||||
```
|
```
|
||||||
|
|
||||||
There's no `nixosConfigurations.proxmox-lxc` (installer-boots-as-an-LXC-
|
There's no `nixosConfigurations.proxmox-lxc` (installer-boots-as-an-LXC-
|
||||||
|
|||||||
@@ -14,6 +14,11 @@
|
|||||||
};
|
};
|
||||||
boot.zfs.forceImportRoot = false;
|
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
|
# Preserved from the pre-refactor `docker` target — stateVersion must never
|
||||||
# be bumped on an already-installed machine.
|
# be bumped on an already-installed machine.
|
||||||
system.stateVersion = "25.05";
|
system.stateVersion = "25.05";
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
services.beszel.agent.environment = {
|
services.beszel.agent.environment = {
|
||||||
#DOCKER_HOST = "tcp://docker-socket-proxy:2375";
|
|
||||||
KEY = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFPR9kwtC4TAeTRu46A7+opZsYpxqkRJ+x/ZyB2GWCeG";
|
KEY = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFPR9kwtC4TAeTRu46A7+opZsYpxqkRJ+x/ZyB2GWCeG";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
services.beszel.agent.environment = {
|
services.beszel.agent.environment = {
|
||||||
#DOCKER_HOST = "tcp://docker-socket-proxy:2375";
|
|
||||||
KEY = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFPR9kwtC4TAeTRu46A7+opZsYpxqkRJ+x/ZyB2GWCeG";
|
KEY = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFPR9kwtC4TAeTRu46A7+opZsYpxqkRJ+x/ZyB2GWCeG";
|
||||||
EXTRA_FILESYSTEMS = "${vars.storageRoot}/${vars.nfsShares.dockerVolumes.subpath}";
|
EXTRA_FILESYSTEMS = "${vars.storageRoot}/${vars.nfsShares.dockerVolumes.subpath}";
|
||||||
LOG_LEVEL = "debug";
|
LOG_LEVEL = "debug";
|
||||||
|
|||||||
@@ -15,6 +15,16 @@
|
|||||||
# under services.beszel.agent.environment.KEY once the hub accepts the
|
# under services.beszel.agent.environment.KEY once the hub accepts the
|
||||||
# new agents, following the pattern in hosts/server/host.nix.
|
# new agents, following the pattern in hosts/server/host.nix.
|
||||||
{ lib, vars, ... }:
|
{ 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 = [
|
imports = [
|
||||||
../ha/pacemaker-stack.nix
|
../ha/pacemaker-stack.nix
|
||||||
@@ -25,16 +35,7 @@
|
|||||||
|
|
||||||
services.nfs.server = {
|
services.nfs.server = {
|
||||||
enable = true;
|
enable = true;
|
||||||
exports = ''
|
exports = mkNfsExports vars.haStorageRoot;
|
||||||
${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}
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# Pacemaker controls nfs-server — prevent systemd from starting it at boot
|
# Pacemaker controls nfs-server — prevent systemd from starting it at boot
|
||||||
|
|||||||
@@ -13,6 +13,15 @@ let
|
|||||||
lib.concatMap (share: ancestors share.subpath)
|
lib.concatMap (share: ancestors share.subpath)
|
||||||
(lib.filter builtins.isAttrs (lib.attrValues vars.nfsShares))
|
(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
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
@@ -95,16 +104,7 @@ in
|
|||||||
|
|
||||||
services.nfs.server = {
|
services.nfs.server = {
|
||||||
enable = true;
|
enable = true;
|
||||||
exports = ''
|
exports = mkNfsExports vars.storageRoot;
|
||||||
${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}
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# mountd (20048) is needed for showmount/NFSv3 mount protocol — without it
|
# mountd (20048) is needed for showmount/NFSv3 mount protocol — without it
|
||||||
|
|||||||
@@ -25,13 +25,10 @@ let
|
|||||||
'';
|
'';
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports =
|
imports = [
|
||||||
[
|
./set-locale.nix
|
||||||
# Include the results of the hardware scan.
|
../ipa/client.nix
|
||||||
# ./hardware-configuration.nix
|
];
|
||||||
./set-locale.nix
|
|
||||||
../ipa/client.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
# System-wide shell config so all users (including IPA accounts) get the
|
# System-wide shell config so all users (including IPA accounts) get the
|
||||||
# same management aliases as the local nixos user's Home Manager provides.
|
# same management aliases as the local nixos user's Home Manager provides.
|
||||||
@@ -42,11 +39,7 @@ in
|
|||||||
};
|
};
|
||||||
interactiveShellInit = buildImageFn;
|
interactiveShellInit = buildImageFn;
|
||||||
};
|
};
|
||||||
# Use the GRUB 2 boot loader.
|
networking.networkmanager.enable = true;
|
||||||
# boot.loader.grub.enable = true;
|
|
||||||
#boot.loader.grub.device = "/dev/sda"; # or "nodev" for efi only
|
|
||||||
|
|
||||||
networking.networkmanager.enable = true; # Easiest to use and most distros use this by default.
|
|
||||||
|
|
||||||
# Recommended over the true default (bypasses ZFS's own import safeguards)
|
# Recommended over the true default (bypasses ZFS's own import safeguards)
|
||||||
# per the option's own docs; matches hosts/docker/host.nix and
|
# 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,23 +1,45 @@
|
|||||||
{ pkgs, vars, ... }:
|
{ lib, pkgs, vars, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
gid = toString vars.dockerAccessGid;
|
||||||
|
in
|
||||||
{
|
{
|
||||||
# virtualisation.docker.enable = true;
|
|
||||||
virtualisation.docker = {
|
virtualisation.docker = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = pkgs.docker;
|
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;
|
|
||||||
# };
|
|
||||||
};
|
};
|
||||||
|
# Pin the docker group GID to match the IPA "docker-access" group so that
|
||||||
|
# IPA group membership alone grants access to the Docker socket. Any user
|
||||||
|
# whose supplementary groups (resolved by SSSD from IPA) include GID
|
||||||
|
# vars.dockerAccessGid will pass the socket group-permission check without
|
||||||
|
# any per-host users.groups.docker.members entry.
|
||||||
|
users.groups.docker.gid = lib.mkForce vars.dockerAccessGid;
|
||||||
users.users.${vars.primaryUser}.extraGroups = [ "docker" ];
|
users.users.${vars.primaryUser}.extraGroups = [ "docker" ];
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
docker-compose
|
docker-compose
|
||||||
docker-buildx
|
docker-buildx
|
||||||
];
|
];
|
||||||
|
|
||||||
|
# NixOS's group activation uses plain `groupmod` without --non-unique.
|
||||||
|
# When SSSD is active it exposes the IPA "docker-access" group at
|
||||||
|
# vars.dockerAccessGid via NSS, so groupmod sees that GID as already in
|
||||||
|
# use and silently skips the change (warning: "not applying GID change").
|
||||||
|
# This script runs after the normal "groups" step and applies the change
|
||||||
|
# with --non-unique (which lets the local docker group share the GID with
|
||||||
|
# the SSSD-provided IPA group). If the GID actually changed it also
|
||||||
|
# restarts docker.socket so the socket is recreated with the new GID.
|
||||||
|
system.activationScripts.docker-group-gid = {
|
||||||
|
deps = [ "groups" ];
|
||||||
|
text = ''
|
||||||
|
current=$(grep "^docker:" /etc/group | cut -d: -f3)
|
||||||
|
if [ "$current" != "${gid}" ]; then
|
||||||
|
${pkgs.shadow}/bin/groupmod --non-unique -g ${gid} docker
|
||||||
|
if ${pkgs.systemd}/bin/systemctl is-active --quiet docker.socket; then
|
||||||
|
${pkgs.systemd}/bin/systemctl stop docker.service docker.socket
|
||||||
|
rm -f /var/run/docker.sock
|
||||||
|
${pkgs.systemd}/bin/systemctl start docker.socket docker.service
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+115
-93
@@ -38,47 +38,122 @@ lib.mkIf enabled {
|
|||||||
networking.domain = lib.mkDefault vars.homeDomain;
|
networking.domain = lib.mkDefault vars.homeDomain;
|
||||||
networking.nameservers = lib.mkDefault [ vars.domainControllerIp ];
|
networking.nameservers = lib.mkDefault [ vars.domainControllerIp ];
|
||||||
|
|
||||||
security.ipa = {
|
security = {
|
||||||
enable = true;
|
ipa = {
|
||||||
domain = vars.homeDomain;
|
enable = true;
|
||||||
inherit realm;
|
domain = vars.homeDomain;
|
||||||
server = vars.ipaServer;
|
inherit realm;
|
||||||
certificate = caCertPkg;
|
server = vars.ipaServer;
|
||||||
inherit basedn;
|
certificate = caCertPkg;
|
||||||
ipaHostname = fqdn;
|
inherit basedn;
|
||||||
offlinePasswords = true;
|
ipaHostname = fqdn;
|
||||||
cacheCredentials = true;
|
offlinePasswords = true;
|
||||||
|
cacheCredentials = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Create the home directory on first login if it doesn't exist yet.
|
||||||
|
# IPA users have no pre-created home on the host; without this sshd
|
||||||
|
# opens a session to a non-existent directory and resets the connection.
|
||||||
|
# lightdm also needs this so the GUI login path can create the home dir
|
||||||
|
# if it was not pre-seeded by the tmpfiles rule above (e.g. on first boot
|
||||||
|
# before SSSD has resolved the user).
|
||||||
|
pam.services = {
|
||||||
|
sshd.makeHomeDir = true;
|
||||||
|
lightdm.makeHomeDir = true;
|
||||||
|
|
||||||
|
# pam_unix returns PAM_AUTHINFO_UNAVAIL without prompting when the local
|
||||||
|
# stub has "!" in shadow (account locked), so PAM_AUTHTOK is never set
|
||||||
|
# and pam_sss's use_first_pass fails with "No authentication token".
|
||||||
|
# Changing to try_first_pass makes pam_sss prompt independently when no
|
||||||
|
# prior module has set the token, restoring IPA password login via
|
||||||
|
# LightDM and su.
|
||||||
|
login.rules.auth.sss.settings = lib.mkForce { try_first_pass = true; };
|
||||||
|
su.rules.auth.sss.settings = lib.mkForce { try_first_pass = true; };
|
||||||
|
};
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
sudo.extraRules = [{
|
||||||
|
users = [ vars.ipaUser ];
|
||||||
|
commands = [{ command = "ALL"; options = [ "NOPASSWD" ]; }];
|
||||||
|
}];
|
||||||
};
|
};
|
||||||
|
|
||||||
# Fetch SSH public keys from IPA so users can log in with the key stored
|
systemd = {
|
||||||
# in their IPA profile rather than needing ~/.ssh/authorized_keys on every
|
# Fetch SSH public keys from IPA so users can log in with the key stored
|
||||||
# host. sss_ssh_authorizedkeys queries SSSD (which queries IPA LDAP).
|
# in their IPA profile rather than needing ~/.ssh/authorized_keys on every
|
||||||
#
|
# host. sss_ssh_authorizedkeys queries SSSD (which queries IPA LDAP).
|
||||||
# /nix/store is 1775 (group-writable by nixbld). OpenSSH 10.0+ rejects
|
#
|
||||||
# AuthorizedKeysCommand binaries whose path contains any group-writable
|
# /nix/store is 1775 (group-writable by nixbld). OpenSSH 10.0+ rejects
|
||||||
# component, silently skipping the command. Copy to /usr/local/bin (all
|
# AuthorizedKeysCommand binaries whose path contains any group-writable
|
||||||
# components root-owned, 755) so the path passes sshd's safety check.
|
# component, silently skipping the command. Copy to /usr/local/bin (all
|
||||||
systemd.tmpfiles.rules = [
|
# components root-owned, 755) so the path passes sshd's safety check.
|
||||||
"d /usr/local 0755 root root - -"
|
tmpfiles.rules = [
|
||||||
"d /usr/local/bin 0755 root root - -"
|
"d /usr/local 0755 root root - -"
|
||||||
"C+ /usr/local/bin/sss_ssh_authorizedkeys 0555 root root - ${pkgs.sssd}/bin/sss_ssh_authorizedkeys"
|
"d /usr/local/bin 0755 root root - -"
|
||||||
# Pre-create the IPA user's home dir so Home Manager activation succeeds
|
"C+ /usr/local/bin/sss_ssh_authorizedkeys 0555 root root - ${pkgs.sssd}/bin/sss_ssh_authorizedkeys"
|
||||||
# even before their first login. On a fresh system SSSD may not have
|
# Pre-create the IPA user's home dir so Home Manager activation succeeds
|
||||||
# resolved the user yet — tmpfiles warns and skips in that case (non-fatal),
|
# even before their first login. On a fresh system SSSD may not have
|
||||||
# and pam_mkhomedir covers the first-login path as a fallback.
|
# resolved the user yet — tmpfiles warns and skips in that case (non-fatal),
|
||||||
"d /home/${vars.ipaUser} 0700 ${vars.ipaUser} ${vars.ipaUser} - -"
|
# and pam_mkhomedir covers the first-login path as a fallback.
|
||||||
];
|
"d /home/${vars.ipaUser} 0700 ${vars.ipaUser} ${vars.ipaUser} - -"
|
||||||
|
];
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
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-<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.
|
||||||
|
services."home-manager-${vars.ipaUser}".unitConfig.ConditionPathExists =
|
||||||
|
"/home/${vars.ipaUser}";
|
||||||
|
};
|
||||||
|
|
||||||
services.openssh.extraConfig = ''
|
services.openssh.extraConfig = ''
|
||||||
AuthorizedKeysCommand /usr/local/bin/sss_ssh_authorizedkeys %u
|
AuthorizedKeysCommand /usr/local/bin/sss_ssh_authorizedkeys %u
|
||||||
AuthorizedKeysCommandUser nobody
|
AuthorizedKeysCommandUser nobody
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# Create the home directory on first login if it doesn't exist yet.
|
|
||||||
# IPA users have no pre-created home on the host; without this sshd
|
|
||||||
# opens a session to a non-existent directory and resets the connection.
|
|
||||||
security.pam.services.sshd.makeHomeDir = true;
|
|
||||||
|
|
||||||
# Host keytab: pre-provisioned on the IPA server, sops-encrypted binary.
|
# Host keytab: pre-provisioned on the IPA server, sops-encrypted binary.
|
||||||
# Placed at /etc/krb5.keytab before SSSD starts so the host authenticates
|
# Placed at /etc/krb5.keytab before SSSD starts so the host authenticates
|
||||||
# to IPA without running ipa-client-install.
|
# to IPA without running ipa-client-install.
|
||||||
@@ -92,44 +167,6 @@ lib.mkIf enabled {
|
|||||||
restartUnits = [ "sssd.service" ];
|
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
|
# NixOS requires isNormalUser/isSystemUser + group on any entry in
|
||||||
# users.users. HM with useUserPackages = true (set in flake.nix) adds a stub
|
# users.users. HM with useUserPackages = true (set in flake.nix) adds a stub
|
||||||
# entry for each HM user so it can install packages to
|
# entry for each HM user so it can install packages to
|
||||||
@@ -137,35 +174,20 @@ lib.mkIf enabled {
|
|||||||
# With security.ipa setting "passwd: sss files" in nsswitch, SSSD's IPA entry
|
# 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
|
# takes priority for NSS lookups — this local stub is only a fallback when
|
||||||
# SSSD is unreachable (at which point auth fails anyway).
|
# 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} = {
|
users.users.${vars.ipaUser} = {
|
||||||
isNormalUser = true;
|
isNormalUser = true;
|
||||||
group = "users";
|
group = "users";
|
||||||
extraGroups = [ "wheel" ];
|
extraGroups = [ "wheel" ];
|
||||||
createHome = false;
|
createHome = false;
|
||||||
|
# "!" is not a password hash — it is the standard "account locked" marker.
|
||||||
|
# It cannot authenticate anyone locally. It exists solely so NixOS generates
|
||||||
|
# a shadow entry for this stub user; without one pam_unix returns
|
||||||
|
# PAM_AUTHINFO_UNAVAIL before prompting, which means PAM_AUTHTOK is never
|
||||||
|
# set and the subsequent pam_sss use_first_pass call has nothing to work
|
||||||
|
# with — blocking LightDM and su logins even when IPA/SSSD auth succeeds.
|
||||||
|
hashedPassword = "!";
|
||||||
};
|
};
|
||||||
|
|
||||||
# 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
|
# Home Manager config for the IPA primary user, applied on every enrolled
|
||||||
# host. Manages what IPA doesn't: dotfiles, user-scoped packages, session
|
# host. Manages what IPA doesn't: dotfiles, user-scoped packages, session
|
||||||
# variables. Switch-nix/Test-nix/buildImage are system-wide (configuration.nix)
|
# variables. Switch-nix/Test-nix/buildImage are system-wide (configuration.nix)
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ in
|
|||||||
# LXC container does).
|
# LXC container does).
|
||||||
imports = [
|
imports = [
|
||||||
(modulesPath + "/virtualisation/proxmox-lxc.nix")
|
(modulesPath + "/virtualisation/proxmox-lxc.nix")
|
||||||
|
../common/preserve-ssh-host-key.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
proxmoxLXC = {
|
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
|
# virtualisation/proxmox-lxc.nix (imported above) registers the Nix
|
||||||
# store DB via a systemd service (register-nix-paths) -- it never runs
|
# store DB via a systemd service (register-nix-paths) -- it never runs
|
||||||
# an activation script at all. Confirmed live this means neither
|
# an activation script at all. Confirmed live this means neither
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ in
|
|||||||
../hardware-configuration/vm/proxmox.nix
|
../hardware-configuration/vm/proxmox.nix
|
||||||
../boot/efi.nix
|
../boot/efi.nix
|
||||||
../disko/proxmox.nix
|
../disko/proxmox.nix
|
||||||
|
../common/preserve-ssh-host-key.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
environment.etc = lib.mkIf hasKeyForThisTarget {
|
environment.etc = lib.mkIf hasKeyForThisTarget {
|
||||||
@@ -46,36 +47,4 @@ in
|
|||||||
mode = "0644";
|
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" ]; };
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-1
@@ -16,7 +16,7 @@
|
|||||||
serverIp = "192.168.2.226"; # server (NFS/ZFS) Proxmox VM LAN IP
|
serverIp = "192.168.2.226"; # server (NFS/ZFS) Proxmox VM LAN IP
|
||||||
dockerIp = "192.168.2.225"; # docker 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)
|
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)
|
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)
|
# Cross-host references (LAN hostnames/users other hosts reach over the network)
|
||||||
@@ -85,6 +85,12 @@
|
|||||||
# that IPA itself doesn't cover: dotfiles, user packages, session variables.
|
# that IPA itself doesn't cover: dotfiles, user packages, session variables.
|
||||||
ipaUser = "wayne";
|
ipaUser = "wayne";
|
||||||
|
|
||||||
|
# GID of the IPA "docker-access" group (GID 50010 on the IPA server).
|
||||||
|
# The local "docker" group is pinned to this GID on every host that runs
|
||||||
|
# Docker so that IPA group membership alone grants docker socket access -
|
||||||
|
# no per-host users.groups.docker.members entry for the IPA user needed.
|
||||||
|
dockerAccessGid = 50010;
|
||||||
|
|
||||||
# HA file server cluster
|
# HA file server cluster
|
||||||
# LAN IPs (vmbr0 / ens18) — client-facing: iSCSI initiators, NFS, management.
|
# LAN IPs (vmbr0 / ens18) — client-facing: iSCSI initiators, NFS, management.
|
||||||
# Storage IPs (vmbr1 / ens19) — isolated internal bridge, used for DRBD
|
# Storage IPs (vmbr1 / ens19) — isolated internal bridge, used for DRBD
|
||||||
|
|||||||
Reference in New Issue
Block a user