initial home-hypervisor config

This commit is contained in:
Dmitriy Kholkin 2023-01-26 00:24:32 +03:00
parent 3ed643bd1e
commit 149c9093ab
8 changed files with 1058 additions and 0 deletions

View File

@ -0,0 +1,20 @@
{ lib, ... }: {
autoinstall = {
debug = false;
hostname = "Home-Hypervisor";
mainuser = "ataraxia";
flakesPath = "/home/nixos/conf";
encryption.enable = true;
encryption.passwordFile = "/home/nixos/pass";
encryption.argonIterTime = "4000";
partitioning.useEntireDisk = true;
partitioning.disk = "/dev/disk/by-id/ata-Samsung_SSD_870_EVO_500GB_S5Y1NJ1R160554B";
partitioning.nullifyDisk = false;
swapPartition.enable = true;
swapPartition.size = "8GiB";
zfsOpts.ashift = 13;
zfsOpts.bootPoolReservation = "256M";
zfsOpts.rootPoolReservation = "25G";
persist.enable = true;
};
}

View File

@ -0,0 +1,89 @@
{ config, pkgs, lib, ... }:
let
zfs_arc_max = toString (2 * 1024 * 1024 * 1024);
in {
boot = {
# extraModprobeConfig = ''
# options zfs metaslab_lba_weighting_enabled=0
# '';
zfs.forceImportAll = lib.mkForce false;
loader.efi.canTouchEfiVariables = false;
loader.efi.efiSysMountPoint = "/boot/efi";
loader.generationsDir.copyKernels = true;
loader.grub = {
enable = true;
device = "nodev";
version = 2;
efiSupport = true;
enableCryptodisk = true;
zfsSupport = true;
efiInstallAsRemovable = true;
copyKernels = true;
# # extraPrepareConfig = ''
# # '';
};
initrd = {
# availableKernelModules = [ "tg3" ]; # for dell-laptop
# postMountCommands = ''
# '';
luks.devices = {
"cryptboot" = {
preLVM = true;
keyFile = "/keyfile0.bin";
# keyFileSize = 4096;
# keyFile = "/dev/disk/by-path/pci-0000:00:1f.2-ata-2.0";
# keyFile = "/dev/disk/by-id/ata-QEMU_HARDDISK_QM00005";
allowDiscards = true;
bypassWorkqueues = config.deviceSpecific.isSSD;
fallbackToPassword = true;
# postOpenCommands = "";
# preOpenCommands = "";
};
"cryptroot" = {
preLVM = true;
keyFile = "/keyfile0.bin";
allowDiscards = true;
bypassWorkqueues = config.deviceSpecific.isSSD;
fallbackToPassword = true;
};
};
secrets = {
"keyfile0.bin" = "/etc/secrets/keyfile0.bin";
};
};
kernelPackages = pkgs.linuxPackages_hardened;
kernelModules = [ "tcp_bbr" "veth" ];
kernelParams = [
# "zfs.metaslab_lba_weighting_enabled=0"
"zfs.zfs_arc_max=${zfs_arc_max}"
"zswap.enabled=0"
"quiet"
"scsi_mod.use_blk_mq=1"
"modeset"
"nofb"
"pti=off"
"spectre_v2=off"
"kvm.ignore_msrs=1"
"rd.systemd.show_status=auto"
"rd.udev.log_priority=3"
];
kernel.sysctl = {
"kernel.sysrq" = false;
"net.core.default_qdisc" = "sch_fq_codel";
"net.ipv4.conf.all.accept_source_route" = false;
"net.ipv4.icmp_ignore_bogus_error_responses" = true;
"net.ipv4.tcp_congestion_control" = "bbr";
"net.ipv4.tcp_fastopen" = 3;
"net.ipv4.tcp_rfc1337" = true;
"net.ipv4.tcp_syncookies" = true;
"net.ipv6.conf.all.accept_source_route" = false;
# disable ipv6
"net.ipv6.conf.all.disable_ipv6" = true;
"net.ipv6.conf.default.disable_ipv6" = true;
};
kernel.sysctl = {
"vm.swappiness" = if config.deviceSpecific.isSSD then 1 else 10;
};
# cleanTmpDir = true;
};
}

View File

@ -0,0 +1,116 @@
{ modulesPath, inputs, lib, pkgs, config, options, ... }:
let
persistRoot = config.autoinstall.persist.persistRoot or "/persist";
in {
imports = with inputs.self; [
"${toString modulesPath}/profiles/hardened.nix"
./hardware-configuration.nix
./boot.nix
./virtualisation.nix
nixosRoles.hypervisor
];
deviceSpecific.devInfo = {
cpu = {
vendor = "intel";
clock = 2300;
cores = 4;
};
drive = {
type = "ssd";
speed = 500;
size = 500;
};
gpu = {
vendor = "other";
};
bigScreen = false;
ram = 12;
fileSystem = "zfs";
};
deviceSpecific.enableVirtualisation = true;
deviceSpecific.vpn.mullvad.enable = false;
deviceSpecific.isServer = true;
zramSwap = {
enable = true;
algorithm = "zstd";
memoryPercent = 70;
numDevices = 1;
};
# Impermanence
persist = {
enable = true;
cache.clean.enable = true;
state.files = [ "/etc/machine-id" ];
};
fileSystems."/home".neededForBoot = true;
fileSystems.${persistRoot}.neededForBoot = true;
boot.initrd.postDeviceCommands = lib.mkAfter ''
zfs rollback -r rpool/nixos/root@empty
zfs rollback -r rpool/user/home@empty
'';
# build hell
environment.noXlibs = lib.mkForce false;
# minimal profile
documentation.nixos.enable = lib.mkForce false;
programs.command-not-found.enable = lib.mkForce false;
xdg.autostart.enable = lib.mkForce false;
xdg.icons.enable = lib.mkForce false;
xdg.mime.enable = lib.mkForce false;
xdg.sounds.enable = lib.mkForce false;
services.udisks2.enable = lib.mkForce false;
fonts.enableDefaultFonts = lib.mkForce false;
fonts.fonts = [ (pkgs.nerdfonts.override { fonts = [ "FiraCode" "VictorMono" ]; }) ];
security.polkit.enable = true;
# security.pam.enableSSHAgentAuth = true;
services.zfs = {
autoScrub.enable = true;
autoScrub.interval = "daily";
trim.enable = true;
trim.interval = "weekly";
};
# hardened
networking.firewall.enable = true;
networking.firewall.allowedTCPPorts = [];
networking.firewall.allowedUDPPorts = [];
systemd.coredump.enable = false;
programs.firejail.enable = true;
# scudo memalloc is unstable
# environment.memoryAllocator.provider = "libc";
# environment.memoryAllocator.provider = "graphene-hardened";
networking.wireless.enable = false;
networking.networkmanager.enable = false;
networking.hostName = config.device;
services.timesyncd.enable = false;
services.openntpd.enable = true;
networking.timeServers = [
"0.ru.pool.ntp.org"
"1.ru.pool.ntp.org"
"2.ru.pool.ntp.org"
"3.ru.pool.ntp.org"
"0.europe.pool.ntp.org"
"1.europe.pool.ntp.org"
"2.europe.pool.ntp.org"
"3.europe.pool.ntp.org"
] ++ options.networking.timeServers.default;
home-manager.users.${config.mainuser} = {
home.file.".config/libvirt/libvirt.conf".text = ''
uri_default = "qemu:///system"
'';
home.packages = with pkgs; [ bat podman-compose ];
xdg.mime.enable = false;
home.stateVersion = "22.11";
};
system.stateVersion = "22.11";
}

View File

@ -0,0 +1,108 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:
{
imports =
[ (modulesPath + "/profiles/qemu-guest.nix")
];
boot.initrd.availableKernelModules = [ "ahci" "virtio_pci" "xhci_pci" "sd_mod" "sr_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-amd" ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "rpool/nixos/root";
fsType = "zfs"; options = [ "zfsutil" "X-mount.mkdir" ];
};
fileSystems."/home" =
{ device = "rpool/user/home";
fsType = "zfs"; options = [ "zfsutil" "X-mount.mkdir" ];
};
fileSystems."/persist" =
{ device = "rpool/persistent/impermanence";
fsType = "zfs"; options = [ "zfsutil" "X-mount.mkdir" ];
};
fileSystems."/srv" =
{ device = "rpool/persistent/servers";
fsType = "zfs"; options = [ "zfsutil" "X-mount.mkdir" ];
};
fileSystems."/etc/secrets" =
{ device = "rpool/persistent/secrets";
fsType = "zfs"; options = [ "zfsutil" "X-mount.mkdir" ];
};
fileSystems."/nix" =
{ device = "rpool/persistent/nix";
fsType = "zfs"; options = [ "zfsutil" "X-mount.mkdir" ];
};
fileSystems."/var/log" =
{ device = "rpool/persistent/log";
fsType = "zfs"; options = [ "zfsutil" "X-mount.mkdir" ];
};
fileSystems."/var/lib/docker" =
{ device = "rpool/persistent/docker";
fsType = "zfs"; options = [ "zfsutil" "X-mount.mkdir" ];
};
fileSystems."/var/lib/podman" =
{ device = "rpool/persistent/podman";
fsType = "zfs"; options = [ "zfsutil" "X-mount.mkdir" ];
};
fileSystems."/var/lib/nixos-containers" =
{ device = "rpool/persistent/nixos-containers";
fsType = "zfs"; options = [ "zfsutil" "X-mount.mkdir" ];
};
fileSystems."/media/bittorrent" =
{ device = "rpool/persistent/bittorrent";
fsType = "zfs"; options = [ "zfsutil" "X-mount.mkdir" ];
};
fileSystems."/media/libvirt" =
{ device = "rpool/persistent/libvirt";
fsType = "zfs"; options = [ "zfsutil" "X-mount.mkdir" ];
};
fileSystems."/boot" =
{ device = "bpool/nixos/boot";
fsType = "zfs"; options = [ "zfsutil" "X-mount.mkdir" ];
};
fileSystems."/boot/efi" =
{ device = "/dev/disk/by-uuid/A3BF-2C90";
fsType = "vfat";
};
swapDevices = [
{
device = "/dev/disk/by-partuuid/c40f4598-4250-4afd-9778-b79619bda1bc";
# randomEncryption.enable = true;
# randomEncryption.allowDiscards = true;
}
];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.enp2s0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
networking.hostId = "c63612aa";
boot.zfs.devNodes = "/dev/disk/by-id";
boot.supportedFilesystems = [ "zfs" ];
boot.initrd.luks.devices."cryptroot".device = "/dev/disk/by-partuuid/47af6a50-2995-42e8-a0f2-844297fe1dc5";
boot.initrd.luks.devices."cryptboot".device = "/dev/disk/by-partuuid/1cdbdb3a-d01c-4f9d-adbb-3bb5e805aca1";
}

View File

@ -0,0 +1 @@
x86_64-linux

View File

@ -0,0 +1,77 @@
{ config, pkgs, lib, ... }: {
virtualisation = {
oci-containers.backend = lib.mkForce "podman";
docker.enable = lib.mkForce false;
podman = {
enable = true;
extraPackages = [ pkgs.zfs ];
# dockerCompat = true;
defaultNetwork.dnsname.enable = true;
# dockerSocket.enable = true;
};
containers.registries.search = [
"docker.io" "gcr.io" "quay.io"
];
containers.storage.settings = {
storage = {
driver = "zfs";
graphroot = "/var/lib/podman/storage";
runroot = "/run/containers/storage";
};
};
lxd = {
enable = true;
zfsSupport = true;
recommendedSysctlSettings = true;
};
lxc = {
enable = true;
lxcfs.enable = true;
systemConfig = ''
lxc.lxcpath = /var/lib/lxd/containers
lxc.bdev.zfs.root = rpool/persistent/lxd
'';
# defaultConfig = ''
# lxc.idmap = u 0 100000 65535
# lxc.idmap = g 0 100000 65535
# lxc.include = ${pkgs.lxcfs}/share/lxc/config/common.conf.d/00-lxcfs.conf
# '';
};
libvirtd = {
enable = true;
qemu = {
ovmf.enable = true;
ovmf.packages = [ pkgs.OVMFFull.fd ];
runAsRoot = false;
};
onBoot = "ignore";
onShutdown = "shutdown";
};
};
security.unprivilegedUsernsClone = true;
# users.users.podmanmanager = {
# uid = 1100;
# isSystemUser = true;
# description = "User that runs podman containers";
# autoSubUidGidRange = true;
# createHome = true;
# extraGroups = [ "podman" ];
# hashedPassword = "!";
# home = "/home/podmanmanager";
# group = "podmanmanager";
# };
# users.groups.podmanmanager = {};
users.users.${config.mainuser} = {
subUidRanges = [{
count = 1000;
startUid = 10000;
}];
subGidRanges = [{
count = 1000;
startGid = 10000;
}];
};
}

View File

@ -0,0 +1,385 @@
set -eux
# Make sure everything is defined as an env var
autoReboot="${autoReboot?}"
flakesPath="${flakesPath?}"
hostname="${hostname?}"
mainUser="${mainUser?}"
debug="${debug?}"
entireDisk="${entireDisk?}"
nullifyDisk="${nullifyDisk?}"
disk="${disk?}"
bootPartition="${bootPartition?}"
rootPartition="${rootPartition?}"
swapPartition="${swapPartition?}"
efiSize="${efiSize?}"
bootSize="${bootSize?}"
rootSize="${rootSize?}"
swapSize="${swapSize?}"
useEncryption="${useEncryption?}"
useSwap="${useSwap?}"
argonIterTime="${argonIterTime?}"
cryptrootName="${cryptrootName?}"
cryptbootName="${cryptbootName?}"
passwordFile="${passwordFile?}"
zfsAshift="${zfsAshift?}"
rootPoolReservation="${rootPoolReservation?}"
bootPoolReservation="${bootPoolReservation?}"
usePersistModule="${usePersistModule?}"
persistRoot="${persistRoot?}"
persistHome="${persistHome?}"
if [ "$debug" = "true" ]; then
cat >&2 << FIN
autoReboot="${autoReboot}"
flakesPath="${flakesPath}"
hostname="${hostname}"
mainUser="${mainUser}"
debug="${debug}"
entireDisk="${entireDisk}"
nullifyDisk="${nullifyDisk}"
disk="${disk}"
bootPartition="${bootPartition}"
rootPartition="${rootPartition}"
swapPartition="${swapPartition}"
efiSize="${efiSize}"
bootSize="${bootSize}"
rootSize="${rootSize}"
swapSize="${swapSize}"
useEncryption="${useEncryption}"
useSwap="${useSwap}"
argonIterTime="${argonIterTime}"
cryptrootName="${cryptrootName}"
cryptbootName="${cryptbootName}"
passwordFile="${passwordFile}"
zfsAshift="${zfsAshift}"
rootPoolReservation="${rootPoolReservation}"
bootPoolReservation="${bootPoolReservation}"
usePersistModule="${usePersistModule}"
persistRoot="${persistRoot}"
persistHome="${persistHome}"
FIN
fi
if [ ! -d "${flakesPath}" ]; then
pprint "flakesPath does not exists!"
exit 2
fi
if [ "$useEncryption" = "true" && ! -f "${passwordFile}" ]; then
pprint "passwordFile does not exists!"
exit 2
fi
pprint () {
local timestamp
timestamp=$(date +%FT%T.%3NZ)
echo -e "${timestamp} $1" 1>&2
}
create_new_part_table() {
wack=0
diskByID=""
if echo $disk | grep '/dev/disk/by-id'; then
diskByID=$disk
else
byid=$(find -L /dev/disk -samefile $disk | grep by-id)
if [ "$byid" = "" ]; then
pprint "fatal: Could not find a /dev/disk/by-id symlink for %s\n" "$disk"
wack=1
else
diskByID=$byid
fi
fi
if [ "$debug" = "true" ]; then
cat >&2 << FIN
diskByID=${diskByID}
FIN
fi
# The for loop has the actual output
if [ "${wack}" -gt 0 ]; then
exit 2
fi
if [ "$nullifyDisk" = "true" ]; then
diskname=$(basename $(readlink -f ${diskByID}))
isHDD=$(cat /sys/block/${diskname}/queue/rotational)
if [ "$isHDD" = 1 ]; then
cat /dev/zero > "$diskByID" || true
else
blkdiscard "$diskByID"
fi
fi
# partitioning
sgdisk --zap-all "$diskByID"
pprint "Creating boot (EFI) partition"
sgdisk -n1:1MiB:+$efiSize -t1:EF00 "$diskByID"
efiPart="$diskByID-part1"
pprint "Creating boot (ZFS) partition"
if [ "$useEncryption" = "true" ]; then
sgdisk -n2:0:+$bootSize -t2:8309 "$diskByID"
else
sgdisk -n2:0:+$bootSize -t2:BF00 "$diskByID"
fi
bootPart="$diskByID-part2"
if [ "$useSwap" = "true" ]; then
pprint "Creating SWAP partition"
sgdisk -n4:0:+$swapSize -t4:8200 "$diskByID"
swapPart="$diskByID-part4"
fi
if [ "$useEncryption" = "true" ]; then
pprint "Creating LUKS partition"
sgdisk -n3:0:$rootSize -t3:8309 "$diskByID"
else
pprint "Creating ROOT partition"
sgdisk -n3:0:$rootSize -t3:BF00 "$diskByID"
fi
rootPart="$diskByID-part3"
partprobe "$diskByID"
sleep 1
pprint "Format EFI partition $efiPart"
mkfs.vfat -n EFI "$efiPart"
}
# Installation begin
if [ "$entireDisk" = "true" ]; then
create_new_part_table
else
use_existing_part_table
fi
if [ "$useEncryption" = "true" ]; then
password=$(cat $passwordFile)
dd if=/dev/urandom of=/tmp/keyfile0.bin bs=1024 count=4
pprint "Creating LUKS container on $bootPart"
echo -n "$password" | cryptsetup --type luks2 --pbkdf argon2id --iter-time $argonIterTime -c aes-xts-plain64 -s 512 -h sha256 luksFormat "$bootPart" -
pprint "Add keyfile to LUKS container on $bootPart"
echo -n "$password" | cryptsetup luksAddKey $bootPart /tmp/keyfile0.bin -
pprint "Open LUKS container on $bootPart"
cryptsetup luksOpen --allow-discards "$bootPart" "$cryptbootName" -d /tmp/keyfile0.bin
pprint "Creating LUKS container on $rootPart"
echo -n "$password" | cryptsetup --type luks2 --pbkdf argon2id --iter-time $argonIterTime -c aes-xts-plain64 -s 512 -h sha256 luksFormat "$rootPart" -
pprint "Add keyfile to LUKS container on $rootPart"
echo -n "$password" | cryptsetup luksAddKey $rootPart /tmp/keyfile0.bin -
pprint "Open LUKS container on $rootPart"
cryptsetup luksOpen --allow-discards "$rootPart" "$cryptrootName" -d /tmp/keyfile0.bin
bootPool="$(ls /dev/disk/by-id/dm-uuid-*$cryptbootName)"
rootPool="$(ls /dev/disk/by-id/dm-uuid-*$cryptrootName)"
else
bootPool="$bootPart"
rootPool="$rootPart"
fi
pprint "Create ZFS root pool on $rootPool"
zpool create \
-f \
-o ashift=$zfsAshift \
-o autotrim=on \
-O acltype=posixacl \
-O atime=on \
-O canmount=off \
-O compression=zstd \
-O dnodesize=auto \
-O normalization=formD \
-O relatime=on \
-O xattr=sa \
-O dedup=off \
-O mountpoint=/ \
-R /mnt \
rpool "$rootPool"
pprint "Create ZFS root datasets"
if [ "$rootPoolReservation" != "0" ]; then
zfs create -o refreservation=$rootPoolReservation -o canmount=off -o mountpoint=none rpool/reserved
fi
# top level datasets
zfs create -o canmount=off -o mountpoint=none rpool/nixos
zfs create -o canmount=off -o mountpoint=none rpool/user
zfs create -o canmount=off -o mountpoint=none rpool/persistent
# empty root
zfs create -o canmount=noauto -o mountpoint=/ rpool/nixos/root
zfs mount rpool/nixos/root
zfs create -o canmount=on -o mountpoint=/home rpool/user/home
# persistent across boots
if [ "$usePersistModule" = "true" ]; then
zfs create -o canmount=on -o mountpoint=$persistRoot rpool/persistent/impermanence
mkdir -p /mnt$persistRoot$persistHome
chown 1000:100 /mnt$persistRoot$persistHome
chmod 755 /mnt$persistRoot$persistHome
fi
zfs create -o canmount=on -o mountpoint=/srv rpool/persistent/servers
zfs create -o canmount=on -o mountpoint=/etc/secrets rpool/persistent/secrets
zfs create -o canmount=on -o mountpoint=/nix rpool/persistent/nix
zfs create -o canmount=on -o mountpoint=/var/log rpool/persistent/log
zfs create -o canmount=noauto -o atime=off rpool/persistent/lxd
zfs create -o canmount=on -o mountpoint=/var/lib/docker -o atime=off rpool/persistent/docker
zfs create -o canmount=on -o mountpoint=/var/lib/podman -o atime=off rpool/persistent/podman
zfs create -o canmount=on -o mountpoint=/var/lib/nixos-containers -o atime=off rpool/persistent/nixos-containers
zfs create -o canmount=on -o mountpoint=/media/bittorrent -o atime=off -o recordsize=16K -o compression=lz4 rpool/persistent/bittorrent
chown 1000:100 /mnt/media/bittorrent
chmod 775 /mnt/media/bittorrent
zfs create -o canmount=on -o mountpoint=/media/libvirt -o atime=off -o recordsize=16K -o compression=lz4 rpool/persistent/libvirt
chown 1000:67 /mnt/media/libvirt
chmod 775 /mnt/media/libvirt
# Create empty zfs snapshots
zfs snapshot rpool/nixos@empty
zfs snapshot rpool/nixos/root@empty
zfs snapshot rpool/user@empty
zfs snapshot rpool/user/home@empty
zfs snapshot rpool/persistent@empty
zfs snapshot rpool/persistent/impermanence@empty
zfs snapshot rpool/persistent/servers@empty
zfs snapshot rpool/persistent/secrets@empty
zfs snapshot rpool/persistent/nix@empty
zfs snapshot rpool/persistent/log@empty
zfs snapshot rpool/persistent/lxd@empty
zfs snapshot rpool/persistent/docker@empty
zfs snapshot rpool/persistent/podman@empty
zfs snapshot rpool/persistent/nixos-containers@empty
zfs snapshot rpool/persistent/bittorrent@empty
zfs snapshot rpool/persistent/libvirt@empty
pprint "Create ZFS boot pool on $bootPool"
zpool create \
-f \
-o compatibility=grub2 \
-o ashift=$zfsAshift \
-o autotrim=on \
-O acltype=posixacl \
-O atime=on \
-O canmount=off \
-O compression=lz4 \
-O devices=off \
-O normalization=formD \
-O relatime=on \
-O xattr=sa \
-O dedup=off \
-O mountpoint=/boot \
-R /mnt \
bpool "$bootPool"
pprint "Create ZFS boot datasets"
if [ "$bootPoolReservation" != "0" ]; then
zfs create -o refreservation=$bootPoolReservation -o canmount=off -o mountpoint=none bpool/reserved
fi
zfs create -o canmount=off -o mountpoint=none bpool/nixos
zfs create -o canmount=on -o mountpoint=/boot bpool/nixos/boot
zfs snapshot bpool/nixos@empty
zfs snapshot bpool/nixos/boot@empty
# Disable cache, stale cache will prevent system from booting
if [ "$usePersistModule" = "true" ]; then
mkdir -p /mnt"$persistRoot"/etc/zfs/
rm -f /mnt"$persistRoot"/etc/zfs/zpool.cache
touch /mnt"$persistRoot"/etc/zfs/zpool.cache
chmod a-w /mnt"$persistRoot"/etc/zfs/zpool.cache
chattr +i /mnt"$persistRoot"/etc/zfs/zpool.cache
else
mkdir -p /mnt/etc/zfs/
rm -f /mnt/etc/zfs/zpool.cache
touch /mnt/etc/zfs/zpool.cache
chmod a-w /mnt/etc/zfs/zpool.cache
chattr +i /mnt/etc/zfs/zpool.cache
fi
mkdir -p /mnt/boot/efi
mount -t vfat "$efiPart" /mnt/boot/efi
if [ "$useSwap" = "true" ]; then
mkswap -L swap -f "$swapPart"
fi
pprint "Generate NixOS configuration"
configExists=false
[ -f $flakesPath/machines/$hostname/configuration.nix ] && configExists=true
nixos-generate-config --root /mnt --dir $flakesPath/machines/$hostname
[ "$configExists" = "false" ] && rm -f $flakesPath/machines/$hostname/configuration.nix
pprint "Append ZFS configuration to hardware-configuration.nix"
hostID=$(head -c8 /etc/machine-id)
hardwareConfig=$(mktemp)
if [ "$useEncryption" = "true" ]; then
bootPartUuid=$(blkid --match-tag PARTUUID --output value "$bootPart")
rootPartUuid=$(blkid --match-tag PARTUUID --output value "$rootPart")
cat <<CONFIG > "$hardwareConfig"
networking.hostId = "$hostID";
boot.zfs.devNodes = "/dev/disk/by-id";
boot.supportedFilesystems = [ "zfs" ];
boot.initrd.luks.devices."$cryptbootName".device = "/dev/disk/by-partuuid/$bootPartUuid";
boot.initrd.luks.devices."$cryptrootName".device = "/dev/disk/by-partuuid/$rootPartUuid";
CONFIG
else
cat <<CONFIG > "$hardwareConfig"
networking.hostId = "$hostID";
boot.zfs.devNodes = "/dev/disk/by-id";
boot.supportedFilesystems = [ "zfs" ];
CONFIG
fi
sed -i "\$e cat $hardwareConfig" $flakesPath/machines/$hostname/hardware-configuration.nix
sed -i 's|fsType = "zfs";|fsType = "zfs"; options = [ "zfsutil" "X-mount.mkdir" ];|g' $flakesPath/machines/$hostname/hardware-configuration.nix
if [ "$useSwap" == "true" ]; then
swapPartUuid=$(blkid --match-tag PARTUUID --output value "$swapPart")
sed -i "s|swapDevices = \[ \];|swapDevices = \[\n {\n device = \"/dev/disk/by-partuuid/$swapPartUuid\";\n randomEncryption.enable = true;\n randomEncryption.allowDiscards = true;\n }\n \];|" $flakesPath/machines/$hostname/hardware-configuration.nix
fi
chown 1000:100 $flakesPath/machines/$hostname/hardware-configuration.nix
git config --global --add safe.directory "$flakesPath"
git -C "$flakesPath" add -A
configPath="/mnt/home/"$mainUser"/nixos-config"
mkdir -p $configPath
chown -R 1000:100 /mnt/home/$mainUser
cp -aT $flakesPath $configPath
pprint "Gen ssh host key for initrd"
ssh-keygen -t ed25519 -N "" -f /mnt/etc/secrets/ssh_host_key
chown root:root /mnt/etc/secrets/ssh_host_key
chmod 600 /mnt/etc/secrets/ssh_host_key
if [ "$useEncryption" = "true" ]; then
cp /tmp/keyfile0.bin /mnt/etc/secrets/keyfile0.bin
chmod 000 /mnt/etc/secrets/keyfile*.bin
fi
if [ "$debug" != "true" ]; then
nixos-install --flake "$configPath/#$hostname" --root /mnt --no-root-passwd
fi
umount -Rl /mnt
zpool export -a
if [ "$useEncryption" = "true" ]; then
cryptsetup luksClose $cryptbootName
cryptsetup luksClose $cryptrootName
fi
if [ "$autoReboot" = "true" ]; then
if ! systemctl reboot --firmware-setup ; then
pprint "Reboot into efi firmware setup failed! Shutdown in 30 seconds"
sleep 30
systemctl poweroff
fi
fi

View File

@ -0,0 +1,262 @@
{ config, pkgs, lib, ... }:
with lib;
let
cfg = config.autoinstall;
# partitionsAttrs = {
# bootPartition = mkOption {
# type = types.str;
# default = "";
# description = "Boot partition";
# };
# rootPartition = mkOption {
# type = types.str;
# default = "";
# description = "Root partition";
# };
# swapPartition = mkOption {
# type = types.nullOr types.str;
# default = "";
# description = "Swap partition";
# };
# };
in{
options = {
autoinstall = {
autoReboot = mkOption {
type = types.bool;
default = false;
description = "Auto reboot after install complete successufuly";
};
partitioning = {
useEntireDisk = mkOption {
type = types.bool;
default = true;
description = "Wipe entire disk and write new partition table";
};
nullifyDisk = mkOption {
type = types.bool;
default = false;
description = "Nullify entire disk. Very slow!";
};
disk = mkOption {
type = types.str;
default = "";
description = "Path to the disk to wipe";
};
# partitions = mkOption {
# type = types.nullOr attrsOf partitionsAttrs;
# default = null;
# description = "If not wipe entire disk";
# };
};
debug = mkOption {
type = types.bool;
default = false;
description = "If we should exit before installing or not to let debugging occur";
};
hostname = mkOption {
type = types.str;
default = "";
description = "The hostname the system will be known as";
};
mainuser = mkOption {
type = types.str;
default = "alukard";
description = "Name of the main user (used for creation of home folder)";
};
flakesPath = mkOption {
type = types.str;
default = "";
description = "Path to config folder with flakes";
};
efiSize = mkOption {
type = types.str;
default = "512MiB";
description = "Size of EFI partition";
};
bootSize = mkOption {
type = types.str;
default = "4GiB";
description = "Size of boot partition";
};
rootSize = mkOption {
type = types.str;
default = "0";
description = "Size of root partition. If using 0, expand root partition to entire free space on disk";
};
swapPartition = {
enable = mkOption {
type = types.bool;
default = true;
description = "Use swap partition";
};
size = mkOption {
type = types.str;
default = "2GiB";
description = "Size of swap partition";
};
};
encryption = {
enable = mkOption {
type = types.bool;
default = false;
description = "Use luks full-disk encryption";
};
argonIterTime = mkOption {
type = types.str;
default = "5000";
description = "iter-time for argon2 in ms";
};
cryptBoot = mkOption {
type = types.str;
default = "cryptboot";
description = "Name of luks boot device";
};
cryptRoot = mkOption {
type = types.str;
default = "cryptroot";
description = "Name of luks root device";
};
passwordFile = mkOption {
type = types.str;
default = "";
description = "Path to file that contains password that pass to luksFormat";
};
};
zfsOpts = {
ashift = mkOption {
type = types.int;
default = 13;
description = "ashift passed to zfs pool creation";
};
bootPoolReservation = mkOption {
type = types.str;
default = "0";
description = "Reserve some space on boot pool";
};
rootPoolReservation = mkOption {
type = types.str;
default = "0";
description = "Reserve some space on root pool";
};
};
persist = {
enable = mkOption {
type = types.bool;
default = true;
description = "Use persist module";
};
persistRoot = mkOption {
type = types.str;
default = "/persist";
description = "Path to persist mount point";
};
persistHome = mkOption {
type = types.str;
default = "/home/${cfg.mainuser}";
description = "Path to home user folder relative to persistRoot";
};
};
# rootDevices = mkOption {
# type = types.listOf types.str;
# default = "/dev/sda";
# description = "the root block device that justdoit will nuke from orbit and force nixos onto";
# };
# bootSize = mkOption {
# type = types.str;
# default = "512MiB";
# description = "/boot size";
# };
# swapSize = mkOption {
# type = types.str;
# default = "2GiB";
# description = "swap size";
# };
# osSize = mkOption {
# type = types.str;
# default = "10GiB";
# description = "size of / partition/whatever basically";
# };
# wipe = mkOption {
# type = types.bool;
# default = false;
# description = "run wipefs on devices prior to install";
# };
# zero = mkOption {
# type = types.bool;
# default = false;
# description = "zero out devices prior to install (time consuming)";
# };
# dedicatedBoot = mkOption {
# type = types.str;
# default = "";
# description = "If there should be a dedicated /boot device fill this in with the device name.";
# };
# # Needs a lot more testing somehow, vm's?
# flavor = mkOption {
# type = types.enum [ "single" "zfs" "lvm" ];
# default = "zfs";
# description = "Specify the disk layout type, single = no zfs mirroring or lvm mirroring";
# };
};
};
config = {
assertions = [{
assertion = cfg.flakesPath != "";
message = "flakesPath can't be empty";
} {
assertion = cfg.hostname != "";
message = "hostname can't be empty";
} {
assertion = !(cfg.encryption.enable && cfg.encryption.passwordFile == "");
message = "If you use encryption, you need to set path to password file";
}];
systemd.services."autoinstall-${cfg.hostname}" = {
description = "NixOS Autoinstall";
# wantedBy = [ "multi-user.target" ];
# after = [ "network.target" "polkit.service" ];
path = with pkgs; [
"/run/current-system/sw/"
"/usr/bin/"
"${systemd}/bin/"
"${git}/bin"
];
script = with pkgs; (builtins.readFile ./autoinstall.sh);
environment = config.nix.envVars // rec {
inherit (config.environment.sessionVariables) NIX_PATH;
autoReboot = boolToString cfg.autoReboot;
entireDisk = boolToString cfg.partitioning.useEntireDisk;
nullifyDisk = boolToString cfg.partitioning.nullifyDisk;
disk = cfg.partitioning.disk or "0";
bootPartition = cfg.partitioning.partitions.bootPartition or "0";
rootPartition = cfg.partitioning.partitions.rootPartition or "0";
swapPartition = cfg.partitioning.partitions.swapPartition or "0";
debug = boolToString cfg.debug;
hostname = cfg.hostname;
flakesPath = cfg.flakesPath;
mainUser = cfg.mainuser;
useSwap = boolToString cfg.swapPartition.enable;
useEncryption = boolToString cfg.encryption.enable;
efiSize = cfg.efiSize;
bootSize = cfg.bootSize;
rootSize = cfg.rootSize;
swapSize = cfg.swapPartition.size or "0";
argonIterTime = cfg.encryption.argonIterTime;
cryptrootName = cfg.encryption.cryptBoot;
cryptbootName = cfg.encryption.cryptRoot;
passwordFile = cfg.encryption.passwordFile;
zfsAshift = toString cfg.zfsOpts.ashift;
bootPoolReservation = cfg.zfsOpts.bootPoolReservation;
rootPoolReservation = cfg.zfsOpts.rootPoolReservation;
usePersistModule = boolToString cfg.persist.enable;
persistRoot = cfg.persist.persistRoot;
persistHome = cfg.persist.persistHome;
HOME = "/root";
# LIBSH = "${./lib.sh}:${../../static/src/lib.sh}";
};
serviceConfig = { Type = "oneshot"; };
};
};
}