Find a file
Casper V. Kristensen d0b81511ff replace systemd-resolved with unbound
Resolved seems to crash on some DNSSEC-enabled NXDOMANs??
2024-04-01 01:19:51 +02:00
.gitea/workflows Replace Containerfile with Forgejo Actions 2024-03-30 03:09:36 +01:00
hosts alpha: knot-dns 2024-03-31 04:29:49 +02:00
modules replace systemd-resolved with unbound 2024-04-01 01:19:51 +02:00
overlays sigma: gitea actions runner 2024-03-30 03:09:36 +01:00
.gitignore Initial commit 2023-06-25 01:28:19 +02:00
flake.lock alpha: knot-dns 2024-03-31 04:29:49 +02:00
flake.nix add sigma 2024-03-28 17:31:20 +01:00
LICENSE fmt license 2023-07-09 00:15:18 +02:00
README.md Use secrets from nixos-secrets repo 2024-03-28 17:28:59 +01:00

nixos

Installation

Follow the NixOS manual to obtain and boot the installation medium. Use the graphical ISO image since it ships with useful programs such as nmtui; the installation can still be done through the terminal.

Disk Partitioning

For impermanence, partitioning should be done as outlined in the tmpfs as root blogpost, but with /nix as a LUKS-encrypted file system. The boot partition will not be encrypted, since that is poorly supported by systemd-boot. Persistent files will be saved under /nix/persist. To find out which of our darlings will be erased on reboot do tree -x / or ncdu -x /.

The following is based on the tmpfs as root blogpost, the NixOS manual's partitioning, formatting and LUKS-Encrypted File Systems sections, ArchWiki's LVM on LUKS, the unofficial NixOS wiki Full Disk Encryption, and this GitHub gist.

We create a 1GiB EFI boot partition (/dev/sda1) and the rest will be our LUKS-encrypted volume:

# Create partition table
parted /dev/sda -- mklabel gpt

# Create /boot partition
parted /dev/sda -- mkpart ESP fat32 1MiB 1024MiB
parted /dev/sda -- set 1 esp on

# Create /nix partition
parted /dev/sda -- mkpart primary 1024MiB 100%

# Create and open LUKS-encrypted container
cryptsetup --type=luks2 luksFormat --label=crypted /dev/sda2
cryptsetup open /dev/sda2 crypted

# Create LVM volume group
pvcreate /dev/mapper/crypted
vgcreate vg /dev/mapper/crypted

# Create root logical volume
lvcreate -l 100%FREE vg -n root

# Format partitions
mkfs.fat -F32 -n BOOT /dev/sda1
mkfs.ext4 -L nix /dev/vg/root

The result should be the following (lsblk -f):

NAME          FSTYPE      FSVER            LABEL
sda
├─sda1        vfat        FAT32            BOOT
└─sda2        crypto_LUKS 2                crypted
  └─crypted   LVM2_member LVM2 001
    └─vg-root ext4        1.0              nix

Whereas the NixOS manual mounts the newly-created nixos partition to /mnt, we will follow the tmpfs as root blogpost and mount /mnt as tmpfs:

mount -t tmpfs none /mnt
mount --mkdir /dev/disk/by-label/BOOT /mnt/boot
mount --mkdir /dev/disk/by-label/nix /mnt/nix
mkdir -p /mnt/nix/persist/

Secrets

All files in the Nix store are world-readable, so it is not a suitable place for including cleartext secrets, even if we had a scheme to securely transfer them to each system. Agenix solves this issue by encrypting the secrets using age, and then decrypting and symlinking them using the system's SSH host key during system activation.

All secrets, and other private configuration such as DNS zonefiles, are stored in a separate, private repo. To bootstrap a new system, we must first generate a host key manually using ssh-keygen -A -f /mnt/nix/persist during installation. Then, on an existing system, add the new host's public key to secrets.nix in the nixos-secrets repo and rekey all secrets using agenix --rekey. Commit and transfer the repository to the new system.

When managing secrets, the Keepass recovery key is used like so:

set AGE_KEY_FILE (mktemp); read -s > $AGE_KEY_FILE
agenix -i $AGE_KEY_FILE -e foo.age

Installation

The remaining installation can be done (more or less) according to the NixOS manual.

cd /mnt/nix
git clone https://git.caspervk.net/caspervk/nixos.git tmp
cd tmp/
nixos-generate-config --root /mnt --show-hardware-config
vim hosts/omega/hardware.nix
git add .  # nix sometimes ignores files outside version control
nixos-install --no-root-passwd --flake .#omega --override-input secrets ./../nixos-secrets/

Hardware Configuration

hosts/*/hardware.nix, while initially generated by nixos-generate-config --show-hardware-config, is manually modified.

State Version

Nixpkgs uses stateVersion so sparingly that auditing the entire nixpkgs repo is easy enough.

Useful Commands

# development
sudo nixos-rebuild switch --flake . --override-input secrets ./../nixos-secrets/

# start build environment with user's default shell instead of bash
nix develop --command $SHELL

# nix shell with python packages
# https://discourse.nixos.org/t/nix-shell-for-python-packages/16575
# https://github.com/NixOS/nix/issues/5567
nix shell --impure --expr 'with builtins.getFlake "nixpkgs"; with legacyPackages.${builtins.currentSystem}; python3.withPackages (ps: with ps; [ numpy ])'

Debugging

# load flake into repl
nix repl . --override-input secrets ./../nixos-secrets/

# print a configuration option
:p nixosConfigurations.omega.options.services.openssh.ports.declarationPositions  # declaration
:p nixosConfigurations.omega.options.services.openssh.ports.default  # declaration default
:p nixosConfigurations.omega.options.services.openssh.ports.definitionsWithLocations  # overwrites
:p nixosConfigurations.omega.options.services.openssh.ports.value  # current value
# print derivation package names
:p builtins.map (d: d.name) outputs.nixosConfigurations.omega.options.environment.systemPackages.value

# print version of package in nixpkgs
:p inputs.nixpkgs.outputs.legacyPackages.${builtins.currentSystem}.openssh.version

References