From 7737abc45ecde3765c8db4d4f28e18a99ef82964 Mon Sep 17 00:00:00 2001 From: Nikolaos Karaolidis Date: Wed, 19 Feb 2025 13:06:35 +0000 Subject: [PATCH] Unfuck secrets Don't worry why all the commit hashes suddenly changed, it's fine. Signed-off-by: Nikolaos Karaolidis --- .vscode/settings.json | 3 + .../configs/system/nix-install/install.sh | 11 +- hosts/elara/secrets/ssh_host_ed25519_key.pub | 2 +- .../secrets/ssh_host_ed25519_key.pub | 2 +- lib/scripts/add-host.sh | 193 ++++++++++++++++-- lib/scripts/remove-host.sh | 12 +- lib/scripts/update-keys.sh | 14 +- 7 files changed, 205 insertions(+), 32 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..1ad0403 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "sops.defaults.ageKeyFile": "./secrets/personal/key.txt" +} diff --git a/hosts/common/configs/system/nix-install/install.sh b/hosts/common/configs/system/nix-install/install.sh index 4d8a98b..cf05cc1 100644 --- a/hosts/common/configs/system/nix-install/install.sh +++ b/hosts/common/configs/system/nix-install/install.sh @@ -64,7 +64,7 @@ prepare_disk() { copy_keys() { mkdir -p "$root/persist/etc/ssh" - cp "$flake/hosts/$host/secrets/ssh_host_ed25519_key" "$root/persist/etc/ssh/ssh_host_ed25519_key" + cp -f "$flake/hosts/$host/secrets/ssh_host_ed25519_key" "$root/persist/etc/ssh/ssh_host_ed25519_key" for path in "$flake/hosts/$host/users"/*; do if [[ -z "$key" ]]; then @@ -74,11 +74,14 @@ copy_keys() { local user user=$(basename "$path") mkdir -p "$root/persist/home/$user/.config/sops-nix" - cp "$flake/secrets/$key/key.txt" "$root/persist/home/$user/.config/sops-nix/key.txt" - chown -R "$(cat "$flake/hosts/$host/users/$user/uid"):100" "$root/persist/home/$user" + cp -f "$flake/secrets/$key/key.txt" "$root/persist/home/$user/.config/sops-nix/key.txt" done } +set_permissions() { + chown -R "$(cat "$flake/hosts/$host/users/$user/uid"):100" "$root/persist/home/$user" +} + install() { nixos-install --root "$root" --flake "$flake#$host" --no-root-passwd } @@ -139,12 +142,14 @@ main() { install) prepare_disk "destroy,format,mount" copy_keys + set_permissions install if [[ "$copy_config_flag" == "true" ]]; then copy_config; fi if [[ "$reboot_flag" == "true" ]]; then finish; fi ;; repair) prepare_disk "mount" + copy_keys install if [[ "$reboot_flag" == "true" ]]; then finish; fi ;; diff --git a/hosts/elara/secrets/ssh_host_ed25519_key.pub b/hosts/elara/secrets/ssh_host_ed25519_key.pub index d763e62..cfbcf9f 100644 --- a/hosts/elara/secrets/ssh_host_ed25519_key.pub +++ b/hosts/elara/secrets/ssh_host_ed25519_key.pub @@ -1 +1 @@ -ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB2sVagJ2CqpitBK4izlfKWIe2n2xkfV95F0VNkAc3FD nick@eirene +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB2sVagJ2CqpitBK4izlfKWIe2n2xkfV95F0VNkAc3FD root@elara diff --git a/hosts/installer/secrets/ssh_host_ed25519_key.pub b/hosts/installer/secrets/ssh_host_ed25519_key.pub index 079297d..0f70235 100644 --- a/hosts/installer/secrets/ssh_host_ed25519_key.pub +++ b/hosts/installer/secrets/ssh_host_ed25519_key.pub @@ -1 +1 @@ -ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHEIK+JkxkC0E8w0IF59gtpG55JBS/osqs1B7VhsI0eI nick@eirene +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHEIK+JkxkC0E8w0IF59gtpG55JBS/osqs1B7VhsI0eI root@installer diff --git a/lib/scripts/add-host.sh b/lib/scripts/add-host.sh index d306104..b186538 100755 --- a/lib/scripts/add-host.sh +++ b/lib/scripts/add-host.sh @@ -1,33 +1,198 @@ -#!/usr/bin/env -S nix shell nixpkgs#ssh-to-age -c bash +#!/usr/bin/env -S nix shell nixpkgs#ssh-to-age nixpkgs#age nixpkgs#sops -c bash # shellcheck shell=bash set -o errexit set -o nounset set -o pipefail -if [[ "$#" -ne 2 ]]; then - echo "Usage: $0 " +if [[ "$#" -ne 1 ]]; then + echo "Usage: $0 " exit 1 fi host="$1" mkdir -p "./hosts/$host/secrets" - -ssh-keygen -t ed25519 -f "./hosts/$host/secrets/ssh_host_ed25519_key" -N "" - +ssh-keygen -t ed25519 -f "./hosts/$host/secrets/ssh_host_ed25519_key" -C "root@$host" -N "" age_key=$(ssh-to-age < "./hosts/$host/secrets/ssh_host_ed25519_key.pub") -find . -type f -name "sops.yaml" | while IFS= read -r sops_file; do - sed -i "/- hosts:/a\ - &$host $age_key" "$sops_file" - sed -i "/- age:/a\ - *$host" "$sops_file" +cat < "./hosts/$host/secrets/sops.yaml" +keys: + - hosts: + - &$host $age_key + - namespaces: + - &personal $(age-keygen -y ./secrets/personal/key.txt | tr -d '\n') + +creation_rules: + - path_regex: .+\.(yaml|yml|json|env|ini|bin) + key_groups: + - age: + - *$host + - *personal +EOF + +luks="" +luks_confirm="" + +until [[ "$luks" == "$luks_confirm" && -n "$luks" ]]; do + read -r -s -p "Enter LUKS passphrase for $host: " luks + echo + read -r -s -p "Confirm LUKS passphrase for $host: " luks_confirm + echo + + if [[ "$luks" != "$luks_confirm" ]]; then + echo "They didn't match. Let's try again." + fi done -sed -i "/knownHosts = {/a\ $host.publicKeyFile = ../../../../$host/secrets/ssh_host_ed25519_key.pub;" ./hosts/common/configs/system/ssh/default.nix -sed -i "/userKnownHostsFile = lib.strings.concatStringsSep \" \" \[/a\ ../../../../../$host/secrets/ssh_host_ed25519_key.pub" ./hosts/common/configs/user/console/ssh/default.nix +machine_id=$(uuidgen -r | tr -d -) -"$(dirname "$0")/update-keys.sh" "$2" +cat < "./hosts/$host/secrets/.decrypted~secrets.yaml" +luks: '$luks' +machineId: $machine_id +EOF + +tmp_age_key="$(mktemp)" +echo "$age_key" > "$tmp_age_key" +export SOPS_AGE_KEY_FILE="$tmp_age_key" + +sops --config "./hosts/$host/secrets/sops.yaml" --encrypt "./hosts/$host/secrets/.decrypted~secrets.yaml" > "./hosts/$host/secrets/secrets.yaml" + +unset SOPS_AGE_KEY_FILE +rm -f "$tmp_age_key" +rm -f "./hosts/$host/secrets/.decrypted~secrets.yaml" + +mkdir -p "./hosts/$host/hardware" + +cat <<'EOF' > "./hosts/$host/hardware/default.nix" +{ ... }: +{ + +} +EOF + +cat <<'EOF' > "./hosts/$host/format.nix" +{ + disko.devices = { + disk.installer = { + device = ""; # Set this to the device you want to install to + type = "disk"; + content = { + type = "gpt"; + partitions = { + boot = { + name = "boot"; + size = "1M"; + type = "EF02"; + }; + esp = { + name = "esp"; + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "umask=0077" ]; + }; + }; + root = { + name = "root"; + size = "100%"; + content = { + name = "main"; + type = "luks"; + passwordFile = "/tmp/installer.key"; + settings = { + allowDiscards = true; + }; + content = { + type = "btrfs"; + extraArgs = [ "-f" ]; + subvolumes = { + "@" = { + mountpoint = "/"; + }; + "@persist" = { + mountpoint = "/persist"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "@nix" = { + mountpoint = "/nix"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "@cache" = { + mountpoint = "/cache"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + }; + }; + }; + }; + }; + }; + }; + }; +} +EOF + +cat < "./hosts/$host/default.nix" +{ inputs, ... }: +{ + imports = [ + ../../lib + + inputs.disko.nixosModules.disko + ./format.nix + + ./hardware + + ../common/configs/system/boot + ../common/configs/system/btrfs + ../common/configs/system/documentation + ../common/configs/system/impermanence + ../common/configs/system/nix + ../common/configs/system/nix-cleanup + ../common/configs/system/nixpkgs + ../common/configs/system/ntp + ../common/configs/system/sops + ../common/configs/system/system + ../common/configs/system/users + ../common/configs/system/zsh + ]; + + networking.hostName = "$host"; + i18n.defaultLocale = "en_US.UTF-8"; + + sops.defaultSopsFile = ./secrets/secrets.yaml; +} +EOF + +cat < "./hosts/$host/README.md" +# $host + +## Post-Install Checklist +EOF + +new_entry="| \`$host\` | [hosts/$host/README.md](./hosts/$host/README.md) |" +last_table_line=$(grep -n "^| " README.md | tail -n 1 | cut -d: -f1) +sed -i "${last_table_line}a$new_entry" README.md + +sed -i "/knownHosts = {/a\\ $host.publicKeyFile = ../../../../$host/secrets/ssh_host_ed25519_key.pub;" ./hosts/common/configs/system/ssh/default.nix + +nix fmt echo "Host $host has been successfully added." -echo "You can generate SSH key pairs for any users that need to connect to user@host using the following command:" -echo "ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_${host}_" +echo "Age Public Key: $age_key" +echo +echo "If you need user-level SSH keys, generate them like this:" +echo " ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_${host}_" diff --git a/lib/scripts/remove-host.sh b/lib/scripts/remove-host.sh index 75098e0..3f44841 100755 --- a/lib/scripts/remove-host.sh +++ b/lib/scripts/remove-host.sh @@ -5,8 +5,8 @@ set -o errexit set -o nounset set -o pipefail -if [[ "$#" -ne 2 ]]; then - echo "Usage: $0 " +if [[ "$#" -ne 1 ]]; then + echo "Usage: $0 " exit 1 fi @@ -20,11 +20,11 @@ find . -type f -name "sops.yaml" | while IFS= read -r sops_file; do done sed -i "/$host/d" ./hosts/common/configs/system/ssh/default.nix -sed -i "/$host/d" ./hosts/common/configs/user/console/ssh/default.nix - -"$(dirname "$0")/update-keys.sh" "$2" +sed -i "/$host/d" ./README.md rm -rf "./hosts/$host" +"$(dirname "$0")/update-keys.sh" + +echo "Please remove SSH key pairs for any users that used to connect to $host." echo "Host $host has been successfully removed." -echo "Please remove SSH key pairs for any users that used to connect to this host." diff --git a/lib/scripts/update-keys.sh b/lib/scripts/update-keys.sh index 6fa449b..76120d7 100755 --- a/lib/scripts/update-keys.sh +++ b/lib/scripts/update-keys.sh @@ -5,18 +5,18 @@ set -o errexit set -o nounset set -o pipefail -if [[ -z "$SOPS_AGE_KEY_FILE" ]]; then - echo "Please set the SOPS_AGE_KEY_FILE environment variable" - exit 1 -fi - find . -type f -name 'sops.yaml' | while IFS= read -r sops_file; do dir=$(dirname "$sops_file") - echo "$dir" + + namespace=$(grep -A1 "namespaces:" "$sops_file" | tail -n1 | awk '{print $2}' | tr -d '&') + SOPS_AGE_KEY_FILE="./secrets/$namespace/key.txt" + export SOPS_AGE_KEY_FILE + find "$dir" -maxdepth 1 -type f -regextype posix-extended \ -regex '.+\.(yaml|yml|json|env|ini|bin)' \ ! -name 'sops.yaml' | while IFS= read -r file; do - echo "$file" sops --config "$sops_file" updatekeys "$file" -y done + + unset SOPS_AGE_KEY_FILE done