From c2d5ea6060d4bfe1549760876e5d2f9665c82af5 Mon Sep 17 00:00:00 2001 From: Yadunand Prem Date: Sat, 17 Aug 2024 01:06:26 +0800 Subject: [PATCH] feat: vm setup --- Readme.md | 51 ++++++++++++++++++++++++ flake.nix | 37 +++++++++++++++++ nixos/common/users.nix | 2 + nixos/proxmox/setup-vm.sh | 53 +++++++++++++++++++++++++ nixos/secrets/keys.nix | 4 ++ nixos/secrets/secrets.nix | 6 +++ nixos/secrets/tailscale.age | 8 ++++ nixos/server/configuration.nix | 32 +++++++++++++++ nixos/server/disko-config.nix | 33 +++++++++++++++ nixos/server/hardware-configuration.nix | 23 +++++++++++ 10 files changed, 249 insertions(+) create mode 100644 Readme.md create mode 100755 nixos/proxmox/setup-vm.sh create mode 100644 nixos/secrets/keys.nix create mode 100644 nixos/secrets/secrets.nix create mode 100644 nixos/secrets/tailscale.age create mode 100644 nixos/server/configuration.nix create mode 100644 nixos/server/disko-config.nix create mode 100644 nixos/server/hardware-configuration.nix diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..042f2f9 --- /dev/null +++ b/Readme.md @@ -0,0 +1,51 @@ +# Homelab +A quick guide on setting up new VMs / Servers in the Homelab with proxmox. +## Pre-Requisites +1. A tailscale setup, with a preauthkey with a long expiry. This will be baked into the nixos ISO for easy access to new VMs +# Install Guide + +1. Generate ISO + +This is to be run on the proxmox node. + +```bash +TAILSCALE_AUTH_KEY= nix build --refresh --verbose --impure "git+https://gitea.ts.yadunut.com/yadunut/homelab.git#generate-iso" +``` +Copy ISO Over to the VM +```bash +cp ./result/iso/nixos-yadunut.iso /var/lib/vz/template/iso +``` + +2. Create virtual machines on proxmox + +This command is to be run on the proxmox Node / via SSH. Follow the guide to setup the VM. + +TODO: This currently only works on falcon, to support other nodes, I need to create new VMs via the API with `pvesh` instead of the `qm` tool. +```bash +nix run --refresh --verbose "git+https://gitea.ts.yadunut.com/yadunut/homelab.git.#create-vm" +``` +Copy the IP address + +3. Use nixos-anywhere to bootstrap virtual machines + +```bash +nix run ".#bootstrap"` +``` + +# Process to creating a New Machine +1. Create an ISO and transfer it over to Proxmox if it doesn't already exist +2. Create the VMs on Proxmox with the `nix run "git+https://gitea.ts.yadunut.com/yadunut/homelab.git#create-vm"` command +3. Create the machine configuration in `./nixos/machines` +4. With NixOS anywhere, + +# Problem +I want to copy the tailscale key over to the newly initialized VMs. I guess the VMs don't need to have tailscale setup on launch of the ISO unless I bake it into the ISO :thinking: + +Wait I could bake it into the ISO. + +It has been baked into the ISO. So now, I can connect to the VM from without being in the same network :) + +Now that I have VMs booted into the ISO, I need to setup the VMs. This would firstly require: +1. Generating the host keys +2. Tailscale encrypt with age, and transfer to the VM +3. Encrypting diff --git a/flake.nix b/flake.nix index 7e71f67..cc4f0cf 100644 --- a/flake.nix +++ b/flake.nix @@ -42,6 +42,43 @@ ]; }; }; + + packages.aarch64-darwin = { + setup-vm = let + pkgs = import nixpkgs { system = "aarch64-darwin"; }; + script-name = "setup-vm"; + src = builtins.readFile ./nixos/proxmox/setup-vm.sh; + script = (pkgs.writeScriptBin script-name src).overrideAttrs(old: { + buildCommand = "${old.buildCommand}\n patchShebangs $out"; + }); + buildInputs = with pkgs; [ + gum + agenix.packages.aarch64-darwin.default + ]; + in pkgs.symlinkJoin { + name = script-name; + paths = [ script ] ++ buildInputs; + nativeBuildInputs = with pkgs; [makeWrapper]; + postBuild = "wrapProgram $out/bin/${script-name} --prefix PATH : $out/bin"; + }; + }; + + nixosConfigurations = let + nodes = ["premhome-falcon-1" "premhome-falcon-2"]; + in builtins.listToAttrs (map (name: { + name = name; + value = nixpkgs.lib.nixosSystem { + specialArgs = { meta = { hostname = name; }; }; + modules = [ + disko.nixosModules.disko + agenix.nixosModules.default + ./nixos/server/disko-config.nix + ./nixos/server/configuration.nix + ./nixos/server/hardware-configuration.nix + ]; + }; + }) nodes); + } // flake-utils.lib.eachDefaultSystem (system: let pkgs = import nixpkgs { inherit system; diff --git a/nixos/common/users.nix b/nixos/common/users.nix index 14c57a1..30adbe0 100644 --- a/nixos/common/users.nix +++ b/nixos/common/users.nix @@ -5,4 +5,6 @@ openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJXOpmWsAnl2RtOuJJMRUx+iJTwf2RWJ1iS3FqXJFzFG" ]; }; security.sudo.wheelNeedsPassword = false; + + users.users.root.openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJXOpmWsAnl2RtOuJJMRUx+iJTwf2RWJ1iS3FqXJFzFG" ]; } diff --git a/nixos/proxmox/setup-vm.sh b/nixos/proxmox/setup-vm.sh new file mode 100755 index 0000000..7504430 --- /dev/null +++ b/nixos/proxmox/setup-vm.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash + +set -Eeuo pipefail + +script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd -P) +tmp_dir=$(mktemp -d) + +function cleanup() { + trap - SIGINT SIGTERM ERR EXIT + + echo "Cleaning Up" + + rm -rf "${tmp_dir}" +} +trap cleanup SIGINT SIGTERM ERR EXIT + +function main() { + if [ ! -e "./flake.nix" ]; then + echo "Run this from within the homelab directory" + fi + + # Get Machine Name: + MACHINE_NAME=$(gum input --prompt="Machine Name: >") + MACHINE_IP=$(gum input --prompt="Machne IP: >") + + echo "Connecting to ${MACHINE_IP} and setting up as ${MACHINE_NAME}" + # + # Check if its ISO (check hostname == nixos) + # Generate Host Public / Private Key Pair + install -d -m755 "${tmp_dir}/etc/ssh" + KEY_PATH="${tmp_dir}/etc/ssh/ssh_host_ed25519_key" + ssh-keygen -t ed25519 -C "yadunut@${MACHINE_NAME}" -f "${KEY_PATH}" -N "" + + + echo "Created SSH Keys: $(cat "${KEY_PATH}".pub)" + + chmod 600 "${KEY_PATH}" + + # Append public key to the secrets file and rekey agenix + pushd "./nixos/secrets" + LINE=" ${MACHINE_NAME} = \"$(cat "${KEY_PATH}".pub)\";" + echo "appending to file ${PWD}./keys.nix" + sed -i -e "\$i${LINE}" "./keys.nix" + agenix --rekey + popd + echo "${tmp_dir}" + echo "Run the command: nix run github:nix-community/nixos-anywhere -- --flake ".#${MACHINE_NAME}" --extra-files "${tmp_dir}" --print-build-logs root@${MACHINE_IP}" + read -n 1 + # Deploy the systems! + # nix run github:nix-community/nixos-anywhere -- --flake ".#${MACHINE_NAME}" --extra-files "${tmp_dir}" --print-build-logs yadunut@${MACHINE_IP} +} + +main "$@" diff --git a/nixos/secrets/keys.nix b/nixos/secrets/keys.nix new file mode 100644 index 0000000..a7e0214 --- /dev/null +++ b/nixos/secrets/keys.nix @@ -0,0 +1,4 @@ +{ +yadunut = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJXOpmWsAnl2RtOuJJMRUx+iJTwf2RWJ1iS3FqXJFzFG"; +yadunut-mbp = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOlXV+TevruoYChk2XbqG5+yqEklRJvOx7YdTGFfXY/f yadunut@yadunut-mbp"; +} # DO NOT ADD ANY NEW LINES AFTER THIS. IT WILL BREAK THE ".#setup-vm" flake diff --git a/nixos/secrets/secrets.nix b/nixos/secrets/secrets.nix new file mode 100644 index 0000000..69d3eec --- /dev/null +++ b/nixos/secrets/secrets.nix @@ -0,0 +1,6 @@ +let + keys = import ./keys.nix; +in +{ + "tailscale.age".publicKeys = builtins.attrValues keys; +} diff --git a/nixos/secrets/tailscale.age b/nixos/secrets/tailscale.age new file mode 100644 index 0000000..9166306 --- /dev/null +++ b/nixos/secrets/tailscale.age @@ -0,0 +1,8 @@ +age-encryption.org/v1 +-> ssh-ed25519 Gc/MTQ eEnmvEpsfgPpmcu+GRYoVHUgfHsA2D0B3jwsK8lGk1o +RsTBrqVJN5xFib4jaXVsx7kY0LIvOaAwqAutPMIxwuY +-> ssh-ed25519 0ckKSg 3yTh4DWOEnNwdEIeQ6usGCZovw/MLKUp5DveBGBFcCg +aTGN26qwcUvD67cypoDAuNhD1E07Qtq/H0Nz2als0RM +--- /kBG7hO54VFMXz5z4WwI3gwgeYA0+pAXauxIKoK9Mb4 +01v1PM-"[Lz=1 |+[l? T&p/7L# + < \ No newline at end of file diff --git a/nixos/server/configuration.nix b/nixos/server/configuration.nix new file mode 100644 index 0000000..c244d31 --- /dev/null +++ b/nixos/server/configuration.nix @@ -0,0 +1,32 @@ +{ config, meta, pkgs, ... }: +{ + imports = [../common/users.nix]; + nix = { + settings.experimental-features = ["nix-command" "flakes"]; + }; + + networking.hostName = meta.hostname; + + age.secrets.tailscale.file = ../secrets/tailscale.age; + + services.tailscale = { + enable = true; + authKeyFile = config.age.secrets.tailscale.path; + extraUpFlags = [ "--login-server" "http://ts.yadunut.com:444" ]; + }; + + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + + services.openssh.enable = true; + services.qemuGuest.enable = true; + + environment.systemPackages = with pkgs; [ + git + neovim + wget + k3s + ]; + + system.stateVersion = "24.11"; +} diff --git a/nixos/server/disko-config.nix b/nixos/server/disko-config.nix new file mode 100644 index 0000000..0b8e693 --- /dev/null +++ b/nixos/server/disko-config.nix @@ -0,0 +1,33 @@ +{ + disko.devices = { + disk = { + main = { + type = "disk"; + device = "/dev/sda"; + content = { + type = "gpt"; + partitions = { + ESP = { + type = "EF00"; + size = "500M"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + }; + }; + root = { + size = "100%"; + content = { + type = "filesystem"; + format = "ext4"; + mountpoint = "/"; + }; + }; + }; + + }; + }; + }; + }; +} diff --git a/nixos/server/hardware-configuration.nix b/nixos/server/hardware-configuration.nix new file mode 100644 index 0000000..505c60d --- /dev/null +++ b/nixos/server/hardware-configuration.nix @@ -0,0 +1,23 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/profiles/qemu-guest.nix") ]; + + boot.initrd.availableKernelModules = [ "uhci_hcd" "ehci_pci" "ahci" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.enp6s18.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; +}