From 7a64899cee500fb95cb8472c42a2a29aa23b305a Mon Sep 17 00:00:00 2001 From: Price Hiller Date: Thu, 7 Dec 2023 09:05:24 -0600 Subject: [PATCH] refactor(luna): massively overhaul luna to better handle opt-in state Now uses BTRFS rollbacks instead of tmpfs --- .envrc | 5 + .gitignore | 2 + flake.lock | 105 ++++++--- flake.nix | 127 ++++++----- hosts/luna/default.nix | 7 +- hosts/luna/modules/default.nix | 11 - hosts/luna/modules/docker/default.nix | 3 - hosts/luna/modules/docker/gitlab.nix | 18 +- hosts/luna/modules/impermanence.nix | 4 - hosts/luna/modules/networking.nix | 1 - hosts/luna/modules/nix.nix | 9 +- hosts/luna/modules/programs.nix | 10 +- hosts/luna/modules/services/default.nix | 8 - hosts/luna/modules/services/fail2ban.nix | 3 - hosts/luna/modules/services/journald.nix | 8 + hosts/luna/modules/services/nginx.nix | 9 +- hosts/luna/modules/services/openssh.nix | 50 ++++- hosts/luna/modules/user.nix | 12 - hosts/luna/modules/users.nix | 19 ++ hosts/luna/os/boot.nix | 44 +++- hosts/luna/os/default.nix | 7 +- hosts/luna/os/disk-config.nix | 57 +++++ hosts/luna/os/filesystem.nix | 25 --- hosts/luna/os/hardware.nix | 1 + hosts/luna/pubkey.nix | 1 + install.bash | 257 ++++++++-------------- lib/default.nix | 32 +++ secrets/gitlab-runner-reg-config.age | Bin 433 -> 0 bytes secrets/luna/gitlab-runner-reg-config.age | 10 + secrets/luna/root-hash-pw.age | Bin 0 -> 540 bytes secrets/secrets.nix | 36 ++- 31 files changed, 518 insertions(+), 363 deletions(-) create mode 100644 .envrc create mode 100644 .gitignore delete mode 100644 hosts/luna/modules/impermanence.nix delete mode 100644 hosts/luna/modules/services/default.nix create mode 100644 hosts/luna/modules/services/journald.nix delete mode 100755 hosts/luna/modules/user.nix create mode 100755 hosts/luna/modules/users.nix create mode 100644 hosts/luna/os/disk-config.nix delete mode 100644 hosts/luna/os/filesystem.nix create mode 100644 hosts/luna/pubkey.nix create mode 100644 lib/default.nix delete mode 100644 secrets/gitlab-runner-reg-config.age create mode 100644 secrets/luna/gitlab-runner-reg-config.age create mode 100644 secrets/luna/root-hash-pw.age diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..4838526 --- /dev/null +++ b/.envrc @@ -0,0 +1,5 @@ +# vim: ft=bash +if ! has nix_direnv_version || ! nix_direnv_version 2.5.1; then + source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.5.1/direnvrc" "sha256-puRzug17Ed4JFS2wbpqa3k764QV6xPP6O3A/ez/JpOM=" +fi +use flake diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a35f739 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.direnv/ +*.ignore diff --git a/flake.lock b/flake.lock index 6283dd4..a068861 100644 --- a/flake.lock +++ b/flake.lock @@ -22,6 +22,29 @@ "type": "github" } }, + "blog": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "host": "gitlab.orion-technologies.io", + "lastModified": 1701591195, + "narHash": "sha256-cyU5Yv3vPaf9cfuqrScyObf8DA77KE+7HxF8WSmCEJA=", + "owner": "blog", + "repo": "blog", + "rev": "cbaf7ebe37d5e305991150a6b3aa9468cfa0a713", + "type": "gitlab" + }, + "original": { + "host": "gitlab.orion-technologies.io", + "owner": "blog", + "repo": "blog", + "type": "gitlab" + } + }, "darwin": { "inputs": { "nixpkgs": [ @@ -44,6 +67,26 @@ "type": "github" } }, + "disko": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1701905325, + "narHash": "sha256-lda63LmEIlDMeCgWfjr3/wb487XPllBByfrGRieyEk4=", + "owner": "nix-community", + "repo": "disko", + "rev": "1144887c6f4d2dcbb2316a24364ef53e25b0fcfe", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "disko", + "type": "github" + } + }, "flake-utils": { "inputs": { "systems": "systems" @@ -62,6 +105,24 @@ "type": "github" } }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1701680307, + "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, "home-manager": { "inputs": { "nixpkgs": [ @@ -114,35 +175,14 @@ "type": "github" } }, - "personal-blog": { - "inputs": { - "flake-utils": "flake-utils", - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "host": "gitlab.orion-technologies.io", - "lastModified": 1701591195, - "narHash": "sha256-cyU5Yv3vPaf9cfuqrScyObf8DA77KE+7HxF8WSmCEJA=", - "owner": "blog", - "repo": "blog", - "rev": "cbaf7ebe37d5e305991150a6b3aa9468cfa0a713", - "type": "gitlab" - }, - "original": { - "host": "gitlab.orion-technologies.io", - "owner": "blog", - "repo": "blog", - "type": "gitlab" - } - }, "root": { "inputs": { "agenix": "agenix", + "blog": "blog", + "disko": "disko", + "flake-utils": "flake-utils_2", "impermanence": "impermanence", - "nixpkgs": "nixpkgs", - "personal-blog": "personal-blog" + "nixpkgs": "nixpkgs" } }, "systems": { @@ -159,6 +199,21 @@ "repo": "default", "type": "github" } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 8ca0e45..a0e2f6f 100644 --- a/flake.nix +++ b/flake.nix @@ -3,6 +3,7 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; impermanence = { url = "github:nix-community/impermanence"; }; @@ -10,69 +11,89 @@ url = "github:ryantm/agenix"; inputs.nixpkgs.follows = "nixpkgs"; }; - personal-blog = { - url = "gitlab:blog/blog?host=gitlab.orion-technologies.io"; + disko = { + url = "github:nix-community/disko"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + blog = { + type = "gitlab"; + owner = "blog"; + repo = "blog"; + host = "gitlab.orion-technologies.io"; inputs.nixpkgs.follows = "nixpkgs"; }; }; - - outputs = inputs @ { self, nixpkgs, impermanence, agenix, ... }: + outputs = inputs @ { self, nixpkgs, impermanence, agenix, disko, flake-utils, blog, ... }: let - specialArgs = { - secrets = ./secrets; - persist-dir = "/nix/persist"; - }; + lib = import ./lib // nixpkgs.lib; + pkgs = nixpkgs.legacyPackages."x86_64-linux"; defaults = { config = { - environment.persistence = { - "${specialArgs.persist-dir}" = { - hideMounts = true; - directories = [ - "/var/lib" - "/var/log" - "/etc/nixos" - "/opt" - "/persist" - ]; - files = [ - "/etc/machine-id" - "/etc/ssh/ssh_host_ed25519_key" - "/etc/ssh/ssh_host_ed25519_key.pub" - "/etc/ssh/ssh_host_rsa_key" - "/etc/ssh/ssh_host_rsa_key.pub" - ]; - }; + environment.etc.machine-id.source = "/nix/persist/ephemeral/etc/machine-id"; + environment.persistence.save = { + hideMounts = true; + persistentStoragePath = "/nix/persist/save"; + }; + environment.persistence.ephemeral = { + persistentStoragePath = "/nix/persist/ephemeral"; + hideMounts = true; + directories = [ + "/var/lib" + "/var/log" + "/etc/nixos" + { directory = "/persist"; user = "root"; group = "root"; mode = "0700"; } + ]; }; - - age.identityPaths = [ - "/persist/nix.key" - ]; }; }; in { - nixosConfigurations.orion = nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; - specialArgs = specialArgs; - modules = [ - { _module.args = inputs; } - defaults - ./hosts/orion - impermanence.nixosModules.impermanence - agenix.nixosModules.default - ]; - }; - nixosConfigurations.luna = nixpkgs.lib.nixosSystem { - system = "x86_64-linux"; - specialArgs = specialArgs; - modules = [ - { _module.args = inputs; } - defaults - ./hosts/luna - impermanence.nixosModules.impermanence - agenix.nixosModules.default - ]; - }; - }; + nixosConfigurations.luna = + let + hostname = "luna"; + in + nixpkgs.lib.nixosSystem + { + system = "x86_64-linux"; + specialArgs = { + inherit self; + inherit flake-utils; + inherit inputs; + inherit hostname; + inherit lib; + inherit blog; + secrets = "${self}/secrets/${hostname}"; + disk = "nvme0n1"; + fqdn = "orion-technologies.io"; + }; + modules = [ + { + _module.args = { }; + } + defaults + impermanence.nixosModules.impermanence + agenix.nixosModules.default + disko.nixosModules.disko + ./hosts/${hostname} + ]; + }; + + } // flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { + inherit system; + overlays = [ agenix.overlays.default ]; + }; + in + { + devShells.default = + pkgs.mkShell + { + packages = with pkgs; [ age age-plugin-yubikey pkgs.agenix ]; + shellHook = '' + export RULES="$PWD/secrets/secrets.nix" + ''; + }; + }); } diff --git a/hosts/luna/default.nix b/hosts/luna/default.nix index 884a5ad..857dad9 100644 --- a/hosts/luna/default.nix +++ b/hosts/luna/default.nix @@ -1,9 +1,6 @@ { config, lib, nixpkgs, ... }: { - imports = [ - ./modules - ./os - ]; - system.stateVersion = "23.11"; + imports = (lib.recurseFilesInDirs [ ./os ./modules ] ".nix"); + system.stateVersion = "24.05"; } diff --git a/hosts/luna/modules/default.nix b/hosts/luna/modules/default.nix index 5a669de..58102d0 100644 --- a/hosts/luna/modules/default.nix +++ b/hosts/luna/modules/default.nix @@ -2,15 +2,4 @@ { time.timeZone = "America/Chicago"; - - imports = [ - ./services - ./docker - ./impermanence.nix - ./nix.nix - ./networking.nix - ./programs.nix - ./user.nix - ./system.nix - ]; } diff --git a/hosts/luna/modules/docker/default.nix b/hosts/luna/modules/docker/default.nix index 97e200f..cc64ad2 100644 --- a/hosts/luna/modules/docker/default.nix +++ b/hosts/luna/modules/docker/default.nix @@ -14,7 +14,4 @@ package = pkgs.docker_24; }; }; - imports = [ - ./gitlab.nix - ]; } diff --git a/hosts/luna/modules/docker/gitlab.nix b/hosts/luna/modules/docker/gitlab.nix index 64eb6ca..4f71712 100644 --- a/hosts/luna/modules/docker/gitlab.nix +++ b/hosts/luna/modules/docker/gitlab.nix @@ -1,9 +1,12 @@ -{ lib, config, specialArgs, ... }: +{ secrets, config, specialArgs, fqdn, ... }: let - gitlab_home = "/opt/gitlab"; - hostname = "gitlab.orion-technologies.io"; + gitlab_home = "/var/lib/gitlab"; + gitlab_host = "gitlab.${fqdn}"; in { + environment.persistence.save.directories = [ + gitlab_home + ]; virtualisation.oci-containers.containers.gitlab = { image = "gitlab/gitlab-ee:latest"; autoStart = true; @@ -18,7 +21,8 @@ in ]; extraOptions = [ "--shm-size=256m" - "--hostname=${hostname}" + "--hostname=${gitlab_host}" + "--pull=always" ]; }; @@ -26,11 +30,11 @@ in 2222 ]; - age.secrets.gitlab-runner-reg-config.file = specialArgs.secrets + "/gitlab-runner-reg-config.age"; + age.secrets.gitlab-runner-reg-config.file = "${secrets}/gitlab-runner-reg-config.age"; services.gitlab-runner = { enable = true; services = { - default = with lib; { + default = { registrationConfigFile = config.age.secrets.gitlab-runner-reg-config.path; dockerImage = "alpine"; tagList = [ @@ -41,7 +45,7 @@ in }; }; - services.nginx.virtualHosts."${hostname}" = { + services.nginx.virtualHosts."${gitlab_host}" = { locations."/".proxyPass = "http://127.0.0.1:8080"; forceSSL = true; enableACME = true; diff --git a/hosts/luna/modules/impermanence.nix b/hosts/luna/modules/impermanence.nix deleted file mode 100644 index 3590a39..0000000 --- a/hosts/luna/modules/impermanence.nix +++ /dev/null @@ -1,4 +0,0 @@ -{ ... }: -{ - environment.persistence = { }; -} diff --git a/hosts/luna/modules/networking.nix b/hosts/luna/modules/networking.nix index 65d91d4..4dfe302 100755 --- a/hosts/luna/modules/networking.nix +++ b/hosts/luna/modules/networking.nix @@ -1,7 +1,6 @@ { inputs, lib, pkgs, hostname, ... }: let - hostname = "luna"; networks_dhcp_use_dns = "no"; networks_dhcp = "ipv4"; networks_multicast_dns = "no"; diff --git a/hosts/luna/modules/nix.nix b/hosts/luna/modules/nix.nix index edf6fa7..4e8fede 100755 --- a/hosts/luna/modules/nix.nix +++ b/hosts/luna/modules/nix.nix @@ -1,16 +1,13 @@ -{ pkgs, ... }: - -{ +{ pkgs, ... }: { nix = { settings = { experimental-features = [ "nix-command" "flakes" ]; auto-optimise-store = true; - trusted-users = ["@wheel"]; + trusted-users = [ "wheel" ]; }; gc = { automatic = true; - dates = "weekly"; - options = "--delete-older-than 7d"; + dates = "daily"; }; }; } diff --git a/hosts/luna/modules/programs.nix b/hosts/luna/modules/programs.nix index e0fbf08..d2b20c3 100755 --- a/hosts/luna/modules/programs.nix +++ b/hosts/luna/modules/programs.nix @@ -1,10 +1,7 @@ -{ pkgs, ... }: - -{ +{ pkgs, ... }: { nixpkgs.config.allowUnfree = true; programs = { - zsh.enable = true; neovim = { enable = true; defaultEditor = true; @@ -13,11 +10,12 @@ environment.systemPackages = with pkgs; [ vim + coreutils-full + nano curl + wget git jq rsync - rustc - cargo ]; } diff --git a/hosts/luna/modules/services/default.nix b/hosts/luna/modules/services/default.nix deleted file mode 100644 index 571abdf..0000000 --- a/hosts/luna/modules/services/default.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ ... }: -{ - imports = [ - ./openssh.nix - ./fail2ban.nix - ./nginx.nix - ]; -} diff --git a/hosts/luna/modules/services/fail2ban.nix b/hosts/luna/modules/services/fail2ban.nix index b53d1a5..b0a2229 100644 --- a/hosts/luna/modules/services/fail2ban.nix +++ b/hosts/luna/modules/services/fail2ban.nix @@ -3,8 +3,5 @@ services.fail2ban = { enable = true; maxretry = 10; - jails.DEFAULT.settings = { - port = "2200"; - }; }; } diff --git a/hosts/luna/modules/services/journald.nix b/hosts/luna/modules/services/journald.nix new file mode 100644 index 0000000..a8902fe --- /dev/null +++ b/hosts/luna/modules/services/journald.nix @@ -0,0 +1,8 @@ +{ ... }: +{ + services.journald = { + extraConfig = '' + SystemMaxUse=100G + ''; + }; +} diff --git a/hosts/luna/modules/services/nginx.nix b/hosts/luna/modules/services/nginx.nix index 2b0ae5a..575c928 100644 --- a/hosts/luna/modules/services/nginx.nix +++ b/hosts/luna/modules/services/nginx.nix @@ -1,7 +1,4 @@ -{ config, pkgs, system, personal-blog, ... }: -let - blog-host = "blog.orion-technologies.io"; -in +{ config, pkgs, blog, fqdn, ... }: { services.nginx = { enable = true; @@ -15,10 +12,10 @@ in defaults.email = "price@orion-technologies.io"; }; - services.nginx.virtualHosts."${blog-host}" = { + services.nginx.virtualHosts."blog.${fqdn}" = { forceSSL = true; enableACME = true; - root = personal-blog.packages.${pkgs.system}.default; + root = blog.packages.${pkgs.system}.default; locations."/".index = "home.html"; }; diff --git a/hosts/luna/modules/services/openssh.nix b/hosts/luna/modules/services/openssh.nix index 212114d..5849777 100644 --- a/hosts/luna/modules/services/openssh.nix +++ b/hosts/luna/modules/services/openssh.nix @@ -1,20 +1,60 @@ -{ ... }: +{ config, ... }: { services.openssh = { enable = true; + # We set the hostkeys manually so they persist through reboots + hostKeys = [ + { + path = (config.environment.persistence.ephemeral.persistentStoragePath + "/etc/ssh/ssh_host_ed25519_key"); + type = "ed25519"; + } + ]; + sftpFlags = [ + "-f AUTHPRIV" + "-l INFO" + ]; + extraConfig = '' + AllowUsers price + ''; settings = { PasswordAuthentication = false; - PermitRootLogin = "prohibit-password"; + PermitRootLogin = "no"; + LogLevel = "VERBOSE"; KexAlgorithms = [ "curve25519-sha256" "curve25519-sha256@libssh.org" - "diffie-hellman-group16-sha512" - "diffie-hellman-group18-sha512" - "sntrup761x25519-sha512@openssh.com" + "diffie-hellman-group-exchange-sha256" + ]; + Ciphers = [ + "chacha20-poly1305@openssh.com" + "aes256-gcm@openssh.com" + "aes128-gcm@openssh.com" + "aes256-ctr" + "aes192-ctr" + "aes128-ctr" + ]; + Macs = [ + "hmac-sha2-512-etm@openssh.com" + "hmac-sha2-256-etm@openssh.com" + "umac-128-etm@openssh.com" ]; }; ports = [ 2200 ]; + banner = '' + ┌────────────────────────────────────────────────────┐ + │ Orion Technologies - Security Notice │ + │ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ │ + │ UNAUTHORIZED ACCESS TO THIS DEVICE IS PROHIBITED │ + │ │ + │ You must have written, explicit, authorized │ + │ permission to access or configure this device. │ + │ Unauthorized attempts and actions to access or use │ + │ this system may result in civil and/or criminal │ + │ penalties. All activities performed on this device │ + │ are logged and monitored. │ + └────────────────────────────────────────────────────┘ + ''; }; } diff --git a/hosts/luna/modules/user.nix b/hosts/luna/modules/user.nix deleted file mode 100755 index 77dd60d..0000000 --- a/hosts/luna/modules/user.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ pkgs, user, ... }: - -{ - users.users = { - root = { - openssh.authorizedKeys.keys = [ - "no-touch-required sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIJ9ODXLAIfGH/7VNobQsp5nwBvNoh+pQMEH7s2jkHpkqAAAACHNzaDpsdW5h" - ]; - initialPassword = "pass"; - }; - }; -} diff --git a/hosts/luna/modules/users.nix b/hosts/luna/modules/users.nix new file mode 100755 index 0000000..4479c57 --- /dev/null +++ b/hosts/luna/modules/users.nix @@ -0,0 +1,19 @@ +{ pkgs, user, config, secrets, ... }: + +{ + age.secrets.root-pw.file = "${secrets}/root-hash-pw.age"; + security.sudo.wheelNeedsPassword = false; + users.users = { + root = { + passwordFile = config.age.secrets.root-pw.path; + }; + price = { + isNormalUser = true; + extraGroups = [ "wheel" ]; + shell = pkgs.bash; + openssh.authorizedKeys.keys = [ + "no-touch-required sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIJ9ODXLAIfGH/7VNobQsp5nwBvNoh+pQMEH7s2jkHpkqAAAACHNzaDpsdW5h" + ]; + }; + }; +} diff --git a/hosts/luna/os/boot.nix b/hosts/luna/os/boot.nix index aea633e..950cefe 100644 --- a/hosts/luna/os/boot.nix +++ b/hosts/luna/os/boot.nix @@ -1,4 +1,4 @@ -{ modulesPath, ... }: +{ modulesPath, pkgs, ... }: { imports = @@ -10,6 +10,48 @@ initrd = { availableKernelModules = [ "xhci_pci" "ahci" "nvme" "uas" "sd_mod" ]; kernelModules = [ ]; + systemd = { + enable = true; + initrdBin = [ pkgs.libuuid pkgs.gawk ]; + services.rollback = { + description = "Rollback btrfs root subvolume"; + wantedBy = [ "initrd.target" ]; + before = [ "sysroot.mount" ]; + after = [ "initrd-root-device.target" ]; + unitConfig.DefaultDependencies = "no"; + serviceConfig.Type = "oneshot"; + script = '' + mkdir -p /mnt + DISK_LABEL="NixOS-Primary" + ATTEMPTS=5 + printf "Attempting to find disk with label '%s'\n" "$DISK_LABEL" + while ((ATTEMPTS > 0)); do + if findfs LABEL="$DISK_LABEL"; then + printf "Found disk!\n" + break; + fi + ((ATTEMPTS--)) + sleep 3 + printf "Remaining disk discovery attempts: %s\n" "$ATTEMPTS" + done + mount -t btrfs -o subvol=/ $(findfs LABEL="$DISK_LABEL") /mnt + btrfs subvolume list -to /mnt/root \ + | awk 'NR>2 { printf $4"\n" }' \ + | while read subvol; do + printf "Removing Subvolume: %s\n" "$subvol"; + btrfs subvolume delete "/mnt/$subvol" + done + + printf "Removing /root subvolume\n" + btrfs subvolume delete /mnt/root + + printf "Restoring base /root subvolume\n" + btrfs subvolume snapshot /mnt/root-base /mnt/root + + umount /mnt + ''; + }; + }; }; loader = { systemd-boot.enable = true; diff --git a/hosts/luna/os/default.nix b/hosts/luna/os/default.nix index 0e87123..63130c3 100644 --- a/hosts/luna/os/default.nix +++ b/hosts/luna/os/default.nix @@ -1,11 +1,6 @@ { modulesPath, ... }: { - imports = [ - ./boot.nix - ./filesystem.nix - ./hardware.nix - ]; - system.stateVersion = "23.11"; + zramSwap.enable = true; } diff --git a/hosts/luna/os/disk-config.nix b/hosts/luna/os/disk-config.nix new file mode 100644 index 0000000..d61f1a8 --- /dev/null +++ b/hosts/luna/os/disk-config.nix @@ -0,0 +1,57 @@ +{ disk ? "nvme0n1", ... }: { + disko.devices = { + disk.${disk} = { + type = "disk"; + device = "/dev/${disk}"; + content = { + type = "gpt"; + partitions = { + esp = + let + label = "NixOS-Boot"; + in + { + priority = 1; + size = "512M"; + type = "EF00"; + content = { + extraArgs = [ "-n ${label}" "-F 32" ]; + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ + "defaults" + ]; + }; + }; + root = + let + label = "NixOS-Primary"; + in + { + size = "100%"; + content = { + type = "btrfs"; + extraArgs = [ "-f" "--label ${label}" ]; + postCreateHook = '' + MOUNT="$(mktemp -d)" + mount "/dev/disk/by-label/${label}" "$MOUNT" -o subvol=/ + trap 'umount $MOUNT; rm -rf $MOUNT' EXIT + btrfs subvolume snapshot -r "$MOUNT/root" "$MOUNT/root-base" + ''; + subvolumes = { + "/root" = { + mountpoint = "/"; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ "compress=zstd" "noatime" ]; + }; + }; + }; + }; + }; + }; + }; + }; +} diff --git a/hosts/luna/os/filesystem.nix b/hosts/luna/os/filesystem.nix deleted file mode 100644 index 1a932dd..0000000 --- a/hosts/luna/os/filesystem.nix +++ /dev/null @@ -1,25 +0,0 @@ -{ config, lib, pkgs, modulesPath, ... }: -{ - fileSystems = { - "/" = { - device = "none"; - fsType = "tmpfs"; - options = [ "defaults" "noatime" "mode=755" ]; - }; - - "/boot" = { - device = "/dev/disk/by-label/NixOS-Boot"; - fsType = "vfat"; - options = [ "defaults" "noatime" ]; - depends = [ "/" ]; - }; - - "/nix" = { - device = "/dev/disk/by-label/NixOS-Primary"; - fsType = "btrfs"; - options = [ "subvol=@nix" "compress=zstd" "noatime" ]; - }; - }; - - zramSwap.enable = true; -} diff --git a/hosts/luna/os/hardware.nix b/hosts/luna/os/hardware.nix index 0c95975..f1d88b6 100644 --- a/hosts/luna/os/hardware.nix +++ b/hosts/luna/os/hardware.nix @@ -1,4 +1,5 @@ { lib, config, ... }: { hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; } diff --git a/hosts/luna/pubkey.nix b/hosts/luna/pubkey.nix new file mode 100644 index 0000000..d9a695d --- /dev/null +++ b/hosts/luna/pubkey.nix @@ -0,0 +1 @@ +"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF5AtCUEvm9pSi8iI4xH5wnJ6dR9tZZY7qPS4GLJbQAW luna" \ No newline at end of file diff --git a/install.bash b/install.bash index 0d3afc1..a96426e 100644 --- a/install.bash +++ b/install.bash @@ -1,179 +1,106 @@ -#!/usr/env/bin bash +#!/usr/bin/env bash -install() { - set -euo pipefail - local disk="${1}" - local encrypt_disk="${2}" - local host="${3}" +set -Eeuo pipefail - local boot_partition="" - local primary_partition="" - if [[ "${disk}" == *"nvme"* ]]; then - local boot_partition="${disk}p1" - local primary_partition="${disk}p2" - else - local boot_partition="${disk}1" - local primary_partition="${disk}2" +SCRIPT_DIR="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" + +gen-system-key() { + local system="${1:?"No system provided to generate a key for!"}" + local priv_key_path="${2:?"No private key path provided!"}" + local key_file="out-key" + local priv_key + local pub_key + + # Gen Key in a temp directory + pushd "$(mktemp -d)" >/dev/null + ssh-keygen -t ed25519 -f ./"${key_file}" -N '' -C "${system}" -q + priv_key="$(cat "${key_file}")" + pub_key="$(cat "${key_file}.pub")" + rm -f "${key_file}" "${key_file}.pub" >/dev/null + popd >/dev/null + + # Update public key for system and rekey secrets + printf "Rekeying for '%s' secrets with new system key!\n" "${system}" 1>&2 + local host_pubkey_path="${SCRIPT_DIR}/hosts/${system}/pubkey.nix" + if [[ -r "${host_pubkey_path}" ]]; then + local backup_pub_key_path + backup_pub_key_path="${host_pubkey_path}.$(date +'%Y-%d-%m_%H:%M:%S')" + printf "Backing up old public key file to '%s'!\n" "${backup_pub_key_path}" 1>&2 + mv "${host_pubkey_path}" "${backup_pub_key_path}" fi - # The size is large because I'd like to be able to hibernate my laptop in its entirety. I have 64 GB of ram. + printf '"%s"' > "${host_pubkey_path}" "${pub_key}" + git add "${host_pubkey_path}" 1>&2 - local label_crypt_luks="NixOS-Crypt" - local label_primary="NixOS-Primary" - local label_boot="NixOS-Boot" + pushd secrets >/dev/null + agenix -r -i "${priv_key_path}" 1>&2 + git add . 1>&2 + popd >/dev/null - swapoff -a >/dev/null 2>&1 || true - umount /mnt/**/* >/dev/null 2>&1 || true - umount /mnt/* >/dev/null 2>&1 || true - umount /mnt >/dev/null 2>&1 || true - cryptsetup close enc >/dev/null 2>&1 || true - wipefs -a "${disk}" || true - - ### Partition The Disk - parted "${disk}" -- mklabel gpt - # Boot partition - parted -a optimal "${disk}" -- mkpart ESP fat32 1MiB 1GiB - parted "${disk}" -- set 1 boot on - mkfs.vfat "${boot_partition}" - fatlabel "${boot_partition}" "${label_boot}" - # Primary Partition - parted -a optimal "${disk}" -- mkpart "${label_primary}" 1Gib 100% - - ### Encrypt - if [[ "${encrypt_disk}" == "yes" ]]; then - cryptsetup --verify-passphrase -v luksFormat "${primary_partition}" - cryptsetup config "${primary_partition}" --label "${label_crypt_luks}" - # Have to decrypt it so we can actually get other things setup - local crypt_open_name="enc" - cryptsetup open "${primary_partition}" "${crypt_open_name}" - primary_partition="/dev/mapper/${crypt_open_name}" - fi - - ### BTRFS Setup - # Go ahead and make the unencrypted BTRFS - mkfs.btrfs -f -L "${label_primary}" "${primary_partition}" - - # Mount it - mount -t btrfs "${primary_partition}" /mnt - - # Create our subvolumes - btrfs subvolume create "/mnt/@nix" - umount /mnt - - ### Final Mountings - # Mount tmpfs to mnt - mount -t tmpfs -o mode=755 none /mnt - - # Create our directories - mkdir /mnt/{"boot","nix"} - # Mount our boot partition - mount -t vfat -o defaults,noatime "${boot_partition}" /mnt/boot - - # Mount our btrfs subvolumes individually with some btrfs options - # NOTE: On high performance NVME SSDs with a beefy CPU it may be worth considering ZLO compression instead of ZSTD. In - # many cases ZLO is more performant, especially when writing, than ZSTD while having a somewhat worse comrpession ratio. - # WARN: ZLO *may* be a good solution, it can be VERY slow on incompressible data. Something to keep in mind. - mount -t btrfs -o noatime,compress=zstd,subvol=@nix "${primary_partition}" /mnt/nix - - # Persistence dir, dirs not to be wiped on reboot stored here - mkdir -p /mnt/nix/persist - # Actually install NixOS - nixos-install --flake "git+file:.#${host}" - # Finally, clone the flake into the persistent nixos config - git clone . /mnt/nix/persist/etc/nixos/ -} - -usage() { - cat <<-__EOF__ - Usage: $(basename "${0}") -d "/dev/DISK_HERE" -s 32 -e - -h | -? | --help - Shows this menu. - Example: - $(basename "${0}") -h - - -d | --disk [REQUIRED] - Path to a disk to install NixOS to. - Default: none - Example: - $(basename "${0}") -d /dev/vda - - -e | --encrypt [OPTIONAL] - Enable disk encryption during install. Note, this will prompt you for the encryption password. - Default: disabled - Example: - $(basename "${0}") -e - __EOF__ -} - -running_as_root() { - ((EUID == 0)) + printf "%s" "${priv_key}" } main() { - if ! running_as_root; then - printf "This script MUST be ran as root, exiting!\n" + local persist_dir="/mnt/nix/persist" + local flake_install_path="${persist_dir}/ephemeral/etc/nixos" + + local system="${1:?"Provide system to build!"}" + local flake=".#${system}" + local conn="${2:?"Provide ssh connection string! (E.g. root@myhost)"}" + local priv_key_path="${3:?Provide path to private key}" + shift 3 + if [[ ! -r "${priv_key_path}" ]]; then + printf "Unable a private key file at '%s'\n!" "${priv_key_path}" 1>&2 + exit 1 + elif [[ ! -r "${SCRIPT_DIR}/hosts/${system}" ]]; then + printf "Could not find a system named '%s' in '%s'!\n" "${system}" "${SCRIPT_DIR}/hosts" 1>&2 exit 1 fi + cat <<-__EOS__ + ───────────────────────────────── + Installing NixOS on Remote Host + ================================= + Host: "${conn}" + Flake: "${flake}" + ───────────────────────────────── + __EOS__ + printf "Generating system keys\n" + local new_sys_key + new_sys_key="$(gen-system-key "${system}" "${priv_key_path}")" + local nixos_anywhere_log + nixos_anywhere_log="$(nix run github:nix-community/nixos-anywhere -- --flake "${flake}" "${conn}" --stop-after-disko 2>&1 | tee >(cat >&2))" + local ssh_login_key="${nixos_anywhere_log##*$'\n'}"; ssh_login_key="${ssh_login_key#*\'}"; ssh_login_key="${ssh_login_key%\'*}" + local ssh_opts="-i ${ssh_login_key} -o GlobalKnownHostsFile=/dev/null -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" + local ssh_cmd="ssh ${conn} ${ssh_opts}" + local system_key_dest="${persist_dir}/ephemeral/etc/ssh/ssh_host_ed25519_key" + printf "SSH Command: %s\n" "${ssh_cmd}" + eval "${ssh_cmd}" <<- __EOS__ + mkdir -p "${persist_dir}/ephemeral/etc/ssh" + mkdir -p "${persist_dir}/save" + mkdir -p "${flake_install_path}" + printf "Putting new system key into place\n" + printf "%s\n" "${new_sys_key}" > "${system_key_dest}" + chmod 0600 "${system_key_dest}" + __EOS__ + printf "Copying flake to system\n"; + rsync -r "${SCRIPT_DIR}"/{*,.*} "${conn}:${flake_install_path}" -e "ssh ${ssh_opts}" --info=PROGRESS2 + printf "Doing final install\n" + eval "${ssh_cmd}" <<- __EOS__ + set -euo pipefail + cd "${flake_install_path}" + nix-env -f '' -iA git + sudo nixos-install --flake "git+file:${flake}" --no-root-password --no-channel-copy + reboot + __EOS__ + printf "%s\n" "${ssh_cmd}" - local disk="" - local host="" - local encrypt_disk="no" - - while :; do - case ${1} in - -h | -\? | --help) - usage # Display a usage synopsis. - exit - ;; - --) # End of all options. - break - ;; - -d | --disk) - shift - disk="${1}" - if [[ ! -b "${disk}" ]]; then - printf "Unable to read disk '%s', check that it exists, is a block device, and that you have write and read permissions for it!" "${disk}" - exit 1 - fi - printf "Setting installation disk to '%s'\n" "${disk}" - ;; - -e | --encrypt) - encrypt_disk="yes" - printf "Enabled disk encryption\n" - ;; - -H | --host) - shift - host="${1}" - printf "Set host to '%s'\n" "${host}" - ;; - -?*) - printf 'Unknown option: %s\n' "$1" >&2 - usage - exit 1 - ;; - *) # Default case: No more options, so break out of the loop. - break ;; - esac - shift - done - - set -euo pipefail - if [[ -z "${disk}" ]]; then - printf "Value for 'disk' (-d) was not provided! See '--help' for usage!\n" - exit 1 - fi - if [[ -z "${host}" ]]; then - printf "Value to 'host' (-H) was not provided! See '--help' for usage!\n" - exit 1 - fi - read -r -s -n 1 -p "Press any key to begin NixOS installation to '${disk}' for host '${host}'!" - printf "\n" - printf "Installing in " - for i in {3..1}; do - printf "%s.." "${i}" - sleep 1 - done - printf "\n" - install "${disk}" "${encrypt_disk}" "${host}" + cat <<- __EOS__ + ────────────────────────────────────────── + Finished Installing NixOS on Remote Host + ========================================== + Host: "${conn}" + Flake: "${flake}" + ────────────────────────────────────────── + __EOS__ } main "${@}" diff --git a/lib/default.nix b/lib/default.nix new file mode 100644 index 0000000..d5d8de9 --- /dev/null +++ b/lib/default.nix @@ -0,0 +1,32 @@ +# Some of these functions were taken from https://github.com/NixOS/nixpkgs/blob/master/lib/ +rec { + hasSuffix = + suffix: + string: + let + lenSuffix = builtins.stringLength suffix; + lenString = builtins.stringLength string; + in + ( + lenString >= lenSuffix && (builtins.substring (lenString - lenSuffix) lenString string) == suffix + ); + recurseDir = dir: + let + dirContents = builtins.readDir dir; + in + (builtins.concatMap + (dirItem: + let + itemType = builtins.getAttr dirItem dirContents; + itemPath = dir + "/${dirItem}"; + in + if itemType == "directory" then + (recurseDir itemPath) + else + [ itemPath ]) + (builtins.attrNames dirContents)); + recurseFilesInDir = dir: suffix: + (builtins.filter (file: hasSuffix "${suffix}" file) (recurseDir dir)); + recurseFilesInDirs = dirs: suffix: + (builtins.concatMap (dir: (recurseFilesInDir dir "${suffix}")) dirs); +} diff --git a/secrets/gitlab-runner-reg-config.age b/secrets/gitlab-runner-reg-config.age deleted file mode 100644 index ad14a3c25aec7660be4fc392f63dafd9c4bcc0bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 433 zcmV;i0Z#s5XJsvAZewzJaCB*JZZ2 zD=$NELo{(%Nmn*OHc?4JVQqFaOfX_)WJ@(-MRy8oV?}ONF*kB`WOO-4VMsScZB|QY zc6w<-XJztK_EeSZ&_J5LsTnQ zLsm{}GInTZV@^p&L2YqIQg&}NYBEJb7cxNFi=4?FIhEr zRW)}CEiEk|NJD34S9x(Xa87k-Oi(XvT19GXcuz-DR$^#kZc}hiSW#m^LT^(@Z+bxr z!7eDc_X=zl0R6^dc?UX>)Ap+keJ`)%X(v`LC53NG%LXEq$1)q=M9=f{;NSiUhg__( zm4CuR7zS_~6ZsUE?KEFfvHfuW_Va%Jq0)AiDFxSs6hQbd_0m+48A#bMFNn#lHxKeH bs77Cry7GAJ*d&CvIcdZ;#{kUMH>v-VBmklN diff --git a/secrets/luna/gitlab-runner-reg-config.age b/secrets/luna/gitlab-runner-reg-config.age new file mode 100644 index 0000000..22d9ce8 --- /dev/null +++ b/secrets/luna/gitlab-runner-reg-config.age @@ -0,0 +1,10 @@ +age-encryption.org/v1 +-> ssh-ed25519 4sH96w zBi3BGIf/OJza0ADpk264QCudT5mKzxcxgfxoNI9HSw +8Ys6frvd7UeXRXPpiClCJ+qoRHiE7K+TfQhbb1o34bk +-> piv-p256 rJs1HA Aw/GcBY+XMD/9++r819joYKKyIrf8gbpjgIgugLhBtBq +BTIRQ/6zl2HqJJrCGbeMwAwmp65EiU5jAs130/MoHOs +-> OKjJEPyZ-grease l {KDS$m oX;O="m +29gF4VbnR6zEbojhshhTvk2tYizn32MsCDsuutl+HCmVTNPvDIkWRSMPylfsZqLY +AMl5wcis0Spit7SKkNKJVCtL/39fXu5zgJU +--- VTqUeA4weWW1vN8qr5jsTgIgbU/3rvYQX8A0gPgYGus +IVҬ*H[հ/IEz#MiҮp0M(TSyDn@[/R亱?l7 ( 7&R8 D JE5(bpn5/w/ \ No newline at end of file diff --git a/secrets/luna/root-hash-pw.age b/secrets/luna/root-hash-pw.age new file mode 100644 index 0000000000000000000000000000000000000000..9ad335b5e62e167cd87284598c11c2eb20511323 GIT binary patch literal 540 zcmWm7OKg*1003a)j0Ze;(DcmJG)RF$A<=3dw1pN%p{!%k1EUmZ%VYmf8AZ)Jc-NR{ zqM4i7;$n8vgID8Gjft9=IODR#gEze_@!(B&`);4<*q9wyU>3z*7+eg2gC_)nl~D*? z%pQ<5O>k%twm4=LwIJOe7onubfiqTp)zk%Dse?R}QXY0vsTlYm3WrkWjghLfY`~P^ z>n>x6U4as#m|bukiWl>;5lOaKu~%?^Y>OH^-Xbr-B9dlMAVQ*5K`XFofI^WN(ty;g zkv>kCpp?&ggIJI&j>3c>pLRxOon4}0r0J^F0pLnzH%*jj=6e7Y_P|dcI`$n(=i9wCbSVck7tXVn{=qvsXZ0i;Ut@J&b($dxq>E>dMui~mQIk9 zk_J5@=z$rvq-#_sbNYFawJ1am1-BAV&|?ZrRGI3w8<7q)$DP z-g|WE_19geJeUOEzWhEyudi>tdHh2BJNHpK{Ihdm?%qr4!@C3L>i3h|Kl!y&pEtQ& KeCXvK?)?KiL&MSl literal 0 HcmV?d00001 diff --git a/secrets/secrets.nix b/secrets/secrets.nix index 1e1095c..0c99a5e 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -1,15 +1,29 @@ let - keys = rec { - master = "age1yubikey1qfnj0k4mkzrn8ef5llwh2sv6hd7ckr0qml3n9hzdpz9c59ypvryhyst87k0"; - orion-tech = { - luna = [ - "age1jgwqs04tphuuklx4g3gjdg42mchagn2gu7sftknerh8y8l9n7v7s27wqgu" - master + root-dir = builtins.toString ./.; + lib = import ../lib; + master-keys = [ + "age1yubikey1qfnj0k4mkzrn8ef5llwh2sv6hd7ckr0qml3n9hzdpz9c59ypvryhyst87k0" + ]; + hosts = { + luna = + let + secrets = "${root-dir}/luna"; + in + [ + "${secrets}/gitlab-runner-reg-config.age" + "${secrets}/root-hash-pw.age" ]; - }; }; in - -{ - "gitlab-runner-reg-config.age".publicKeys = keys.orion-tech.luna; -} +(builtins.listToAttrs + (builtins.concatMap + (host: + (builtins.map + (secret: { + name = builtins.toString secret; + value = { + publicKeys = [ (import ./../hosts/${host}/pubkey.nix) ] ++ master-keys; + }; + }) + (builtins.getAttr host hosts))) + (builtins.attrNames hosts)))