diff --git a/src/nixos/machines/ignucius/services/distributedBuilds.nix b/src/nixos/machines/ignucius/services/distributedBuilds.nix index e700a01e..73d23781 100644 --- a/src/nixos/machines/ignucius/services/distributedBuilds.nix +++ b/src/nixos/machines/ignucius/services/distributedBuilds.nix @@ -39,25 +39,25 @@ in mkIf config.nix.distributedBuilds { nix = { buildMachines = [ - # { - # # MORPH - # hostName = "morph.systems.nx"; - # systems = [ "x86_64-linux" "i686-linux" "aarch64-linux" ]; - # protocol = "ssh-ng"; + { + # MORPH + hostName = "morph.systems.nx"; + systems = [ "x86_64-linux" "i686-linux" "aarch64-linux" ]; + protocol = "ssh-ng"; - # # FIXME-QA(Krey): Set this as a variable from nixos/modules/distributedBuilds - # sshUser = "builder"; - # # sshUser = builder-account; + # FIXME-QA(Krey): Set this as a variable from nixos/modules/distributedBuilds + sshUser = "builder"; + # sshUser = builder-account; - # # FIXME-QA(Krey): Set this as a variable from nixos/modules/distributedBuilds - # sshKey = "/etc/ssh/ssh_builder_ed25519_key"; - # #sshKey = "${builder-key-path}/ssh_${builder-account}_ed25519_key"; + # FIXME-QA(Krey): Set this as a variable from nixos/modules/distributedBuilds + sshKey = "/etc/ssh/ssh_builder_ed25519_key"; + #sshKey = "${builder-key-path}/ssh_${builder-account}_ed25519_key"; - # maxJobs = 8; # 100%, 16GB RAM available - # speedFactor = 10; - # supportedFeatures = [ "nixos-test" "benchmark" "big-parallel" "kvm" ]; - # mandatoryFeatures = [ ]; - # } + maxJobs = 8; # 100%, 16GB RAM available + speedFactor = 10; + supportedFeatures = [ "nixos-test" "benchmark" "big-parallel" "kvm" ]; + mandatoryFeatures = [ ]; + } # { # # SINNENFREUDE # hostName = "sinnenfreude.systems.nx"; diff --git a/src/nixos/machines/morph/config/disks.nix b/src/nixos/machines/morph/config/disks.nix index 05be68ef..59bf6340 100644 --- a/src/nixos/machines/morph/config/disks.nix +++ b/src/nixos/machines/morph/config/disks.nix @@ -57,6 +57,10 @@ in mkMerge [ content = { type = "filesystem"; format = "vfat"; # FAT32 + # SECURITY(Krey): Required since systemd 254, to not make the random-seed file writtable by default + # * https://github.com/nix-community/disko/issues/527#issuecomment-1924076948 + # * https://discourse.nixos.org/t/nixos-install-with-custom-flake-results-in-boot-being-world-accessible/34555/14 + mountOptions = [ "umask=0077" ]; mountpoint = "/boot"; }; }; diff --git a/src/nixos/machines/morph/config/kernel.nix b/src/nixos/machines/morph/config/kernel.nix index bb544bee..fea16c06 100644 --- a/src/nixos/machines/morph/config/kernel.nix +++ b/src/nixos/machines/morph/config/kernel.nix @@ -6,6 +6,7 @@ let inherit (lib) mkIf mkForce; in { # NOTE(Krey): Morph is projected to be used as a gaming server where the hardened kernel might impact it's performance too much + # FIXME-SECURITY(Krey): Hardened kernel causes lot of issues, pending custom kernel boot.kernelPackages = mkForce pkgs.linuxPackages; # Kernel Modules diff --git a/src/nixos/machines/morph/releases/24_05/default.nix b/src/nixos/machines/morph/releases/24_05/default.nix new file mode 100644 index 00000000..79befee8 --- /dev/null +++ b/src/nixos/machines/morph/releases/24_05/default.nix @@ -0,0 +1,104 @@ +{ inputs, lib, self,... }: + +# Declaration for 24_05 release of NixOS for MORPH + +let + inherit (lib) mkForce; +in { + flake.nixosConfigurations."nixos-morph-24_05" = inputs.nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + + pkgs = import inputs.nixpkgs { + system = "x86_64-linux"; + config.allowUnfree = mkForce false; # Forbid proprietary code + config.nvidia.acceptLicense = mkForce false; # Nvidia, Fuck You! + }; + + modules = [ + self.nixosModules."nixos-morph" + + { + nix.nixPath = [ + "nixpkgs=${self.inputs.nixpkgs}" + ]; + + nix.registry = { + nixpkgs = { flake = self.inputs.nixpkgs; }; + }; + } + + # Principles + self.inputs.ragenix.nixosModules.default + self.inputs.sops.nixosModules.sops + self.inputs.hm.nixosModules.home-manager + self.inputs.disko.nixosModules.disko + self.inputs.lanzaboote.nixosModules.lanzaboote + self.inputs.impermanence.nixosModules.impermanence + self.inputs.arkenfox.hmModules.default + + # An Anime Game + self.inputs.aagl.nixosModules.default { + networking.mihoyo-telemetry.block = true; # Block miHoYo telemetry servers + nix.settings = { + substituters = [ "https://ezkea.cachix.org" ]; + trusted-public-keys = [ "ezkea.cachix.org-1:ioBmUbJTZIKsHmWWXPe1FSFbeVe+afhfgqgTSNd34eI=" ]; + }; + } + ]; + + specialArgs = { + inherit self; + + # Priciple args + stable = import inputs.nixpkgs { + system = "x86_64-linux"; + config.allowUnfree = mkForce false; # Forbid proprietary code + }; + + unstable = import inputs.nixpkgs-unstable { + system = "x86_64-linux"; + config.allowUnfree = mkForce false; # Forbid proprietary code + }; + + staging = import inputs.nixpkgs-staging { + system = "x86_64-linux"; + config.allowUnfree = mkForce false; # Forbid proprietary code + }; + + staging-next = import inputs.nixpkgs-staging-next { + system = "x86_64-linux"; + config.allowUnfree = mkForce false; # Forbid proprietary code + }; + }; + }; + + # Task to perform installation of morph in NixOS distribution, 24_05 release + perSystem = { system, pkgs, inputs', self', ... }: { + packages.nixos-morph-24_05-install = pkgs.writeShellApplication { + name = "nixos-morph-24_05-install"; + bashOptions = [ + "errexit" # Exit on False Return + "posix" # Run in POSIX mode + ]; + runtimeInputs = [ + inputs'.disko.packages.disko-install # disko-install + pkgs.age # age + pkgs.nixos-install-tools # nixos-install + pkgs.gawk # awk + pkgs.curl + pkgs.jq + ]; + runtimeEnv = { + systemDevice = self.nixosConfigurations.nixos-morph-24_05.config.disko.devices.disk.system.device; + + secretPasswordPath = self.nixosConfigurations.nixos-morph-24_05.config.age.secrets.morph-disks-password.file; + + secretSSHHostKeyPath = self.nixosConfigurations.nixos-morph-24_05.config.age.secrets.morph-ssh-ed25519-private.file; + }; + text = builtins.readFile ./morph-nixos-24_05-install.sh; + }; + + # Declare for `nix run` + apps.nixos-morph-24_05-install.program = self'.packages.nixos-morph-24_05-install; + }; +} diff --git a/src/nixos/machines/morph/releases/24_05/morph-nixos-24_05-install.sh b/src/nixos/machines/morph/releases/24_05/morph-nixos-24_05-install.sh new file mode 100644 index 00000000..881471a5 --- /dev/null +++ b/src/nixos/machines/morph/releases/24_05/morph-nixos-24_05-install.sh @@ -0,0 +1,110 @@ +#@ This POSIX Shell Script is executed in an isolated reproducible environment managed by Nix , which handles dependencies, ensures deterministic function imports, sets any needed variables and performs strict linting prior to script execution to capture common issues for quality assurance. + +# shellcheck disable=SC2154 # Do not trigger SC2154 for variables provided to the environment by Nix +{ + : "$systemDevice" # Absolute path to target device by id + : "$secretPasswordPath" # Path to the file storing decrypted secret with disk password + : "$secretSSHHostKeyPath" # Path to the private SSH key of the system + : "$nixiumDoNotReboot" # Internal variable to prevent reboot after installation for special use-cases +} + +### [START] Export this outside [START] ### + +# FIXME-QA(Krey): This should be a runtimeInput +die() { printf "FATAL: %s\n" "$2"; exit ;} # Termination Helper + +# FIXME-QA(Krey): This should be a runtimeInput +status() { printf "STATUS: %s\n" "$1" ;} # Status Helper + +# FIXME-QA(Krey): This should be a runtimeInput +warn() { printf "WARNING: %s\n" "$1" ;} # Warning Helper + +# FIXME(Krey): This should be managed for all used scripts e.g. runtimeEnv +# Refer to https://github.com/srid/flake-root/discussions/5 for details tldr flake-root doesn't currently allow parsing the specific commit +#[ -n "$FLAKE_ROOT" ] || FLAKE_ROOT="github:NiXium-org/NiXium/$(curl -s -X GET "https://api.github.com/repos/NiXium-org/NiXium/commits" | jq -r '.[0].sha')" +[ -n "$FLAKE_ROOT" ] || FLAKE_ROOT="github:NiXium-org/NiXium/$(curl -s -X GET "https://api.github.com/repos/NiXium-org/NiXium/commits?sha=central" | jq -r '.[0].sha')" + +### [END] Export this outside [END] ### + +[ "$(id -u || true)" = 0 ] || die 126 "This script must be executed as the root user" # Ensure that we are root + +# Check if the declared installation device is available on the target system +[ -b "$systemDevice" ] || die 1 "Expected device was not found, refusing to install for safety" + +###! This script performs declarative installation of NiXium-Managed NixOS 24_05 for the MORPH system +###! +###! For that we utilize: +###! * Ragenix - The Rust implementation of agenix which is used to handle secrets in a declarative way +###! * Disko (specifically 'disko-install') - NixOS utility used to declaratively format disks and perform system installation +###! +###! First we need to decrypt the needed secrets mainly we need: +###! * The disk encryption password - Used to encrypt the disks +###! * Private SSH host key - Required by NiXium to differenciate the system and ability to decrypt secrets +###! +###! ..in the ragenix-expected directory which is `/run/agenix/`. +###! +###! Then we pre-build the system configuration to avoid rebuilds and lesser the risk of failure later and initialize the disko-install payload after which the system will reboot into the new Operating System. +###! +###! Warning: For this payload to work we require that the disks that we are manipulating are not used to boot the current Operating System as otherwise disko-install will fail for safety. Use recovery disk or load a minimal nixos installer in the Random Access Memory ("RAM") + +#! Ensure sane Ragenix Secret Directory ("RSD") +# By default the RSD is a symlink to /run/agenix.d/ +if [ -L "/run/agenix" ]; then + status "Required Ragenix Secret Directory is present" + +else # We assume that ragenix is not deployed on the target system + status "Expected Ragenix Secret Directory is not present, setting up manually" + + [ -d "/run/agenix" ] || mkdir --verbose --parents /run/agenix.d/1 + + ln --verbose --symbolic /run/agenix.d/1 /run/agenix # Perform the symlink + + # Ensure that the RSD has the expected permissions + chown --verbose "root:root" "/run/agenix.d/1" # Ensure expected ownership + chmod --verbose 700 "/run/agenix.d/1" # Ensure expected permission + + status "Ragenix Secret Directory has been set up" +fi + +#! Set up the identity file +status "Verifying the Identity File" + +[ -n "$ragenixIdentity" ] || ragenixIdentity="$HOME/.ssh/id_ed25519" # Try to use the default path + +# If the identity file is provided then use it to decrypt the secrets otherwise use hard-coded secrets +if [ -s "$ragenixIdentity" ]; then + status "The identity file is provided trying to decrypt the secrets" + + [ -s "/run/agenix/morph-disks-password" ] || age --identity "$ragenixIdentity" --decrypt --output "/run/agenix/morph-disks-password" "$secretPasswordPath" + + [ -s "/run/agenix/morph-ssh-ed25519-private" ] || age --identity "$ragenixIdentity" --decrypt --output "/run/agenix/morph-ssh-ed25519-private" "$secretSSHHostKeyPath" + + status "Decrypting of required secrets was successful" +else + status "Required Identity File was not found, managing by using hard-coded secrets" + + warn "BEWARE THAT USING HARD-CODED SECRETS IS A SECURITY HOLE!" + + [ -s "/run/agenix/morph-disks-password" ] || echo "000000" > "/run/agenix/morph-ssh-ed25519-private" + + [ -s "/run/agenix/morph-ssh-ed25519-private" ] || ssh-keygen -f "/run/agenix/morph-ssh-ed25519-private" -N "" +fi + +#! Pre-build the system configuration +status "Pre-building the system configuration" +nixos-rebuild build --flake "$FLAKE_ROOT#nixos-morph-24_05" # pre-build the configuration + +#! Perform the Payload +status "Performing the system installation" +esudo disko-install \ + --flake "$FLAKE_ROOT#nixos-morph-24_05" \ + --mode format \ + --debug \ + --disk system "$(realpath "$systemDevice" || true)" \ + --extra-files "$/run/agenix/morph-ssh-ed25519-private" /nix/persist/system/etc/ssh/ssh_host_ed25519_key + +#! Reboot in the new Operating System +[ "$nixiumDoNotReboot" = 0 ] || { + status "Installation was successful, performing reboot" + reboot +} diff --git a/src/nixos/machines/morph/releases/default.nix b/src/nixos/machines/morph/releases/default.nix index 6243d0c8..2c41e002 100644 --- a/src/nixos/machines/morph/releases/default.nix +++ b/src/nixos/machines/morph/releases/default.nix @@ -3,5 +3,6 @@ ./master ./stable ./unstable + ./24_05 ]; } diff --git a/src/nixos/machines/morph/releases/stable/default.nix b/src/nixos/machines/morph/releases/stable/default.nix index f2caf60b..2117d88f 100644 --- a/src/nixos/machines/morph/releases/stable/default.nix +++ b/src/nixos/machines/morph/releases/stable/default.nix @@ -1,4 +1,4 @@ -{ inputs, lib, self,... }: +{ inputs, lib, self, self', ... }: # Declaration for STABLE release of NixOS for MORPH @@ -100,5 +100,80 @@ in { # Declare for `nix run` apps.nixos-morph-stable-install.program = self'.packages.nixos-morph-stable-install; + + # Unattended installer + packages.nixos-morph-stable-unattended-installer-iso = inputs.nixos-generators.nixosGenerate { + pkgs = import inputs.nixpkgs { + inherit system; + config.allowUnfree = true; + }; + + inherit system; + + modules = [ + { + boot.loader.timeout = mkForce 0; + + boot.kernelParams = [ + "copytoram" # Run the installer from the Random Access Memory + ]; + + environment.systemPackages = [ + pkgs.git + ]; + + nix.settings.experimental-features = "nix-command flakes"; + + services.getty.loginProgram = "${pkgs.util-linux}/bin/nologin"; # Do not permit login on ttys + + services.getty.greetingLine = ''<<< Welcome To The NiXium Installer >>>''; + + systemd.services.inception = { + description = "NiXium Installation"; + after = [ "multi-user.target" ]; + wantedBy = [ "network-online.target" ]; + path = [ + inputs'.disko.packages.disko-install # disko-install + pkgs.age # age + pkgs.nixos-install-tools # nixos-install + pkgs.gawk # awk + pkgs.curl + pkgs.jq + pkgs.openssh # ssh-keygen + pkgs.nixos-rebuild + pkgs.util-linux # mountpoint + ]; + + serviceConfig = { + ExecStart = "${pkgs.nix}/bin/nix run github:kreyren/nixos-config/morph-changes#nixos-morph-stable-install"; + StandardInput = "tty-force"; # Force interaction with TTY1 + StandardOutput = "tty"; # Show the output on the TTY + StandardError = "tty"; # Display any errors on the TTY + TTYPath = "/dev/tty1"; # Specify TTY1 for the interaction + Restart = "always"; + # Make it wait 30 sec so that we don't blow past the API rate limits in case there is an error + RestartSec = 30; # Wait 30 second before trying again + }; + }; + + # Connect to FreeNet if the system doesn't have access to the internet by itself + networking.wireless.networks."FreeNet" = { }; + } + + { + services.sshd.enable = true; # Start OpenSSH server + users.users.root.openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOzh6FRxWUemwVeIDsr681fgJ2Q2qCnwJbvFe4xD15ve kreyren@fsfe.org" # Allow root access for the Super Administrator (KREYREN) + ]; + } + ]; + format = "iso"; + + specialArgs = { + inherit self; + }; + }; + + apps.nixos-morph-stable-unattended-installer-iso.program = self'.packages.nixos-morph-stable-unattended-installer-iso; }; } diff --git a/src/nixos/machines/morph/releases/stable/morph-nixos-stable-install.sh b/src/nixos/machines/morph/releases/stable/morph-nixos-stable-install.sh index 763a4d97..4bd7eb01 100644 --- a/src/nixos/machines/morph/releases/stable/morph-nixos-stable-install.sh +++ b/src/nixos/machines/morph/releases/stable/morph-nixos-stable-install.sh @@ -22,7 +22,7 @@ warn() { printf "WARNING: %s\n" "$1" ;} # Warning Helper # FIXME(Krey): This should be managed for all used scripts e.g. runtimeEnv # Refer to https://github.com/srid/flake-root/discussions/5 for details tldr flake-root doesn't currently allow parsing the specific commit #[ -n "$FLAKE_ROOT" ] || FLAKE_ROOT="github:NiXium-org/NiXium/$(curl -s -X GET "https://api.github.com/repos/NiXium-org/NiXium/commits" | jq -r '.[0].sha')" -[ -n "$FLAKE_ROOT" ] || FLAKE_ROOT="github:NiXium-org/NiXium/$(curl -s -X GET "https://api.github.com/repos/NiXium-org/NiXium/commits?sha=central" | jq -r '.[0].sha')" +[ -n "$FLAKE_ROOT" ] || FLAKE_ROOT="github:kreyren/nixos-config/morph-changes" ### [END] Export this outside [END] ###