diff --git a/Justfile b/Justfile index 80bfd95..59a46f1 100644 --- a/Justfile +++ b/Justfile @@ -19,6 +19,9 @@ deploy: europium: nixos-rebuild switch --flake .#europium --target-host europium --build-host europium --use-remote-sudo +beryllium: + nixos-rebuild switch --flake .#beryllium --target-host beryllium --build-host beryllium --use-remote-sudo + # Opens the elements configuration in the default editor edit: {{editor}} {{shell('pwd')}} @@ -35,7 +38,7 @@ repl: # Enter a flake dev shell [group('nix')] shell name: - nix develop .#{{name}} + nix develop --extra-experimental-features "flakes nix-command" .#{{name}} # Updates nix flakes [group('nix')] diff --git a/README.md b/README.md index 015feed..3535ee9 100644 --- a/README.md +++ b/README.md @@ -15,13 +15,70 @@ depending on the context. In order to enter one of the configured devshells, one can use either the command `elements shell ` (if elements is already available) or run `nix develop .#name` in the flake root directory. +## How to deploy a new host + +Boot into a install medium. Since this repository is public, we don't need to mess +with any SSH keys yet. Clone the repository and enter it. +``` + git clone https://github.com/padarom/elements.git + cd elements +``` + +Then install just, which is the only explicit requirement for this deployment which +you must install manually. All other dependencies are installed via the dev shell. + +After installing just, enter the deployment shell. +``` + nix-shell -p just + just shell deploy +``` + +Now, a basic host configuration (with a disko module) is required. This can either +be prepared on another host and comitted, or created now, in the install media. +Depending on how many hosts I will still onboard, I might end up creating helper +functionality in the dev shell specifically for this use case. + +Now, say the host we want to deploy is configured as `hydrogen`. Inspect the +compiled disko disk configuration for the host: +``` + elements disk-test hydrogen +``` + +If that configuration seems fine, you can deploy it. This will wipe and reformat +the configured drives. Disko will ask you whether you want to confirm. +``` + elements disk hydrogen +``` + +Your disk is now ready and you can install NixOS onto the disk. Run the following: +``` + elements install hydrogen +``` + +Now NixOS is ready and can be booted. You can decide whether you also want to +copy the elements config into a user's home directory. Alternatively, the host can +simply be remote-managed via another host, so this step isn't always necessary. +``` + elements config hydrogen {username} +``` + +Ideally in the future we'll be able to set an encrypted password file and deploy +the host with that. Since the host does not yet have a SSH key to decrypt any +(rekeyed) secrets that might already be present, that is not yet possible. Therefore +the following is still required: +``` + # Exit from all dev shells to get back to your original shell + + sudo nixos-enter + passwd {username} +``` + ### Todo Since this is pretty much always a work-in-progress I do not expect it to be in the most presentable state at all times. Whenever I have time I try to streamline some of the config, but especially when trying out new tools the code could be a bit wild. There's a couple of ideas I have for this: -- [ ] Build a deployment dev shell - [ ] Deploy base tooling to all hosts. This mainly includes `nushell` and `helix` configs. They should still be configurable per-host. Potential issue here could be hosts where I don't use home manager - [ ] Make everything more composable. Can make use of the `elements` config some more, like how it's done for `quirks` diff --git a/lib/default.nix b/lib/default.nix index 5b2d379..7801f8a 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -1,4 +1,4 @@ -{lib, ...}: rec { +{lib, ...}: { rootPath = ./..; secret = name: ./../secrets/${name}; diff --git a/modules/nixos/services/beszel.nix b/modules/nixos/services/beszel.nix index b5d8b3a..ad82e1b 100644 --- a/modules/nixos/services/beszel.nix +++ b/modules/nixos/services/beszel.nix @@ -10,6 +10,15 @@ in { options.services = { beszel-agent = { enable = mkEnableOption "Enable the Beszel Agent"; + key = mkOption { + type = types.str; + description = "The public key to bind the agent to"; + }; + port = mkOption { + type = types.int; + description = "The port to bind the agent to"; + default = 45876; + }; }; }; @@ -24,8 +33,8 @@ in { description = "Beszel Agent (remote monitoring)"; environment = { - KEY = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMkUPOw28Cu2LMuzfmvjT/L2ToNHcADwGyGvSpJ4wH2T"; - LISTEN = "45876"; + KEY = cfg.key; + LISTEN = builtins.toString cfg.port; }; serviceConfig = { diff --git a/shells/deploy/Justfile b/shells/deploy/Justfile index f1e55ff..9799a2e 100644 --- a/shells/deploy/Justfile +++ b/shells/deploy/Justfile @@ -1,5 +1,40 @@ -# TODO: Figure out how to link to the root Justfile and import -# it with `import '../../Justfile`. +default: + @just --list --justfile {{justfile()}} -say word: - @cowsay {{word}} +# Inspect the disk configuration compiled by disko. +[no-cd] +disk-test host: + #!/usr/bin/env bash + set -euxo pipefail + build_path=$(disko --dry-run --flake "$(pwd)#{{host}}" | tail -n 1) + less $build_path + +# Deploys the disk configuration. This will reformat and mount the disk. +[no-cd] +disk host: + sudo disko --flake "$(pwd)#{{host}}" -m destroy,format,mount + +# Mounts the configured disk. Useful for when the disk is already formatted. +[no-cd] +mount host: + sudo disko --flake "$(pwd)#{{host}}" -m mount + +# Installs NixOS onto the drives previously mounted by disko. +[no-cd] +install host: + #!/usr/bin/env bash + sudo nixos-install --flake "$(pwd)#{{host}}" + +# Deploys the dotfile repository to a user's home dir. +[no-cd] +config host user: + #!/usr/bin/env bash + set -euxo pipefail + home=$(nix eval --extra-experimental-features "nix-command flakes" --impure --expr "(builtins.getFlake \"$(pwd)\").nixosConfigurations.{{host}}.config.users.users.{{user}}.home" | tail -n 1 | tr -d \") + cp -R $(pwd) "/mnt$home/.dotfiles" + +# send-key: +# croc send ~/.ssh/id_key + +# receive-key phrase: +# croc {{phrase}} diff --git a/shells/deploy/default.nix b/shells/deploy/default.nix index a2d08a9..41757a0 100644 --- a/shells/deploy/default.nix +++ b/shells/deploy/default.nix @@ -1,13 +1,20 @@ -{pkgs, ...}: +{ + lib, + inputs, + pkgs, + ... +}: pkgs.mkShell { packages = with pkgs; [ just - cowsay + croc + inputs.disko.packages.${pkgs.system}.disko + helix ]; # Define an alias to use a Justfile specifically with # deployment tooling enabled. shellHook = '' - alias elements="just -f ${././Justfile} -d ${../..}" + alias elements="just -f ${././Justfile}" ''; } diff --git a/systems/x86_64-linux/beryllium/default.nix b/systems/x86_64-linux/beryllium/default.nix index 38e840f..326ccba 100644 --- a/systems/x86_64-linux/beryllium/default.nix +++ b/systems/x86_64-linux/beryllium/default.nix @@ -1,11 +1,70 @@ # ++ 4_Be: Beryllium # -# NUC environment -{lib, ...}: { +# NUC / HomeLab environment +{ + lib, + pkgs, + ... +}: { + imports = [ + ./hardware.nix + ./disko.nix + ]; + + # Set up two main drives for RAID 1 + disko.devices.disk = { + one.device = "/dev/sda"; + two.device = "/dev/sdb"; + }; + + boot = { + loader = { + efi.canTouchEfiVariables = true; + grub = { + enable = true; + efiSupport = true; + device = "nodev"; + mirroredBoots = [ + { + devices = ["/dev/sda"]; + path = "/boot"; + } + { + devices = ["/dev/sdb"]; + path = "/boot2"; + } + ]; + }; + }; + + # Set up mdmon to notify me when one of the drives fails + swraid.mdadmConf = '' + MAILADDR raid@muehl.dev + ''; + }; + elements = { hostname = "beryllium"; + users = ["christopher"]; secrets = { - key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEp5oRV7VbOlQ172/mLskChJwK6snXD9P4ZeROxniJtJ"; + key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBUKDCjB0VpQubi8BfnYKbh4MIE1tcvKQesdoPE4NXAf"; }; }; + + users.users.christopher.openssh.authorizedKeys.keys = ["ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMVKJfY6B9TsUPdPXy3tkqL42sJgJRz3NOOKTqhytMMf christopher@cobalt"]; + + services = { + openssh.enable = true; + openssh.ports = [7319]; + openssh.settings.PasswordAuthentication = false; + + beszel-agent.enable = true; + beszel-agent.key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMkUPOw28Cu2LMuzfmvjT/L2ToNHcADwGyGvSpJ4wH2T"; + }; + + virtualisation.podman.enable = true; + + environment.systemPackages = with pkgs; [ + podman-compose + ]; } diff --git a/systems/x86_64-linux/beryllium/disko.nix b/systems/x86_64-linux/beryllium/disko.nix new file mode 100644 index 0000000..02bdedf --- /dev/null +++ b/systems/x86_64-linux/beryllium/disko.nix @@ -0,0 +1,63 @@ +let + mkDrive = bootMountpoint: { + type = "disk"; + content = { + type = "gpt"; + partitions = { + boot = { + size = "1M"; + type = "EF02"; # for grub MBR + }; + ESP = { + size = "512M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = bootMountpoint; + mountOptions = ["umask=0077"]; + }; + }; + swap = { + size = "8G"; + content = { + type = "swap"; + discardPolicy = "both"; + }; + }; + mdadm = { + size = "100%"; + content = { + type = "mdraid"; + name = "raid1"; + }; + }; + }; + }; + }; +in { + disko.devices = { + disk = { + one = mkDrive "/boot"; + two = mkDrive "/boot2"; + }; + + mdadm = { + raid1 = { + type = "mdadm"; + level = 1; + content = { + type = "gpt"; + partitions.primary = { + size = "100%"; + content = { + type = "filesystem"; + format = "ext4"; + mountpoint = "/"; + }; + }; + }; + }; + }; + }; +} diff --git a/systems/x86_64-linux/beryllium/hardware.nix b/systems/x86_64-linux/beryllium/hardware.nix new file mode 100644 index 0000000..05213be --- /dev/null +++ b/systems/x86_64-linux/beryllium/hardware.nix @@ -0,0 +1,17 @@ +{ + config, + lib, + ... +}: { + boot.initrd.availableKernelModules = ["xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" "rtsx_pci_sdmmc"]; + boot.initrd.kernelModules = []; + boot.kernelModules = ["kvm-intel"]; + boot.extraModulePackages = []; + boot.swraid.enable = true; + + networking.useDHCP = lib.mkDefault true; + + virtualisation.virtualbox.guest.enable = true; + + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/systems/x86_64-linux/cobalt/default.nix b/systems/x86_64-linux/cobalt/default.nix index e4810b0..a09d766 100644 --- a/systems/x86_64-linux/cobalt/default.nix +++ b/systems/x86_64-linux/cobalt/default.nix @@ -10,7 +10,7 @@ with lib._elements; { imports = [ ./hardware.nix - ./disk-config.nix + ./disko.nix ]; elements = { @@ -100,6 +100,7 @@ with lib._elements; { # Linux link via MQTT lnxlink.enable = true; beszel-agent.enable = true; + beszel-agent.key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMkUPOw28Cu2LMuzfmvjT/L2ToNHcADwGyGvSpJ4wH2T"; pipewire = { enable = lib.mkForce true; diff --git a/systems/x86_64-linux/cobalt/disk-config.nix b/systems/x86_64-linux/cobalt/disko.nix similarity index 100% rename from systems/x86_64-linux/cobalt/disk-config.nix rename to systems/x86_64-linux/cobalt/disko.nix diff --git a/systems/x86_64-linux/mercury/default.nix b/systems/x86_64-linux/mercury/default.nix index 251c222..47a12c5 100644 --- a/systems/x86_64-linux/mercury/default.nix +++ b/systems/x86_64-linux/mercury/default.nix @@ -10,7 +10,7 @@ with lib._elements; { imports = [ ./hardware.nix - ./disk-config.nix + ./disko.nix ]; elements = { diff --git a/systems/x86_64-linux/mercury/disk-config.nix b/systems/x86_64-linux/mercury/disko.nix similarity index 100% rename from systems/x86_64-linux/mercury/disk-config.nix rename to systems/x86_64-linux/mercury/disko.nix