Files organization update

This commit is contained in:
Raphaël Numbus
2026-01-25 09:06:31 +01:00
parent eb17551aec
commit d4ea4ea1a8
39 changed files with 236 additions and 89 deletions
+57
View File
@@ -0,0 +1,57 @@
{ lib, ... }:
{
disko.devices = {
# Boot disk LVM configuration
lvm_vg = {
pool = {
type = "lvm_vg";
lvs = {
root = {
size = "100%FREE";
content.type = "filesystem";
content.format = "btrfs";
content.mountpoint = "/";
};
swap = {
size = "16G";
content.type = "swap";
};
};
};
};
disk = {
# Boot disk
"boot-1" = {
type = "disk";
device = "${BOOT_DISK_1_ID}";
content = {
type = "gpt";
partitions = {
ESP = {
size = "1G";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "umask=0077" ];
};
};
luks = {
size = "100%";
content = {
type = "luks";
name = "crypted-boot-1";
settings = {
keyFile = "/etc/secrets/disks/boot-1";
allowDiscards = true;
};
content = {
type = "lvm_pv";
vg = "pool";
};
};
};
};
};
};
+75
View File
@@ -0,0 +1,75 @@
{ lib, ... }:
{
disko.devices = {
disk = {
"boot-1" = {
type = "disk";
device = "${BOOT_DISK_1_ID}";
content = {
type = "gpt";
partitions = {
ESP = {
size = "1G";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "umask=0077" ];
};
};
crypt_p1 = {
size = "100%";
content = {
type = "luks";
name = "crypted-boot-1";
settings = {
keyFile = "/etc/secrets/disks/boot-1";
allowDiscards = true;
};
};
};
};
};
};
"boot-2" = {
type = "disk";
device = "${BOOT_DISK_2_ID}";
content = {
type = "gpt";
partitions = {
crypt_p2 = {
size = "100%";
content = {
type = "luks";
name = "crypted-boot-2";
settings = {
keyFile = "/etc/secrets/disks/boot-2";
allowDiscards = true;
};
content = {
type = "btrfs";
extraArgs = [
"-d raid1"
"/dev/mapper/crypted-boot-1"
];
subvolumes = {
"/root" = {
mountpoint = "/";
mountOptions = [
"rw"
"relatime"
"ssd"
];
};
"/swap" = {
mountpoint = "none";
swap.size = "16G";
};
};
};
};
};
};
};
};
+28
View File
@@ -0,0 +1,28 @@
"content-${j}" = {
type = "disk";
device = "${CONTENT_DISK_ID}";
content = {
type = "gpt";
partitions = {
luks = {
size = "100%";
content = {
type = "luks";
name = "crypted-content-${j}";
initrdUnlock = false;
settings = {
keyFile = "/etc/secrets/disks/content-${j}";
allowDiscards = ${ALLOW_DISCARDS:-false};
crypttabExtraOpts = [ "nofail" "noauto" ];
};
content = {
type = "filesystem";
format = "xfs";
mountpoint = "/mnt/content-${j}";
mountOptions = [ "nofail" "noauto" ];
};
};
};
};
};
};
+56
View File
@@ -0,0 +1,56 @@
# Data mirror disks
"content-1" = {
type = "disk";
device = "/dev/disk/by-id/ata-FUJITSU_MHW2120BH_NZ2TT772DCN5";
content = {
type = "gpt";
partitions = {
"data-1" = {
size = "$PARTITION_SIZE";
content = {
type = "luks";
name = "crypted-content-1";
settings.keyFile = "/etc/secrets/disks/content-1";
content = {
type = "mdraid";
name = "data-storage";
};
};
};
};
};
};
"parity-1" = {
type = "disk";
device = "/dev/disk/by-id/ata-TOSHIBA_MQ04ABF100_X7CXT0D8T";
content = {
type = "gpt";
partitions = {
"parity-1" = {
size = "$PARTITION_SIZE";
content = {
type = "luks";
name = "crypted-parity-1";
settings.keyFile = "/etc/secrets/disks/parity-1";
content = {
type = "mdraid";
name = "data-storage";
};
};
};
};
};
};
};
# RAID 1 Configuration
mdadm = {
"data-storage" = {
type = "mdadm";
level = 1;
content = {
type = "filesystem";
format = "xfs";
mountpoint = "/mnt/data-storage";
};
};
+28
View File
@@ -0,0 +1,28 @@
"parity-${j}" = {
type = "disk";
device = "${PARITY_DISK_ID}";
content = {
type = "gpt";
partitions = {
luks = {
size = "100%";
content = {
type = "luks";
name = "crypted-parity-${j}";
initrdUnlock = false;
settings = {
keyFile = "/etc/secrets/disks/parity-${j}";
allowDiscards = ${ALLOW_DISCARDS:-false};
crypttabExtraOpts = [ "nofail" "noauto" ];
};
content = {
type = "filesystem";
format = "xfs";
mountpoint = "/mnt/parity-${j}";
mountOptions = [ "nofail" "noauto" ];
};
};
};
};
};
};
+124
View File
@@ -0,0 +1,124 @@
{ lib, utils, config, ... }:
let
inherit (lib)
head
optional
foldl'
nameValuePair
listToAttrs
optionals
concatStringsSep
sortOn
mkIf
mkEnableOption
mkOption
types
;
in
{
options = {
systemIdentity = {
enable = mkEnableOption "hashing of Luks values into PCR 15 and subsequent checks";
pcr15 = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
The expected value of PCR 15 after all luks partitions have been unlocked
Should be a 64 character hex string as ouput by the sha256 field of
'systemd-analyze pcrs 15 --json=short'
If set to null (the default) it will not check the value.
If the check fails the boot will abort and you will be dropped into an emergency shell, if enabled.
In ermergency shell type:
'systemctl disable check-pcrs'
'systemctl default'
to continue booting
'';
};
};
boot.initrd.luks.devices = lib.mkOption {
type =
with lib.types;
attrsOf (submodule {
config.crypttabExtraOpts = optionals config.systemIdentity.enable [
"tpm2-device=auto"
"tpm2-measure-pcr=yes"
];
});
};
};
config = mkIf config.systemIdentity.enable {
boot.kernelParams = [
"rd.luks=no"
];
boot.initrd.systemd.services =
{
check-pcrs = mkIf (config.systemIdentity.pcr15 != null) {
script = ''
echo "Checking PCR 15 value"
if [[ $(systemd-analyze pcrs 15 --json=short | jq -r ".[0].sha256") != "${config.systemIdentity.pcr15}" ]] ; then
echo "PCR 15 check failed"
exit 1
else
echo "PCR 15 check succeeded"
fi
'';
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
unitConfig.DefaultDependencies = "no";
after = [ "cryptsetup.target" ];
before = [ "sysroot.mount" ];
requiredBy = [ "sysroot.mount" ];
};
}
// (listToAttrs (
foldl' (
acc: attrs:
let
extraOpts = attrs.value.crypttabExtraOpts ++ (optional attrs.value.allowDiscards "discard");
cfg = config.boot.initrd.systemd;
in
[
(nameValuePair "cryptsetup-${attrs.name}" {
unitConfig = {
Description = "Cryptography setup for ${attrs.name}";
DefaultDependencies = "no";
IgnoreOnIsolate = true;
Conflicts = [ "umount.target" ];
BindsTo = "${utils.escapeSystemdPath attrs.value.device}.device";
};
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
TimeoutSec = "infinity";
KeyringMode = "shared";
OOMScoreAdjust = 500;
ImportCredential = "cryptsetup.*";
ExecStart = ''${cfg.package}/bin/systemd-cryptsetup attach '${attrs.name}' '${attrs.value.device}' '-' '${concatStringsSep "," extraOpts}' '';
ExecStop = ''${cfg.package}/bin/systemd-cryptsetup detach '${attrs.name}' '';
};
after =
[
"cryptsetup-pre.target"
"systemd-udevd-kernel.socket"
"${utils.escapeSystemdPath attrs.value.device}.device"
]
++ (optional cfg.tpm2.enable "systemd-tpm2-setup-early.service")
++ optional (acc != [ ]) "${(head acc).name}.service";
before = [
"blockdev@dev-mapper-${attrs.name}.target"
"cryptsetup.target"
"umount.target"
];
wants = [ "blockdev@dev-mapper-${attrs.name}.target" ];
requiredBy = [ "sysroot.mount" ];
})
]
++ acc
) [ ] (sortOn (x: x.name) (lib.attrsets.attrsToList config.boot.initrd.luks.devices))
));
};
}
+60
View File
@@ -0,0 +1,60 @@
{ config, lib, pkgs, ... }:
{
### --> MergerFS setup
fileSystems."/mnt/data" = {
device = "/mnt/content-*";
fsType = "fuse.mergerfs";
options = [
"category.create=ff"
"cache.files=partial"
"dropcacheonclose=true"
"defaults"
"noauto"
"nofail"
"allow_other"
"moveonenospc=1"
"minfreespace=50G"
"func.getattr=newest"
"fsname=mergerfs_data"
"x-mount.mkdir"
"x-systemd.automount"
"x-systemd.requires=mount-dependencies.service"
];
};
### MergerFS setup <--
systemd.services.mount-dependencies = {
description = "This service will mount the encrypted disks for mergerFS";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
# Bring the service up
ExecStart = pkgs.writeShellScript "mount-disks" ''
$MOUNT_DEPENDENCIES_START
'';
# Take it down gracefully
ExecStop = pkgs.writeShellScript "unmount-disks" ''
$MOUNT_DEPENDENCIES_STOP
'';
Restart = "on-failure";
};
};
### --> SnapRAID setup
services.snapraid = {
enable = true;
contentFiles = [
$SNAPRAID_CONTENT_FILES
];
parityFiles = [
$SNAPRAID_PARITY_FILES
];
dataDisks = {
$SNAPRAID_DATA_DISKS
};
};
### SnapRAID setup <--
}
+25
View File
@@ -0,0 +1,25 @@
{ config, pkgs, lib, ... }:
let
hardDrives = [
DISK_LIST
];
in
{
### --> Disk spindown
systemd.services.hd-idle = {
description = "External HD spin down daemon";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
ExecStart =
let
idleTime = toString 1800;
hardDriveParameter = lib.strings.concatMapStringsSep " " (x: "-a ${x} -i ${idleTime}") hardDrives;
in
"${pkgs.hd-idle}/bin/hd-idle -i 0 ${hardDriveParameter}";
};
};
### Disk spindown <--
}