From 5554b5191e34f2d0a404ecce0cec0fbbff6ead9a Mon Sep 17 00:00:00 2001 From: Akshay Mankar Date: Fri, 27 Oct 2023 23:06:55 +0200 Subject: [PATCH] Add NixOS config for nachtigall --- flake.lock | 84 ++++++++++++++-- flake.nix | 102 +++++++++----------- hosts/nachtigall/default.nix | 95 ++++++++++++++++++ hosts/nachtigall/hardware-configuration.nix | 48 +++++++++ lib/compat/default.nix | 21 ++++ lib/compat/nixos/default.nix | 9 ++ lib/default.nix | 20 ++++ lib/deploy.nix | 62 ++++++++++++ lib/unlock-zfs-on-boot.nix | 29 ++++++ public-keys/admins.nix | 9 ++ public-keys/default.nix | 8 ++ 11 files changed, 425 insertions(+), 62 deletions(-) create mode 100644 hosts/nachtigall/default.nix create mode 100644 hosts/nachtigall/hardware-configuration.nix create mode 100644 lib/compat/default.nix create mode 100644 lib/compat/nixos/default.nix create mode 100644 lib/default.nix create mode 100644 lib/deploy.nix create mode 100644 lib/unlock-zfs-on-boot.nix create mode 100644 public-keys/admins.nix create mode 100644 public-keys/default.nix diff --git a/flake.lock b/flake.lock index bae7c5c..57f82db 100644 --- a/flake.lock +++ b/flake.lock @@ -32,6 +32,42 @@ "type": "github" } }, + "deploy-rs": { + "inputs": { + "flake-compat": "flake-compat", + "nixpkgs": "nixpkgs", + "utils": "utils" + }, + "locked": { + "lastModified": 1695052866, + "narHash": "sha256-agn7F9Oww4oU6nPiw+YiYI9Xb4vOOE73w8PAoBRP4AA=", + "owner": "serokell", + "repo": "deploy-rs", + "rev": "e3f41832680801d0ee9e2ed33eb63af398b090e9", + "type": "github" + }, + "original": { + "owner": "serokell", + "repo": "deploy-rs", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1668681692, + "narHash": "sha256-Ht91NGdewz8IQLtWZ9LCeNXMSXHUss+9COoqu6JLmXU=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "009399224d5e398d03b22badca40a37ac85412a1", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "flake-parts": { "inputs": { "nixpkgs-lib": "nixpkgs-lib" @@ -123,16 +159,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1690548937, - "narHash": "sha256-x3ZOPGLvtC0/+iFAg9Kvqm/8hTAIkGjc634SqtgaXTA=", - "owner": "nixos", + "lastModified": 1671417167, + "narHash": "sha256-JkHam6WQOwZN1t2C2sbp1TqMv3TVRjzrdoejqfefwrM=", + "owner": "NixOS", "repo": "nixpkgs", - "rev": "2a9d660ff0f7ffde9d73be328ee6e6f10ef66b28", + "rev": "bb31220cca6d044baa6dc2715b07497a2a7c4bc7", "type": "github" }, "original": { - "owner": "nixos", - "ref": "nixos-unstable", + "owner": "NixOS", + "ref": "nixpkgs-unstable", "repo": "nixpkgs", "type": "github" } @@ -156,6 +192,22 @@ } }, "nixpkgs_2": { + "locked": { + "lastModified": 1690548937, + "narHash": "sha256-x3ZOPGLvtC0/+iFAg9Kvqm/8hTAIkGjc634SqtgaXTA=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "2a9d660ff0f7ffde9d73be328ee6e6f10ef66b28", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { "locked": { "lastModified": 1636823747, "narHash": "sha256-oWo1nElRAOZqEf90Yek2ixdHyjD+gqtS/pAgwaQ9UhQ=", @@ -172,11 +224,12 @@ }, "root": { "inputs": { + "deploy-rs": "deploy-rs", "flake-parts": "flake-parts", "home-manager": "home-manager", "nix-darwin": "nix-darwin", "nixos-flake": "nixos-flake", - "nixpkgs": "nixpkgs", + "nixpkgs": "nixpkgs_2", "terranix": "terranix" } }, @@ -185,7 +238,7 @@ "bats-assert": "bats-assert", "bats-support": "bats-support", "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs_2", + "nixpkgs": "nixpkgs_3", "terranix-examples": "terranix-examples" }, "locked": { @@ -216,6 +269,21 @@ "repo": "terranix-examples", "type": "github" } + }, + "utils": { + "locked": { + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 76f8c9e..612fefe 100644 --- a/flake.nix +++ b/flake.nix @@ -11,6 +11,8 @@ nixos-flake.url = "github:srid/nixos-flake"; terranix.url = "github:terranix/terranix"; + + deploy-rs.url = "github:serokell/deploy-rs"; }; outputs = inputs@{ self, terranix, ... }: @@ -19,78 +21,62 @@ imports = [ inputs.nixos-flake.flakeModule - ./terraform.nix + # ./terraform.nix + ./public-keys + ./lib ]; perSystem = { config, ... }: { }; flake = let - # TODO: Change username - myUserName = "john"; + username = "barkeeper"; system = "x86_64-linux"; - in - { - # Configurations for Linux (NixOS) machines + in { nixosConfigurations = { - # TODO: Change hostname from "example1" to something else. - example1 = self.nixos-flake.lib.mkLinuxSystem "x86_64-linux" { + nachtigall = self.nixos-flake.lib.mkLinuxSystem system { imports = [ - self.nixosModules.common # See below for "nixosModules"! - self.nixosModules.linux - ./hosts/example1/default.nix + self.nixosModules.common + ./hosts/nachtigall + self.pub-solar.lib.linux.unlockZFSOnBoot self.nixosModules.home-manager + self.nixosModules.linux { - home-manager.users.${myUserName} = { + home-manager.users.${username} = { imports = [ - self.homeModules.common # See below for "homeModules"! - self.homeModules.linux + self.homeModules.common ]; - home.stateVersion = "22.11"; + home.stateVersion = "23.05"; }; } ]; }; }; - # Configurations for macOS machines - darwinConfigurations = { - # TODO: Change hostname from "example1" to something else. - example1 = self.nixos-flake.lib.mkMacosSystem "aarch64-darwin" { - imports = [ - self.nixosModules.common # See below for "nixosModules"! - self.nixosModules.darwin - ./hosts/example1/default.nix - self.darwinModules.home-manager - { - home-manager.users.${myUserName} = { - imports = [ - self.homeModules.common # See below for "homeModules"! - self.homeModules.darwin - ]; - home.stateVersion = "22.11"; - }; - } - ]; - }; - }; - - # All nixos/nix-darwin configurations are kept here. nixosModules = { # Common nixos/nix-darwin configuration shared between Linux and macOS. common = { pkgs, ... }: { - environment.systemPackages = with pkgs; [ - hello - ]; + virtualisation.docker.enable = true; + services.openssh.enable = true; + services.openssh.settings.PermitRootLogin = "prohibit-password"; }; + # NixOS specific configuration linux = { pkgs, ... }: { - users.users.${myUserName}.isNormalUser = true; - services.netdata.enable = true; - }; - # nix-darwin specific configuration - darwin = { pkgs, ... }: { - security.pam.enableSudoTouchIdAuth = true; + users.users.${username} = { + name = username; + group = username; + extraGroups = ["wheel"]; + isNormalUser = true; + openssh.authorizedKeys.keys = self.publicKeys.allAdmins; + }; + users.groups.${username} = {}; + + security.sudo.wheelNeedsPassword = false; + nix.settings.trusted-users = [ "root" username ]; + + # TODO: Remove when we stop locking ourselves out. + users.users.root.openssh.authorizedKeys.keys = self.publicKeys.allAdmins; }; }; @@ -101,14 +87,22 @@ programs.git.enable = true; programs.starship.enable = true; programs.bash.enable = true; + programs.neovim = { + enable = true; + vimAlias = true; + viAlias = true; + defaultEditor = true; + # configure = { + # packages.myVimPackages = with pkgs.vimPlugins; { + # start = [vim-nix vim-surrund rainbow]; + # }; + # }; + }; }; - # home-manager config specific to NixOS - linux = { - xsession.enable = true; - }; - # home-manager config specifi to Darwin - darwin = { - targets.darwin.search = "Bing"; + }; + deploy.nodes = self.pub-solar.lib.deploy.mkDeployNodes self.nixosConfigurations { + nachtigall = { + sshUser = username; }; }; }; diff --git a/hosts/nachtigall/default.nix b/hosts/nachtigall/default.nix new file mode 100644 index 0000000..09fd08f --- /dev/null +++ b/hosts/nachtigall/default.nix @@ -0,0 +1,95 @@ +{ config, pkgs, ... }: + +{ + imports = + [ # Include the results of the hardware scan. + ./hardware-configuration.nix + ]; + + # Use GRUB2 as the boot loader. + # We don't use systemd-boot because Hetzner uses BIOS legacy boot. + boot.loader.systemd-boot.enable = false; + boot.loader.grub = { + enable = true; + efiSupport = false; + mirroredBoots = [ + { + devices = [ + "/dev/disk/by-id/nvme-SAMSUNG_MZVL21T0HCLR-00B00_S676NF0R517371" + ]; + path = "/boot1"; + } + { + devices = [ + "/dev/disk/by-id/nvme-KXG60ZNV1T02_TOSHIBA_Z9NF704ZF9ZL" + ]; + path = "/boot2"; + } + ]; + copyKernels = true; + }; + boot.supportedFilesystems = [ "zfs" ]; + + boot.kernelParams = [ + "boot.shell_on_fail=1" + "ip=138.201.80.102::138.201.80.65:255.255.255.192:nachtigall::off" + ]; + + boot.initrd.availableKernelModules = [ "igb" ]; + + networking.hostName = "nachtigall"; + networking.domain = "pub.solar"; + networking.hostId = "00000001"; + + # enable flakes by default + nix = { + package = pkgs.nixFlakes; + extraOptions = '' + experimental-features = nix-command flakes + ''; + }; + + # Set your time zone. + time.timeZone = "Etc/UTC"; + + environment = { + enableDebugInfo = true; + # just a couple of packages to make our lives easier + systemPackages = with pkgs; [ vim ]; + }; + + # Network (Hetzner uses static IP assignments, and we don't use DHCP here) + networking.useDHCP = false; + networking.interfaces."enp35s0".ipv4.addresses = [ + { + address = "138.201.80.102"; + prefixLength = 26; + } + ]; + networking.interfaces."enp35s0".ipv6.addresses = [ + { + address = "2a01:4f8:172:1c25::1"; + prefixLength = 64; + } + ]; + networking.defaultGateway = "138.201.80.65"; + networking.defaultGateway6 = { address = "fe80::1"; interface = "enp35s0"; }; + networking.nameservers = [ + # cloudflare + "1.1.1.1" + "2606:4700:4700::1111" + "2606:4700:4700::1001" + # google + "8.8.8.8" + "2001:4860:4860::8888" + "2001:4860:4860::8844" + ]; + + users.users.root.initialHashedPassword = "$y$j9T$bIN6GjQkmPMllOcQsq52K0$q0Z5B5.KW/uxXK9fItB8H6HO79RYAcI/ZZdB0Djke32"; + + # This value determines the NixOS release with which your system is to be + # compatible, in order to avoid breaking some software such as database + # servers. You should change this only after NixOS release notes say you + # should. + system.stateVersion = "23.05"; # Did you read the comment? +} diff --git a/hosts/nachtigall/hardware-configuration.nix b/hosts/nachtigall/hardware-configuration.nix new file mode 100644 index 0000000..f06e4eb --- /dev/null +++ b/hosts/nachtigall/hardware-configuration.nix @@ -0,0 +1,48 @@ +# 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 + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "ahci" "nvme" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-amd" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "root_pool/root"; + fsType = "zfs"; + }; + + fileSystems."/var/lib/postgresql" = + { device = "root_pool/data/postgresql"; + fsType = "zfs"; + }; + + fileSystems."/boot1" = + { device = "/dev/disk/by-uuid/5493-EFF5"; + fsType = "vfat"; + }; + + fileSystems."/boot2" = + { device = "/dev/disk/by-uuid/5494-BA1E"; + fsType = "vfat"; + }; + + swapDevices = [ ]; + + # 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.eth0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + powerManagement.cpuFreqGovernor = lib.mkDefault "ondemand"; + hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/lib/compat/default.nix b/lib/compat/default.nix new file mode 100644 index 0000000..fc1bc0c --- /dev/null +++ b/lib/compat/default.nix @@ -0,0 +1,21 @@ +let + lock = builtins.fromJSON (builtins.readFile builtins.path { + path = ../../flake.lock; + name = "lockPath"; + }); + flake = + import + ( + fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz"; + sha256 = lock.nodes.flake-compat.locked.narHash; + } + ) + { + src = builtins.path { + path = ../../.; + name = "projectRoot"; + }; + }; +in + flake diff --git a/lib/compat/nixos/default.nix b/lib/compat/nixos/default.nix new file mode 100644 index 0000000..617c6a9 --- /dev/null +++ b/lib/compat/nixos/default.nix @@ -0,0 +1,9 @@ +{...}: let + inherit (default.inputs.nixos) lib; + + host = configs.${hostname} or configs.PubSolarOS; + configs = default.nixosConfigurations; + default = (import ../.).defaultNix; + hostname = lib.fileContents /etc/hostname; +in + host diff --git a/lib/default.nix b/lib/default.nix new file mode 100644 index 0000000..20566ff --- /dev/null +++ b/lib/default.nix @@ -0,0 +1,20 @@ +{ self, lib, inputs, ... }: { + # Configuration common to all Linux systems + flake = { + pub-solar.lib = let + callLibs = file: import file {inherit lib;}; + in rec { + ## Define your own library functions here! + #id = x: x; + ## Or in files, containing functions that take {lib} + #foo = callLibs ./foo.nix; + ## In configs, they can be used under "lib.our" + + deploy = import ./deploy.nix { inherit inputs lib; }; + + linux = { + unlockZFSOnBoot = import ./unlock-zfs-on-boot.nix {publicKeys = self.publicKeys.allAdmins;}; + }; + }; + }; +} diff --git a/lib/deploy.nix b/lib/deploy.nix new file mode 100644 index 0000000..5e9f641 --- /dev/null +++ b/lib/deploy.nix @@ -0,0 +1,62 @@ +/* + * The contents of this file are adapted from digga + * https://github.com/divnix/digga + * + * Licensed under the MIT license + */ + +{ lib, inputs }: let + getFqdn = c: let + net = c.config.networking; + fqdn = + if (net ? domain) && (net.domain != null) + then "${net.hostName}.${net.domain}" + else net.hostName; + in + fqdn; +in { + mkDeployNodes = systemConfigurations: extraConfig: + /* + * + Synopsis: mkNodes _systemConfigurations_ _extraConfig_ + + Generate the `nodes` attribute expected by deploy-rs + where _systemConfigurations_ are `nodes`. + + _systemConfigurations_ should take the form of a flake's + _nixosConfigurations_. Note that deploy-rs does not currently support + deploying to darwin hosts. + + _extraConfig_, if specified, will be merged into each of the + nodes' configurations. + + Example _systemConfigurations_ input: + + ``` + { + hostname-1 = { + fastConnection = true; + sshOpts = [ "-p" "25" ]; + }; + hostname-2 = { + sshOpts = [ "-p" "19999" ]; + sshUser = "root"; + }; + } + ``` + * + */ + lib.recursiveUpdate + (lib.mapAttrs + ( + _: c: { + hostname = getFqdn c; + profiles.system = { + user = "root"; + path = inputs.deploy-rs.lib.${c.pkgs.stdenv.hostPlatform.system}.activate.nixos c; + }; + } + ) + systemConfigurations) + extraConfig; +} diff --git a/lib/unlock-zfs-on-boot.nix b/lib/unlock-zfs-on-boot.nix new file mode 100644 index 0000000..529b272 --- /dev/null +++ b/lib/unlock-zfs-on-boot.nix @@ -0,0 +1,29 @@ +{publicKeys}: { + # From https://nixos.wiki/wiki/ZFS#Unlock_encrypted_zfs_via_ssh_on_boot + boot.initrd.network = { + enable = true; + ssh = { + enable = true; + # To prevent ssh clients from freaking out because a different host key is used, + # a different port for ssh is useful (assuming the same host has also a regular sshd running) + port = 2222; + + # Please create this manually the first time. + hostKeys = [ "/etc/secrets/initrd/ssh_host_ed25519_key" ]; + authorizedKeys = publicKeys; + }; + # this will automatically load the zfs password prompt on login + # and kill the other prompt so boot can continue + postCommands = '' + cat < /root/.profile + if pgrep -x "zfs" > /dev/null + then + zfs load-key -a + killall zfs + else + echo "zfs not running -- maybe the pool is taking some time to load for some unforseen reason." + fi + EOF + ''; + }; +} diff --git a/public-keys/admins.nix b/public-keys/admins.nix new file mode 100644 index 0000000..7e742ed --- /dev/null +++ b/public-keys/admins.nix @@ -0,0 +1,9 @@ +{ + axeman-1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMNeQYLFauAbzDyIbKC86NUh9yZfiyBm/BtIdkcpZnSU axeman@tuxnix"; + b12f-1 = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHx4A8rLYmFgTOp1fDGbbONN8SOT0l5wWrUSYFUcVzMPTyfdT23ZVIdVD5yZCySgi/7PSh5mVmyLIZVIXlNrZJg= @b12f Yubi Main"; + b12f-2 = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEST9eyAY3nzGYNnqDYfWHu+89LZsOjyKHMqCFvtP7vrgB7F7JbbECjdjAXEOfPDSCVwtMMpq8JJXeRMjpsD0rw= @b12f Yubi Backup"; + hensoko-1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEbaQdxp7Flz6ttELe63rn+Nt9g43qJOLih6VCMP4gPb"; + hensoko-2 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAqkqMYgncrnczcW/0PY+Z+FmNXXpgw6D9JWTTwiainy"; + teutat3s-1 = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFro/k4Mgqyh8yV/7Zwjc0dv60ZM7bROBU9JNd99P/4co6fxPt1pJiU/pEz2Dax/HODxgcO+jFZfvPEuLMCeAl0= YubiKey #10593996 PIV Slot 9a"; + +} diff --git a/public-keys/default.nix b/public-keys/default.nix new file mode 100644 index 0000000..a5fdaa3 --- /dev/null +++ b/public-keys/default.nix @@ -0,0 +1,8 @@ +{lib, ...}: +{ + flake = { + publicKeys = { + allAdmins = lib.attrsets.attrValues (import ./admins.nix); + }; + }; +}