greenhouse

kore

my public infrastructure monorepo

git clone [email protected]:kore.git

kore / nixos / features / global.nix304 lines · 7880B · raw

1{ inputs, outputs, config, lib, pkgs, utils, modulesPath, ... }:
2
3let
4  impermanence = config.kore.impermanence.enable;
5  rollback = impermanence && config ? disko && config.disko.devices.disk ? main;
6  wsl = config ? wsl && config.wsl.enable;
7
8  rootDevice = config.fileSystems."/".device;
9  rootUnit = "${utils.escapeSystemdPath rootDevice}.device";
10in {
11  imports = [
12    inputs.impermanence.nixosModules.impermanence
13
14    ( modulesPath + "/profiles/minimal.nix" )
15  ];
16
17  programs.bash.promptInit = ''
18    __prompt() {
19      local status=$?
20      case "$TERM" in
21        foot*|xterm*|tmux*|screen*)
22          printf '\e]0;%s@%s %s\a' "$USER" "''${HOSTNAME%%.*}" "''${PWD/#$HOME/\~}" ;;
23      esac
24
25      local arrow='\[\e[32m\]->\[\e[0m\]'
26      [ "$status" -ne 0 ] && arrow='\[\e[31m\]->\[\e[0m\]'
27
28      local pre=""
29      [ -n "''${SSH_CONNECTION:-}" ] && pre='\[\e[37m\]\h\[\e[0m\] '
30      [ "$EUID" -eq 0 ] && pre="\[\e[31m\]root\[\e[0m\] $pre"
31
32      PS1="$pre\[\e[37m\]\W\[\e[0m\] $arrow "
33    }
34    PROMPT_COMMAND=__prompt
35  '';
36
37  i18n = {
38    defaultLocale = "en_US.UTF-8";
39    supportedLocales = [ "en_US.UTF-8/UTF-8" ];
40  };
41  time.timeZone = lib.mkDefault "UTC";
42
43  nix = {
44    package = pkgs.nixVersions.latest;
45
46    gc = {
47      automatic = true;
48      dates = "daily";
49      options = "--delete-older-than 7d";
50    };
51
52    settings = {
53      keep-outputs = false;
54      keep-derivations = false;
55      auto-optimise-store = true;
56
57      trusted-users = [ "root" "@wheel" ];
58      experimental-features = [ "nix-command" "flakes" ];
59    };
60
61    registry.nixpkgs.to = {
62      type = "github";
63      owner = "NixOS";
64      repo = "nixpkgs";
65      inherit (inputs.nixpkgs) rev narHash;
66    };
67    nixPath = [ "nixpkgs=flake:nixpkgs" ];
68  };
69
70  nixpkgs = {
71    overlays = builtins.attrValues outputs.overlays;
72
73    flake = {
74      setFlakeRegistry = false;
75      setNixPath = false;
76    };
77
78    config = {
79      allowUnfree = lib.mkForce false;
80      allowBroken = lib.mkForce false;
81    };
82  };
83
84  system.tools = {
85    nixos-build-vms.enable = false;
86    nixos-enter.enable = false;
87    nixos-generate-config.enable = false;
88    nixos-install.enable = false;
89    nixos-option.enable = false;
90  };
91
92  networking = {
93    domain = "lostduk.com";
94
95    useDHCP = lib.mkDefault true;
96    enableIPv6 = lib.mkForce false;
97
98    firewall = {
99      enable = lib.mkForce true;
100      allowPing = lib.mkForce false;
101      allowedTCPPorts = [];
102      allowedUDPPorts = [];
103    };
104  };
105
106  networking.dhcpcd.extraConfig = lib.mkIf (!wsl) "nohook resolv.conf";
107
108  services = {
109    pcscd.enable = true;
110
111    resolved = lib.mkIf (!wsl) {
112      enable = true;
113
114      settings.Resolve = {
115        DNS = [
116          "194.242.2.2#dns.mullvad.net"
117          "9.9.9.9#dns.quad9.net"
118          "149.112.112.112#dns.quad9.net"
119        ];
120        FallbackDNS = [];
121        Domains = [ "~." ];
122        DNSOverTLS = true;
123        DNSSEC = false;
124      };
125    };
126
127    openssh = {
128      enable = lib.mkDefault true;
129      settings = {
130        PermitRootLogin = "no";
131        PasswordAuthentication = false;
132        KbdInteractiveAuthentication = false;
133      };
134      hostKeys = [{
135        path = "${lib.optionalString impermanence "/persist"}/etc/ssh/ssh_host_ed25519_key";
136        type = "ed25519";
137      }];
138    };
139  };
140
141  security = {
142    protectKernelImage = true;
143
144    audit = {
145      enable = true;
146      rules = [ "-a exit,always -F arch=b64 -S execve" ];
147    };
148
149    sudo = {
150      execWheelOnly = true;
151      wheelNeedsPassword = lib.mkForce true;
152    };
153
154    auditd.enable = true;
155    pam.sshAgentAuth.enable = true;
156  };
157
158  users = {
159    mutableUsers = lib.mkForce false;
160
161    users.root.hashedPassword = lib.mkForce "!";
162  };
163
164  boot = {
165    kernelParams = [
166      "slab_nomerge"
167      "init_on_alloc=1"
168      "init_on_free=1"
169      "page_alloc.shuffle=1"
170      "randomize_kstack_offset=on"
171      "vsyscall=none"
172      "debugfs=off"
173    ];
174
175    kernel.sysctl = {
176      "kernel.kptr_restrict" = 2;
177      "kernel.dmesg_restrict" = 1;
178      "kernel.printk" = "3 3 3 3";
179      "kernel.unprivileged_bpf_disabled" = 1;
180      "net.core.bpf_jit_harden" = 2;
181      "kernel.yama.ptrace_scope" = 1;
182      "kernel.sysrq" = 0;
183      "kernel.perf_event_paranoid" = 3;
184      "dev.tty.ldisc_autoload" = 0;
185      "vm.unprivileged_userfaultfd" = 0;
186      "fs.suid_dumpable" = 0;
187      "fs.protected_fifos" = 2;
188      "fs.protected_regular" = 2;
189      "fs.protected_symlinks" = 1;
190      "fs.protected_hardlinks" = 1;
191
192      "net.ipv4.tcp_syncookies" = 1;
193      "net.ipv4.tcp_rfc1337" = 1;
194      "net.ipv4.conf.all.rp_filter" = 1;
195      "net.ipv4.conf.default.rp_filter" = 1;
196      "net.ipv4.conf.all.accept_redirects" = 0;
197      "net.ipv4.conf.default.accept_redirects" = 0;
198      "net.ipv4.conf.all.secure_redirects" = 0;
199      "net.ipv4.conf.default.secure_redirects" = 0;
200      "net.ipv4.conf.all.send_redirects" = 0;
201      "net.ipv4.conf.default.send_redirects" = 0;
202      "net.ipv4.conf.all.accept_source_route" = 0;
203      "net.ipv4.conf.default.accept_source_route" = 0;
204      "net.ipv4.icmp_echo_ignore_broadcasts" = 1;
205    };
206
207    blacklistedKernelModules = [
208      "dccp" "sctp" "rds" "tipc" "n-hdlc" "ax25" "netrom" "x25" "rose"
209      "decnet" "econet" "af_802154" "ipx" "appletalk" "psnap" "p8023"
210      "p8022" "can" "atm"
211      "cramfs" "freevxfs" "jffs2" "hfs" "hfsplus"
212      "firewire-core" "thunderbolt" "vivid"
213    ];
214  };
215
216  systemd.coredump.settings.Coredump = {
217    Storage = "none";
218    ProcessSizeMax = 0;
219  };
220
221  environment = {
222    defaultPackages = lib.mkForce [];
223
224    etc = lib.mkIf (!config.services.openssh.enable) (lib.mapAttrs' (name: user:
225      lib.nameValuePair "ssh/authorized_keys.d/${name}" {
226        mode = "0444";
227        text = lib.concatLines user.openssh.authorizedKeys.keys;
228      }) (lib.filterAttrs (_: user: user.openssh.authorizedKeys.keys != []) config.users.users));
229
230    persistence."/persist" = {
231      enable = impermanence;
232      hideMounts = false;
233
234      directories = [
235        "/srv"
236        "/var/log"
237        "/var/lib/nixos"
238        "/var/lib/systemd"
239      ];
240    };
241  };
242
243  programs.nano.enable = false;
244
245  fileSystems = lib.mkIf impermanence {
246    "/persist".neededForBoot = true;
247  };
248
249  system.activationScripts.persistent-dirs = lib.mkIf impermanence {
250    deps = [ "users" ];
251    text =
252      let
253        mkHomePersist = user: lib.optionalString user.createHome ''
254          mkdir -p /persist${user.home}
255          chown ${user.name}:${user.group} /persist${user.home}
256          chmod ${user.homeMode} /persist${user.home}
257        '';
258      in
259        lib.concatLines (map mkHomePersist (lib.attrValues config.users.users));
260  };
261
262  assertions = [{
263    assertion = rollback -> config.boot.initrd.systemd.enable;
264    message = "kore: root rollback needs boot.initrd.systemd.enable";
265  }];
266
267  boot.initrd = lib.mkIf rollback {
268    supportedFilesystems = [ "btrfs" ];
269
270    systemd.services.wipe-root = {
271      wantedBy = [ "initrd.target" ];
272      requires = [ rootUnit ];
273      after = [ rootUnit ];
274      before = [ "sysroot.mount" ];
275      unitConfig.DefaultDependencies = "no";
276      serviceConfig = {
277        Type = "oneshot";
278        RemainAfterExit = true;
279      };
280      script = ''
281        mkdir -p /tmp
282        MNTPOINT=$(mktemp -d)
283        (
284          mount ${rootDevice} "$MNTPOINT"
285          trap 'umount "$MNTPOINT"' EXIT
286
287          if [[ -e $MNTPOINT/@ ]]; then
288            echo "Backing up root..."
289            mkdir -p $MNTPOINT/old_roots
290            mv "$MNTPOINT/@" "$MNTPOINT/old_roots/@_$(date "+%Y-%m-%-d_%H:%M:%S")"
291          fi
292
293          echo "Deleting 7+ days old roots..."
294          find "$MNTPOINT/old_roots" -mindepth 1 -maxdepth 1 \
295            -mtime +7 \
296            -exec btrfs sub del -R {} +
297
298          echo "Creating new root..."
299          btrfs sub cre "$MNTPOINT/@"
300        )
301      '';
302    };
303  };
304}