feat: optional impermanence and encryption

This commit is contained in:
Swarsel 2024-12-23 17:07:47 +01:00
parent c6f64d8764
commit c3e606a759
Signed by: swarsel
GPG key ID: 26A54C31F2A4FD84
5 changed files with 149 additions and 47 deletions

View file

@ -994,7 +994,7 @@ The interesting part is in the start:
inputs.stylix.nixosModules.stylix inputs.stylix.nixosModules.stylix
inputs.lanzaboote.nixosModules.lanzaboote inputs.lanzaboote.nixosModules.lanzaboote
inputs.disko.nixosModules.disko inputs.disko.nixosModules.disko
# inputs.impermanence.nixosModules.impermanence inputs.impermanence.nixosModules.impermanence
inputs.sops-nix.nixosModules.sops inputs.sops-nix.nixosModules.sops
inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm
./profiles/common/nixos ./profiles/common/nixos
@ -1627,6 +1627,8 @@ I have removed most of the machines from this section. What remains are some hos
{ {
_module.args = { _module.args = {
withSwap = false; withSwap = false;
withImpermanence = true;
withEncryption = false;
}; };
} }
./hardware-configuration.nix ./hardware-configuration.nix
@ -1689,7 +1691,7 @@ I have removed most of the machines from this section. What remains are some hos
swarselsystems = { swarselsystems = {
wallpaper = self + /wallpaper/lenovowp.png; wallpaper = self + /wallpaper/lenovowp.png;
impermanence = false; impermanence = true;
isBtrfs = false; isBtrfs = false;
initialSetup = true; initialSetup = true;
}; };
@ -2728,6 +2730,8 @@ This program sets up a new NixOS host.
target_destination="" target_destination=""
target_user="swarsel" target_user="swarsel"
ssh_port="22" ssh_port="22"
persist_dir=""
disk_encryption=0
temp=$(mktemp -d) temp=$(mktemp -d)
function help_and_exit() { function help_and_exit() {
@ -2746,6 +2750,7 @@ This program sets up a new NixOS host.
echo " Default='${target_user}'." echo " Default='${target_user}'."
echo " --port <ssh_port> specify the ssh port to use for remote access. Default=${ssh_port}." echo " --port <ssh_port> specify the ssh port to use for remote access. Default=${ssh_port}."
echo " --impermanence Use this flag if the target machine has impermanence enabled. WARNING: Assumes /persist path." echo " --impermanence Use this flag if the target machine has impermanence enabled. WARNING: Assumes /persist path."
echo " --encryption Use this flag if the target machine has full disk encryption enabled."
echo " --debug Enable debug mode." echo " --debug Enable debug mode."
echo " -h | --help Print this help." echo " -h | --help Print this help."
exit 0 exit 0
@ -2834,6 +2839,14 @@ This program sets up a new NixOS host.
shift shift
temp=$1 temp=$1
;; ;;
--impermanence)
shift
persist_dir="/persist"
;;
--encryption)
shift
disk_encryption=1
;;
--debug) --debug)
set -x set -x
;; ;;
@ -2869,18 +2882,19 @@ This program sets up a new NixOS host.
# ------------------------ # ------------------------
green "Preparing a new ssh_host_ed25519_key pair for $target_hostname." green "Preparing a new ssh_host_ed25519_key pair for $target_hostname."
# Create the directory where sshd expects to find the host keys # Create the directory where sshd expects to find the host keys
install -d -m755 "$temp/etc/ssh" install -d -m755 "$temp/$persist_dir/etc/ssh"
# Generate host ssh key pair without a passphrase # Generate host ssh key pair without a passphrase
ssh-keygen -t ed25519 -f "$temp/etc/ssh/ssh_host_ed25519_key" -C root@"$target_hostname" -N "" ssh-keygen -t ed25519 -f "$temp/$persist_dir/etc/ssh/ssh_host_ed25519_key" -C root@"$target_hostname" -N ""
# Set the correct permissions so sshd will accept the key # Set the correct permissions so sshd will accept the key
chmod 600 "$temp/etc/ssh/ssh_host_ed25519_key" chmod 600 "$temp/$persist_dir/etc/ssh/ssh_host_ed25519_key"
echo "Adding ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" echo "Adding ssh host fingerprint at $target_destination to ~/.ssh/known_hosts"
# This will fail if we already know the host, but that's fine # This will fail if we already know the host, but that's fine
ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true
# ------------------------ # ------------------------
# when using luks, disko expects a passphrase on /tmp/disko-password, so we set it for now and will update the passphrase later # when using luks, disko expects a passphrase on /tmp/disko-password, so we set it for now and will update the passphrase later
# via the config # via the config
green "Preparing a temporary password for disko." if [ "$disk_encryption" -eq 1 ]; then
green "--encryption set: Preparing a temporary password for disko."
green "[Optional] Set disk encryption passphrase:" green "[Optional] Set disk encryption passphrase:"
read -rs luks_passphrase read -rs luks_passphrase
if [ -n "$luks_passphrase" ]; then if [ -n "$luks_passphrase" ]; then
@ -2888,6 +2902,9 @@ This program sets up a new NixOS host.
else else
$ssh_root_cmd "/bin/sh -c 'echo passphrase > /tmp/disko-password'" $ssh_root_cmd "/bin/sh -c 'echo passphrase > /tmp/disko-password'"
fi fi
else
green "--encryption not set: Not using disk encryption.."
fi
# ------------------------ # ------------------------
green "Generating hardware-config.nix for $target_hostname and adding it to the nix-config." green "Generating hardware-config.nix for $target_hostname and adding it to the nix-config."
$ssh_root_cmd "nixos-generate-config --force --no-filesystems --root /mnt" $ssh_root_cmd "nixos-generate-config --force --no-filesystems --root /mnt"
@ -2911,6 +2928,11 @@ This program sets up a new NixOS host.
fi fi
done done
# ------------------------ # ------------------------
if [ -n "$persist_dir" ]; then
$ssh_root_cmd "cp /etc/machine-id $persist_dir/etc/machine-id || true"
$ssh_root_cmd "cp -R /etc/ssh/ $persist_dir/etc/ssh/ || true"
fi
# ------------------------
green "Generating an age key based on the new ssh_host_ed25519_key." green "Generating an age key based on the new ssh_host_ed25519_key."
target_key=$( target_key=$(
ssh-keyscan -p "$ssh_port" -t ssh-ed25519 "$target_destination" 2>&1 | ssh-keyscan -p "$ssh_port" -t ssh-ed25519 "$target_destination" 2>&1 |
@ -2960,6 +2982,10 @@ This program sets up a new NixOS host.
cd "${git_root}" cd "${git_root}"
just sync "$target_user" "$target_destination" just sync "$target_user" "$target_destination"
if [ -n "$persist_dir" ]; then
$ssh_root_cmd "cp -r /home/$target_user/.dotfiles $persist_dir/.dotfiles || true"
fi
if yes_or_no "Do you want to rebuild immediately?"; then if yes_or_no "Do you want to rebuild immediately?"; then
green "Rebuilding nix-config on $target_hostname" green "Rebuilding nix-config on $target_hostname"
$ssh_root_cmd "mkdir -p /root/.local/share/nix/; printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' > /root/.local/share/nix/trusted-settings.json" $ssh_root_cmd "mkdir -p /root/.local/share/nix/; printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' > /root/.local/share/nix/trusted-settings.json"

View file

@ -163,7 +163,7 @@
inputs.stylix.nixosModules.stylix inputs.stylix.nixosModules.stylix
inputs.lanzaboote.nixosModules.lanzaboote inputs.lanzaboote.nixosModules.lanzaboote
inputs.disko.nixosModules.disko inputs.disko.nixosModules.disko
# inputs.impermanence.nixosModules.impermanence inputs.impermanence.nixosModules.impermanence
inputs.sops-nix.nixosModules.sops inputs.sops-nix.nixosModules.sops
inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm inputs.nswitch-rcm-nix.nixosModules.nswitch-rcm
./profiles/common/nixos ./profiles/common/nixos

View file

@ -10,6 +10,8 @@ in
{ {
_module.args = { _module.args = {
withSwap = false; withSwap = false;
withImpermanence = true;
withEncryption = false;
}; };
} }
./hardware-configuration.nix ./hardware-configuration.nix
@ -72,7 +74,7 @@ in
swarselsystems = { swarselsystems = {
wallpaper = self + /wallpaper/lenovowp.png; wallpaper = self + /wallpaper/lenovowp.png;
impermanence = false; impermanence = true;
isBtrfs = false; isBtrfs = false;
initialSetup = true; initialSetup = true;
}; };

View file

@ -1,8 +1,10 @@
# NOTE: ... is needed because dikso passes diskoFile # NOTE: ... is needed because dikso passes diskoFile
{ lib { lib
, pkgs , pkgs
, withSwap ? false
, swapSize , swapSize
, withSwap ? true
, withEncryption ? true
, withImpermanence ? true
, ... , ...
}: }:
{ {
@ -26,7 +28,47 @@
mountOptions = [ "defaults" ]; mountOptions = [ "defaults" ];
}; };
}; };
luks = { root = lib.mkIf (!withEncryption) {
size = "100%";
content = {
type = "btrfs";
extraArgs = [ "-f" ]; # force overwrite
postCreateHook = lib.mkIf withImpermanence ''
MNTPOINT=$(mktemp -d)
mount "/dev/mapper/root" "$MNTPOINT" -o subvol=/
trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT
btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank
'';
subvolumes = {
"@root" = {
mountpoint = "/";
mountOptions = [
"compress=zstd"
"noatime"
];
};
"@persist" = lib.mkIf withImpermanence {
mountpoint = "/persist";
mountOptions = [
"compress=zstd"
"noatime"
];
};
"@nix" = {
mountpoint = "/nix";
mountOptions = [
"compress=zstd"
"noatime"
];
};
"@swap" = lib.mkIf withSwap {
mountpoint = "/.swapvol";
swap.swapfile.size = "${swapSize}G";
};
};
};
};
luks = lib.mkIf withEncryption {
size = "100%"; size = "100%";
content = { content = {
type = "luks"; type = "luks";
@ -45,6 +87,12 @@
content = { content = {
type = "btrfs"; type = "btrfs";
extraArgs = [ "-f" ]; # force overwrite extraArgs = [ "-f" ]; # force overwrite
postCreateHook = lib.mkIf withImpermanence ''
MNTPOINT=$(mktemp -d)
mount "/dev/mapper/cryptroot" "$MNTPOINT" -o subvol=/
trap 'umount $MNTPOINT; rm -rf $MNTPOINT' EXIT
btrfs subvolume snapshot -r $MNTPOINT/root $MNTPOINT/root-blank
'';
subvolumes = { subvolumes = {
"@root" = { "@root" = {
mountpoint = "/"; mountpoint = "/";
@ -53,13 +101,13 @@
"noatime" "noatime"
]; ];
}; };
# "@persist" = { "@persist" = lib.mkIf withImpermanence {
# mountpoint = "${config.hostSpec.persistFolder}"; mountpoint = "/persist";
# mountOptions = [ mountOptions = [
# "compress=zstd" "compress=zstd"
# "noatime" "noatime"
# ]; ];
# }; };
"@nix" = { "@nix" = {
mountpoint = "/nix"; mountpoint = "/nix";
mountOptions = [ mountOptions = [
@ -81,6 +129,8 @@
}; };
}; };
fileSystems."/persist".neededForBoot = lib.mkIf withImpermanence true;
environment.systemPackages = [ environment.systemPackages = [
pkgs.yubikey-manager # For luks fido2 enrollment before full install pkgs.yubikey-manager # For luks fido2 enrollment before full install
]; ];

View file

@ -5,6 +5,8 @@ target_hostname=""
target_destination="" target_destination=""
target_user="swarsel" target_user="swarsel"
ssh_port="22" ssh_port="22"
persist_dir=""
disk_encryption=0
temp=$(mktemp -d) temp=$(mktemp -d)
function help_and_exit() { function help_and_exit() {
@ -23,6 +25,7 @@ function help_and_exit() {
echo " Default='${target_user}'." echo " Default='${target_user}'."
echo " --port <ssh_port> specify the ssh port to use for remote access. Default=${ssh_port}." echo " --port <ssh_port> specify the ssh port to use for remote access. Default=${ssh_port}."
echo " --impermanence Use this flag if the target machine has impermanence enabled. WARNING: Assumes /persist path." echo " --impermanence Use this flag if the target machine has impermanence enabled. WARNING: Assumes /persist path."
echo " --encryption Use this flag if the target machine has full disk encryption enabled."
echo " --debug Enable debug mode." echo " --debug Enable debug mode."
echo " -h | --help Print this help." echo " -h | --help Print this help."
exit 0 exit 0
@ -111,6 +114,14 @@ while [[ $# -gt 0 ]]; do
shift shift
temp=$1 temp=$1
;; ;;
--impermanence)
shift
persist_dir="/persist"
;;
--encryption)
shift
disk_encryption=1
;;
--debug) --debug)
set -x set -x
;; ;;
@ -146,24 +157,28 @@ sed -i "/$target_hostname/d; /$target_destination/d" ~/.ssh/known_hosts
# ------------------------ # ------------------------
green "Preparing a new ssh_host_ed25519_key pair for $target_hostname." green "Preparing a new ssh_host_ed25519_key pair for $target_hostname."
# Create the directory where sshd expects to find the host keys # Create the directory where sshd expects to find the host keys
install -d -m755 "$temp/etc/ssh" install -d -m755 "$temp/$persist_dir/etc/ssh"
# Generate host ssh key pair without a passphrase # Generate host ssh key pair without a passphrase
ssh-keygen -t ed25519 -f "$temp/etc/ssh/ssh_host_ed25519_key" -C root@"$target_hostname" -N "" ssh-keygen -t ed25519 -f "$temp/$persist_dir/etc/ssh/ssh_host_ed25519_key" -C root@"$target_hostname" -N ""
# Set the correct permissions so sshd will accept the key # Set the correct permissions so sshd will accept the key
chmod 600 "$temp/etc/ssh/ssh_host_ed25519_key" chmod 600 "$temp/$persist_dir/etc/ssh/ssh_host_ed25519_key"
echo "Adding ssh host fingerprint at $target_destination to ~/.ssh/known_hosts" echo "Adding ssh host fingerprint at $target_destination to ~/.ssh/known_hosts"
# This will fail if we already know the host, but that's fine # This will fail if we already know the host, but that's fine
ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true ssh-keyscan -p "$ssh_port" "$target_destination" >> ~/.ssh/known_hosts || true
# ------------------------ # ------------------------
# when using luks, disko expects a passphrase on /tmp/disko-password, so we set it for now and will update the passphrase later # when using luks, disko expects a passphrase on /tmp/disko-password, so we set it for now and will update the passphrase later
# via the config # via the config
green "Preparing a temporary password for disko." if [ "$disk_encryption" -eq 1 ]; then
green "[Optional] Set disk encryption passphrase:" green "--encryption set: Preparing a temporary password for disko."
read -rs luks_passphrase green "[Optional] Set disk encryption passphrase:"
if [ -n "$luks_passphrase" ]; then read -rs luks_passphrase
if [ -n "$luks_passphrase" ]; then
$ssh_root_cmd "/bin/sh -c 'echo $luks_passphrase > /tmp/disko-password'" $ssh_root_cmd "/bin/sh -c 'echo $luks_passphrase > /tmp/disko-password'"
else else
$ssh_root_cmd "/bin/sh -c 'echo passphrase > /tmp/disko-password'" $ssh_root_cmd "/bin/sh -c 'echo passphrase > /tmp/disko-password'"
fi
else
green "--encryption not set: Not using disk encryption.."
fi fi
# ------------------------ # ------------------------
green "Generating hardware-config.nix for $target_hostname and adding it to the nix-config." green "Generating hardware-config.nix for $target_hostname and adding it to the nix-config."
@ -188,6 +203,11 @@ while true; do
fi fi
done done
# ------------------------ # ------------------------
if [ -n "$persist_dir" ]; then
$ssh_root_cmd "cp /etc/machine-id $persist_dir/etc/machine-id || true"
$ssh_root_cmd "cp -R /etc/ssh/ $persist_dir/etc/ssh/ || true"
fi
# ------------------------
green "Generating an age key based on the new ssh_host_ed25519_key." green "Generating an age key based on the new ssh_host_ed25519_key."
target_key=$( target_key=$(
ssh-keyscan -p "$ssh_port" -t ssh-ed25519 "$target_destination" 2>&1 | ssh-keyscan -p "$ssh_port" -t ssh-ed25519 "$target_destination" 2>&1 |
@ -237,6 +257,10 @@ if yes_or_no "Do you want to copy your full nix-config and nix-secrets to $targe
cd "${git_root}" cd "${git_root}"
just sync "$target_user" "$target_destination" just sync "$target_user" "$target_destination"
if [ -n "$persist_dir" ]; then
$ssh_root_cmd "cp -r /home/$target_user/.dotfiles $persist_dir/.dotfiles || true"
fi
if yes_or_no "Do you want to rebuild immediately?"; then if yes_or_no "Do you want to rebuild immediately?"; then
green "Rebuilding nix-config on $target_hostname" green "Rebuilding nix-config on $target_hostname"
$ssh_root_cmd "mkdir -p /root/.local/share/nix/; printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' > /root/.local/share/nix/trusted-settings.json" $ssh_root_cmd "mkdir -p /root/.local/share/nix/; printf '{\"extra-substituters\":{\"https://nix-community.cachix.org\":true,\"https://nix-community.cachix.org https://cache.ngi0.nixos.org/\":true},\"extra-trusted-public-keys\":{\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=\":true,\"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs= cache.ngi0.nixos.org-1:KqH5CBLNSyX184S9BKZJo1LxrxJ9ltnY2uAs5c/f1MA=\":true}}' > /root/.local/share/nix/trusted-settings.json"