From 6fb15c9fe0c736778fdf82e40a3ff10c1992f925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leon=20Schwarz=C3=A4ugl?= Date: Tue, 22 Jul 2025 21:27:13 +0200 Subject: [PATCH] feat: improve emergency access --- SwarselSystems.org | 125 +++++++++++++++++-------- modules/nixos/common/boot.nix | 25 +++++ modules/nixos/common/globals.nix | 6 ++ modules/nixos/common/users.nix | 22 +++-- nix/globals.nix | 1 + profiles/nixos/localserver/default.nix | 1 + profiles/nixos/minimal/default.nix | 1 + profiles/nixos/moonside/default.nix | 1 + profiles/nixos/personal/default.nix | 1 + profiles/nixos/reduced/default.nix | 1 + profiles/nixos/syncserver/default.nix | 1 + secrets/repo/globals.nix.enc | 6 +- 12 files changed, 142 insertions(+), 49 deletions(-) create mode 100644 modules/nixos/common/boot.nix diff --git a/SwarselSystems.org b/SwarselSystems.org index de8a276..282c040 100644 --- a/SwarselSystems.org +++ b/SwarselSystems.org @@ -782,6 +782,7 @@ Lastly, in order make this actually available to my configurations, i use the =i domains services user + root ; }; }; @@ -3740,53 +3741,59 @@ in inherit (lib) mkOption types - ; + ; in { - options = { - globals = mkOption { - default = { }; - type = types.submodule { - options = { - user = { - name = mkOption { - type = types.str; - }; - work = mkOption { - type = types.str; - }; + options = { + globals = mkOption { + default = { }; + type = types.submodule { + options = { + root = { + hashedPassword = mkOption { + type = types.str; }; + }; + + user = { + name = mkOption { + type = types.str; + }; + work = mkOption { + type = types.str; + }; + }; - services = mkOption { - type = types.attrsOf ( - types.submodule { - options = { - domain = mkOption { - type = types.str; - }; + services = mkOption { + type = types.attrsOf ( + types.submodule { + options = { + domain = mkOption { + type = types.str; }; - } - ); - }; + }; + } + ); + }; - domains = { - main = mkOption { - type = types.str; - }; + domains = { + main = mkOption { + type = types.str; }; }; }; }; - - _globalsDefs = mkOption { - type = types.unspecified; - default = options.globals.definitions; - readOnly = true; - internal = true; - }; }; - } + + _globalsDefs = mkOption { + type = types.unspecified; + default = options.globals.definitions; + readOnly = true; + internal = true; + }; + }; + } #+end_src **** Meta options (options only) @@ -4065,7 +4072,7 @@ In case of using a fully setup system, this makes also sure that no further user For that reason, make sure that =sops-nix= is properly working before finishing the minimal setup, otherwise we might lose user access. The bootstrapping script takes care of this. #+begin_src nix-ts :tangle modules/nixos/common/users.nix - { self, pkgs, config, lib, minimal, ... }: + { self, pkgs, config, lib, globals, minimal, ... }: let sopsFile = self + /secrets/general/secrets.yaml; in @@ -4076,13 +4083,19 @@ For that reason, make sure that =sops-nix= is properly working before finishing users = { mutableUsers = lib.mkIf (!minimal) false; - users."${config.swarselsystems.mainUser}" = { + users = { + root = { + inherit (globals.root) hashedPassword; + shell = pkgs.zsh; + }; + "${config.swarselsystems.mainUser}" = { isNormalUser = true; description = "Leon S"; password = lib.mkIf (minimal || config.swarselsystems.isPublic) "setup"; hashedPasswordFile = lib.mkIf (!minimal && !config.swarselsystems.isPublic) config.sops.secrets.main-user-hashed-pw.path; extraGroups = [ "wheel" ] ++ lib.optionals (!minimal) [ "networkmanager" "syncthing" "docker" "lp" "audio" "video" "vboxusers" "libvirtd" "scanner" ]; packages = with pkgs; [ ]; + }; }; }; }; @@ -4261,6 +4274,36 @@ This dynamically uses systemd boot or Lanzaboote depending on the minimal system } #+end_src +**** Boot + +#+begin_src nix-ts :tangle modules/nixos/common/boot.nix + { lib, pkgs, config, globals, ... }: + { + options.swarselmodules.boot = lib.mkEnableOption "boot config"; + config = lib.mkIf config.swarselmodules.boot { + boot = { + initrd.systemd = { + enable = true; + emergencyAccess = globals.root.hashedPassword; + users.root.shell = "${pkgs.bashInteractive}/bin/bash"; + storePaths = [ "${pkgs.bashInteractive}/bin/bash" ]; + extraBin = { + ip = "${pkgs.iproute2}/bin/ip"; + ping = "${pkgs.iputils}/bin/ping"; + cryptsetup = "${pkgs.cryptsetup}/bin/cryptsetup"; + }; + }; + kernelParams = [ "log_buf_len=16M" ]; + tmp.useTmpfs = true; + loader.timeout = lib.mkDefault 2; + }; + + console.earlySetup = true; + + }; + } +#+end_src + **** Impermanence :PROPERTIES: :CUSTOM_ID: h:e7668594-fa8b-4d36-a695-a58222478988 @@ -5730,7 +5773,7 @@ This allows me to use screen sharing on Wayland. The implementation is a bit cru } #+end_src -**** Podmam (distrobox) +**** Podman (distrobox) :PROPERTIES: :CUSTOM_ID: h:1bef3914-a258-4585-b232-e0fbe9e7a9b5 :END: @@ -16204,6 +16247,7 @@ Modules that need to be loaded on the NixOS level. Note that these will not be a lowBattery = lib.mkDefault true; lanzaboote = lib.mkDefault true; autologin = lib.mkDefault true; + boot = lib.mkDefault true; optional = { gaming = lib.mkDefault true; @@ -16279,6 +16323,7 @@ Modules that need to be loaded on the NixOS level. Note that these will not be a lowBattery = lib.mkDefault true; lanzaboote = lib.mkDefault true; autologin = lib.mkDefault true; + boot = lib.mkDefault true; server = { ssh = lib.mkDefault true; @@ -16320,6 +16365,7 @@ Modules that need to be loaded on the NixOS level. Note that these will not be a zsh = lib.mkDefault true; yubikey = lib.mkDefault true; autologin = lib.mkDefault true; + boot = lib.mkDefault true; server = { ssh = lib.mkDefault true; @@ -16583,6 +16629,7 @@ Modules that need to be loaded on the NixOS level. Note that these will not be a time = lib.mkDefault true; users = lib.mkDefault true; sops = lib.mkDefault true; + boot = lib.mkDefault true; server = { general = lib.mkDefault true; packages = lib.mkDefault true; @@ -16639,6 +16686,7 @@ Modules that need to be loaded on the NixOS level. Note that these will not be a time = lib.mkDefault true; users = lib.mkDefault true; sops = lib.mkDefault true; + boot = lib.mkDefault true; server = { general = lib.mkDefault true; packages = lib.mkDefault true; @@ -16672,6 +16720,7 @@ Modules that need to be loaded on the NixOS level. Note that these will not be a users = lib.mkDefault true; impermanence = lib.mkDefault true; sops = lib.mkDefault true; + boot = lib.mkDefault true; server = { general = lib.mkDefault true; packages = lib.mkDefault true; diff --git a/modules/nixos/common/boot.nix b/modules/nixos/common/boot.nix new file mode 100644 index 0000000..758f29c --- /dev/null +++ b/modules/nixos/common/boot.nix @@ -0,0 +1,25 @@ +{ lib, pkgs, config, globals, ... }: +{ + options.swarselmodules.boot = lib.mkEnableOption "boot config"; + config = lib.mkIf config.swarselmodules.boot { + boot = { + initrd.systemd = { + enable = true; + emergencyAccess = globals.root.hashedPassword; + users.root.shell = "${pkgs.bashInteractive}/bin/bash"; + storePaths = [ "${pkgs.bashInteractive}/bin/bash" ]; + extraBin = { + ip = "${pkgs.iproute2}/bin/ip"; + ping = "${pkgs.iputils}/bin/ping"; + cryptsetup = "${pkgs.cryptsetup}/bin/cryptsetup"; + }; + }; + kernelParams = [ "log_buf_len=16M" ]; + tmp.useTmpfs = true; + loader.timeout = lib.mkDefault 2; + }; + + console.earlySetup = true; + + }; +} diff --git a/modules/nixos/common/globals.nix b/modules/nixos/common/globals.nix index 74fcf6a..24e3793 100644 --- a/modules/nixos/common/globals.nix +++ b/modules/nixos/common/globals.nix @@ -11,6 +11,12 @@ in default = { }; type = types.submodule { options = { + root = { + hashedPassword = mkOption { + type = types.str; + }; + }; + user = { name = mkOption { type = types.str; diff --git a/modules/nixos/common/users.nix b/modules/nixos/common/users.nix index de19aa6..29d3afb 100644 --- a/modules/nixos/common/users.nix +++ b/modules/nixos/common/users.nix @@ -1,4 +1,4 @@ -{ self, pkgs, config, lib, minimal, ... }: +{ self, pkgs, config, lib, globals, minimal, ... }: let sopsFile = self + /secrets/general/secrets.yaml; in @@ -9,13 +9,19 @@ in users = { mutableUsers = lib.mkIf (!minimal) false; - users."${config.swarselsystems.mainUser}" = { - isNormalUser = true; - description = "Leon S"; - password = lib.mkIf (minimal || config.swarselsystems.isPublic) "setup"; - hashedPasswordFile = lib.mkIf (!minimal && !config.swarselsystems.isPublic) config.sops.secrets.main-user-hashed-pw.path; - extraGroups = [ "wheel" ] ++ lib.optionals (!minimal) [ "networkmanager" "syncthing" "docker" "lp" "audio" "video" "vboxusers" "libvirtd" "scanner" ]; - packages = with pkgs; [ ]; + users = { + root = { + inherit (globals.root) hashedPassword; + shell = pkgs.zsh; + }; + "${config.swarselsystems.mainUser}" = { + isNormalUser = true; + description = "Leon S"; + password = lib.mkIf (minimal || config.swarselsystems.isPublic) "setup"; + hashedPasswordFile = lib.mkIf (!minimal && !config.swarselsystems.isPublic) config.sops.secrets.main-user-hashed-pw.path; + extraGroups = [ "wheel" ] ++ lib.optionals (!minimal) [ "networkmanager" "syncthing" "docker" "lp" "audio" "video" "vboxusers" "libvirtd" "scanner" ]; + packages = with pkgs; [ ]; + }; }; }; }; diff --git a/nix/globals.nix b/nix/globals.nix index d1f0c77..77d5e01 100644 --- a/nix/globals.nix +++ b/nix/globals.nix @@ -55,6 +55,7 @@ domains services user + root ; }; }; diff --git a/profiles/nixos/localserver/default.nix b/profiles/nixos/localserver/default.nix index e3577e5..ada2738 100644 --- a/profiles/nixos/localserver/default.nix +++ b/profiles/nixos/localserver/default.nix @@ -10,6 +10,7 @@ time = lib.mkDefault true; users = lib.mkDefault true; sops = lib.mkDefault true; + boot = lib.mkDefault true; server = { general = lib.mkDefault true; packages = lib.mkDefault true; diff --git a/profiles/nixos/minimal/default.nix b/profiles/nixos/minimal/default.nix index d7afc1e..9929e27 100644 --- a/profiles/nixos/minimal/default.nix +++ b/profiles/nixos/minimal/default.nix @@ -16,6 +16,7 @@ zsh = lib.mkDefault true; yubikey = lib.mkDefault true; autologin = lib.mkDefault true; + boot = lib.mkDefault true; server = { ssh = lib.mkDefault true; diff --git a/profiles/nixos/moonside/default.nix b/profiles/nixos/moonside/default.nix index d365d4c..cf80ece 100644 --- a/profiles/nixos/moonside/default.nix +++ b/profiles/nixos/moonside/default.nix @@ -11,6 +11,7 @@ users = lib.mkDefault true; impermanence = lib.mkDefault true; sops = lib.mkDefault true; + boot = lib.mkDefault true; server = { general = lib.mkDefault true; packages = lib.mkDefault true; diff --git a/profiles/nixos/personal/default.nix b/profiles/nixos/personal/default.nix index 580f2af..c34af54 100644 --- a/profiles/nixos/personal/default.nix +++ b/profiles/nixos/personal/default.nix @@ -44,6 +44,7 @@ lowBattery = lib.mkDefault true; lanzaboote = lib.mkDefault true; autologin = lib.mkDefault true; + boot = lib.mkDefault true; optional = { gaming = lib.mkDefault true; diff --git a/profiles/nixos/reduced/default.nix b/profiles/nixos/reduced/default.nix index 0a64002..71bce91 100644 --- a/profiles/nixos/reduced/default.nix +++ b/profiles/nixos/reduced/default.nix @@ -44,6 +44,7 @@ lowBattery = lib.mkDefault true; lanzaboote = lib.mkDefault true; autologin = lib.mkDefault true; + boot = lib.mkDefault true; server = { ssh = lib.mkDefault true; diff --git a/profiles/nixos/syncserver/default.nix b/profiles/nixos/syncserver/default.nix index 7c28a4b..b511dd5 100644 --- a/profiles/nixos/syncserver/default.nix +++ b/profiles/nixos/syncserver/default.nix @@ -11,6 +11,7 @@ time = lib.mkDefault true; users = lib.mkDefault true; sops = lib.mkDefault true; + boot = lib.mkDefault true; server = { general = lib.mkDefault true; packages = lib.mkDefault true; diff --git a/secrets/repo/globals.nix.enc b/secrets/repo/globals.nix.enc index 00450be..64a35db 100644 --- a/secrets/repo/globals.nix.enc +++ b/secrets/repo/globals.nix.enc @@ -1,5 +1,5 @@ { - "data": "ENC[AES256_GCM,data:PW4DwwvVLuaUtuvJr/h+Zx+8V1i1D3hVlATFr5yI5nykn7T/ZLf7lJFYJGqms9DHExxiGmYNWCXkFrRqOnKpBajxUuuljaE0Yd4bxIga4hF5KC+nJS5BGT9tVOQfp/sopJvp7QjxLKBcZcZ9uya2+DhxJdhmtRUj5A04ze68PsQMl4zuU7Y=,iv:1rblF4XnYDHpwz0Sl6E/3Xd9ITP5KWC8Qm5Ghf+TaTI=,tag:JmxpswTJZO7y9D4hQEn1Gw==,type:str]", + "data": "ENC[AES256_GCM,data:8qexHpKJg6o1Fb9H50I3H25UOpNFs2sQl2hd3B2hdJRTjc96aVgTgI838Fnn7G6mFBpHqP0SFCU0/CP6SKqbhJ6SucrfpQN/RqZlSCxmuZi3sqv3voNd7/5JzY0D/5XUTfzHkeEA34HS0GcNLLY7m+QskfJdqGSMB5P++88xCNETqv+sRPVegm1ZGttj+tttesLkAcIU0556WiQhyIcpR4ZiO75NWRFerOmb4LxADR+bwBfesfGUfjflsqOSJll17N9SECSWE7o75Ojn+yde/EznK+zQlsCYvPp90d2xU6dpdRNtp9jrjvXvEVCmcwjIqIKXqurc2CU=,iv:xBYgbmjHwhbH+7WR5MLVysrChxr6rERo6WZuu07sUS0=,tag:vMoMu9mrrGRTA3oO2wsnWw==,type:str]", "sops": { "age": [ { @@ -27,8 +27,8 @@ "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBibGlMSU4vUEF5UlNVZzlr\nMTMyOFY2Zi8rZFdZT1JrelZEUUZkZHFvOFdzCjVPbVovaU9nZklJQWNZeDJZNm0r\nMXBIK2hsZEY0NElxTVVMWmN6WU1Ld28KLS0tIENaallkK05SMllia3prV25hZDR2\nZDBNU0dYYnJESG1JZGpvSGp1WW9UMVEKJgfdLp7BRXvyAekecNJiaBXmxSj1qNxx\nZeHceqEkfWV/PzX+RP4LHjXTQCLEOJijbKxDmxSsYq49hC9xjZASuw==\n-----END AGE ENCRYPTED FILE-----\n" } ], - "lastmodified": "2025-07-03T16:55:42Z", - "mac": "ENC[AES256_GCM,data:+k6CeK5XiwsJJtvqr/NnRQvERqsV46tQoDnY6L5ptKQLyhMC8HPhrfn/LTJmRNqA8VXaDwSqm8zn+l8mJK55P/kZeeuLSmsvSYIgKlbp6naAbhyWM/q7IsT1fOAmFGKuG5nKaOy+ufxaXwIWWRPejmi9i+gmEw2FOTNimwyOqwc=,iv:q6P6QuipKMGc5i5oZ7XoU/qkbgo4X/SejfJUorAGb1M=,tag:sGfym1AaYAYHEzwDC5Dgsg==,type:str]", + "lastmodified": "2025-07-22T17:19:04Z", + "mac": "ENC[AES256_GCM,data:r1h9ouXb8o8Vk3/l3SX6hxbPApMn4BcCIs52Jhv9s9RYURMGb9qqPipbX7yFIYDBMka2qJJ0BneJz2EI60nTxx+QqATImR2oot2U6iONrelgs+AL3We//xpHOVHSxQ9XMmeEOcVqXEU3u843jV1RElxarRCwB9yM6IWTPx2qNzA=,iv:bS571Ddgz6Fbhyxy2bL/087ZTD7egcvPoLXD9uF8aN0=,tag:HJBI6G6ivRHhJMXYrNhIKw==,type:str]", "pgp": [ { "created_at": "2025-07-02T12:10:18Z",