From 24dc18ee81f9a8624f7d868da502ccd749b4a6a5 Mon Sep 17 00:00:00 2001
From: niten <niten@fudo.org>
Date: Wed, 13 Oct 2021 17:23:47 -0700
Subject: [PATCH] Make all hosts' initrd network-accessible

First attempt
---
 config/hardware/socrates.nix | 28 +++++------
 config/hosts/lambda.nix      |  1 +
 config/hosts/limina.nix      |  1 +
 config/hosts/nostromo.nix    |  1 +
 config/hosts/plato.nix       |  1 +
 config/hosts/socrates.nix    |  1 +
 config/hosts/spark.nix       |  1 +
 config/hosts/system3.nix     |  1 +
 config/hosts/zbox.nix        |  1 +
 config/sites.nix             |  2 +-
 config/users.nix             | 16 +------
 lib/default.nix              |  1 +
 lib/fudo/hosts.nix           |  4 +-
 lib/fudo/initrd-network.nix  | 92 ++++++++++++++++++++++++++++++++++++
 lib/fudo/local-network.nix   | 21 +++++---
 lib/fudo/ssh.nix             |  2 -
 lib/types/host.nix           | 32 +++++++++++++
 17 files changed, 165 insertions(+), 41 deletions(-)
 create mode 100644 lib/fudo/initrd-network.nix

diff --git a/config/hardware/socrates.nix b/config/hardware/socrates.nix
index 4a13786..584c7af 100644
--- a/config/hardware/socrates.nix
+++ b/config/hardware/socrates.nix
@@ -20,20 +20,20 @@
           "r8169"
         ];
         kernelModules = [ "dm-snapshot" ];
-        network = {
-          enable = true;
-          ssh = {
-            enable = true;
-            port = 22;
-            authorizedKeys = [
-              "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDPwh522lvafTJYA0X2uFdP7Ws+Um1f8gZsARK1Y5nMzf6ZcWBF1jplTOKUVSOl4isMWni0Tu0TnX4zqCcgocWUVbwIwXSIRYqdiCPvVOH+/Ibc97n1/dYxk5JPMtbrsEw6/gWZxVg0qwe0J3dQWldEMiDY7iWhlrmIr7YL+Y3PUd7DOwp3PbfWfNyzTfE1kXcz5YvTeN+txFhbbXT0oS2R2wtc1vYXFZ/KbNstjqd+i8jszAq3ZkbbwL3aNR0RO4n8+GoIILGw8Ya4eP7D6+mYk608IhAoxpGyMrUch2TC2uvOK3rd/rw1hsTxf4AKjAZbrfd/FJaYru9ZeoLjD4bRGMdVp56F1m7pLvRiWRK62pV2Q/fjx+4KjHUrgyPd601eUIP0ayS/Rfuq8ijLpBJgO5/Y/6mFus/kjZIfRR9dXfLM67IMpyEzEITYrc/R2sedWf+YHxSh6eguAZ/kLzioar1nHLR7Wzgeu0tgWkD78WQGjpXGoefAz3xHeBg3Et0= niten@plato"
-            ];
-            hostKeys = [
-              "/state/ssh/ssh_host_ed25519_key"
-              "/state/ssh/ssh_host_rsa_key"
-            ];
-          };
-        };
+        # network = {
+        #   enable = true;
+        #   ssh = {
+        #     enable = true;
+        #     port = 22;
+        #     authorizedKeys = [
+        #       "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDPwh522lvafTJYA0X2uFdP7Ws+Um1f8gZsARK1Y5nMzf6ZcWBF1jplTOKUVSOl4isMWni0Tu0TnX4zqCcgocWUVbwIwXSIRYqdiCPvVOH+/Ibc97n1/dYxk5JPMtbrsEw6/gWZxVg0qwe0J3dQWldEMiDY7iWhlrmIr7YL+Y3PUd7DOwp3PbfWfNyzTfE1kXcz5YvTeN+txFhbbXT0oS2R2wtc1vYXFZ/KbNstjqd+i8jszAq3ZkbbwL3aNR0RO4n8+GoIILGw8Ya4eP7D6+mYk608IhAoxpGyMrUch2TC2uvOK3rd/rw1hsTxf4AKjAZbrfd/FJaYru9ZeoLjD4bRGMdVp56F1m7pLvRiWRK62pV2Q/fjx+4KjHUrgyPd601eUIP0ayS/Rfuq8ijLpBJgO5/Y/6mFus/kjZIfRR9dXfLM67IMpyEzEITYrc/R2sedWf+YHxSh6eguAZ/kLzioar1nHLR7Wzgeu0tgWkD78WQGjpXGoefAz3xHeBg3Et0= niten@plato"
+        #     ];
+        #     hostKeys = [
+        #       "/state/ssh/ssh_host_ed25519_key"
+        #       "/state/ssh/ssh_host_rsa_key"
+        #     ];
+        #   };
+        # };
       };
 
       loader = {
diff --git a/config/hosts/lambda.nix b/config/hosts/lambda.nix
index 7666888..6ebf1a2 100644
--- a/config/hosts/lambda.nix
+++ b/config/hosts/lambda.nix
@@ -22,4 +22,5 @@
   arch = "x86_64-linux";
   nixos-system = true;
   machine-id = "c031cda2e88a4cedb3b22f41f9042646";
+  initrd-ip = "10.0.5.11";
 }
diff --git a/config/hosts/limina.nix b/config/hosts/limina.nix
index 7c2a2ba..a37f078 100644
--- a/config/hosts/limina.nix
+++ b/config/hosts/limina.nix
@@ -21,4 +21,5 @@
     public-key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA44EqP6HHjIPBFuxKvi2oZc1sNU+N4pNMtlS89KWuDm";
     key-path = "/state/master-key/key";
   };
+  initrd-ip = "10.0.5.1";
 }
diff --git a/config/hosts/nostromo.nix b/config/hosts/nostromo.nix
index 6d6164a..2dd9d1e 100644
--- a/config/hosts/nostromo.nix
+++ b/config/hosts/nostromo.nix
@@ -21,4 +21,5 @@
     public-key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIODtNR4b43ZJgyGo9Hc+CmC4+bzgxbsVYI9fhDqjyRSo";
     key-path = "/state/master-key/key";
   };
+  initrd-ip = "10.0.5.10";
 }
diff --git a/config/hosts/plato.nix b/config/hosts/plato.nix
index 718e040..6b5d9ff 100644
--- a/config/hosts/plato.nix
+++ b/config/hosts/plato.nix
@@ -24,4 +24,5 @@
     public-key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICgAzn6gyG1ze7L1WLU84poPGcoUntqfvgn+/s3bxhR2";
     key-path = "/state/master-key/key";
   };
+  initrd-ip = "10.0.5.11";
 }
diff --git a/config/hosts/socrates.nix b/config/hosts/socrates.nix
index 7ff7663..8577343 100644
--- a/config/hosts/socrates.nix
+++ b/config/hosts/socrates.nix
@@ -21,4 +21,5 @@
     public-key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINmJJFbAV8P1V1LSZr56GJ5ul3LBgdapbh+MK3ixTsxf";
     key-path = "/state/master-key/key";
   };
+  initrd-ip = "10.0.5.10";
 }
diff --git a/config/hosts/spark.nix b/config/hosts/spark.nix
index 9558ab6..df17627 100644
--- a/config/hosts/spark.nix
+++ b/config/hosts/spark.nix
@@ -22,4 +22,5 @@
     public-key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGs8MfR3d6f1Llqk5dn/ypODUT1Oi4SQGof/YvOPNf14";
     key-path = "/state/master-key/key";
   };
+  initrd-ip = "10.0.5.108";
 }
diff --git a/config/hosts/system3.nix b/config/hosts/system3.nix
index 2a915c8..8eb00b4 100644
--- a/config/hosts/system3.nix
+++ b/config/hosts/system3.nix
@@ -22,4 +22,5 @@
     public-key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEaF5T7Pb613C31BJVj74WYx4Pytj/lmH+PqjkqoNNkQ";
     key-path = "/state/master-key/key";
   };
+  initrd-ip = "10.0.5.111";
 }
diff --git a/config/hosts/zbox.nix b/config/hosts/zbox.nix
index 806dc7e..3486ed2 100644
--- a/config/hosts/zbox.nix
+++ b/config/hosts/zbox.nix
@@ -22,4 +22,5 @@
     public-key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDsn68vDKV4jnBuICSDX/2Gpnshbrz0r9t4lXIke1vqh";
     key-path = "/state/master-key/key";
   };
+  initrd-ip = "10.0.5.110";
 }
diff --git a/config/sites.nix b/config/sites.nix
index 7056529..c9cf998 100644
--- a/config/sites.nix
+++ b/config/sites.nix
@@ -6,7 +6,7 @@
       gateway-v4 = "10.0.0.1";
       nameservers = [ "10.0.0.1" ];
       network = "10.0.0.0/16";
-      dynamic-network = "10.0.1.0/24";
+      dynamic-network = "10.0.100.0/24";
       timezone = "America/Los_Angeles";
       gateway-host = "nostromo";
       deploy-pubkeys = [
diff --git a/config/users.nix b/config/users.nix
index 248ab43..ed3c2bf 100644
--- a/config/users.nix
+++ b/config/users.nix
@@ -14,13 +14,9 @@ in {
         "$6$a1q2Duoe35hd5$IaZGXPfqyGv9uq5DQm7DZq0vIHsUs39sLktBiBBqMiwl/f/Z4jSvNZLJp9DZJYe5u2qGBYh1ca.jsXvQA8FPZ/";
       ssh-authorized-keys = [
         "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDoWkjyeIfgwm0b78weToVYOQSD0RQ0qbNzpsN5NokbIFv2/980kLtnYrQEgIJ/JwMLlT3uJYacbCT5/a6Fb8oLxNpj0AF1EKaWZ3Rrlg72Sq+9SEwJwWWmZizX83sovMwUBMaUp6jWLhAhPpzBW5pfc5YWoc89wxGbELSwzgt5EgHbSJgvDnaHSp3fVaY01wfDXbL/oO160iNe7wv2HLMZu/FkWBkIjz6HmoGJJzYM89bUpHbyYG28lmCHB/8UPog5/BsjOn3/qupgf4zh6mMdMsXLvbR2jVwVjxcEMj9N5nCvc+Y3oi7Mij6VNrWbhkaAJMEzeMhWYrF3/pFQxUqG37aK3d0gw9kp5tMDLIlAPX4y1lfA87pIzoa0+Alql0CJQA1IJvp9SFG7lBmSthWQLmZvwwfoGg/ZjF6rOgsVoZ8TizpQnydWJDr6NboU9LL9Oa64OM5Rs0AU3cR2UbOF4QIcWFJ/7oDe3dOnfZ8QYqx9eXJyxoAUpDanaaTHYBiAKkeOBwQU+MVLKCcONKw9FZclf/1TpDB5b3/JeUFANjHQTv0UXA4YYU7iCx6H7XB4qwwtU9O19CGQYYfCfULX12/fRpYJw6VJaQWyyU4Bn5dk/dcB2nGI36jwbLMfhbUTIApujioAnd/GQIMakHEZ1+syPhMx9BxMkZb99B0A1Q== openpgp:0x4EC95B64"
+        "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDGVez4of30f+j0cWKj5kYCKeFjyNsYvG9UbOMxF5hImD2lP5MSbFBv31gFgHjx3yCG4zQRZlpuyU5uWo0qIwe9N84/LcZcB9WrWKZXDmuof7zPFy0J+Hj+LVLDQI/mVXHNwkMhBMHpPrdwA05EYDAYCYklWT4cSByu10pHtST+olF8i+A+UQgUzgNZzdJVeiYZv6MBDTYsJWptGeDUkl2B0Es3gtbGYcCCfnyS3RC7DIXlDo3NBbAr7WaHY2MBbT+R/+jicn9E3IY3NCM5jENxqmvHy9MDsxEEYgFNm7IDwq4V1VRUWy277YsvRbmEaHb+osOA5u1VNN4z3UftOZcSZgR5C/vR71cENXoPt1YQpCzu7i38ojtvL+tDVEKT7sIovrQw8q1sszNlW2nXh8RSPiIq5TMnrV73MP0egKcr9n3tfxwi1BIkLjvfom/02BkTK9R9v+VMNhYU1YwROhORCiMIgoxUGiUvtH8u38JGr7E0hhMoAjCE5k80WPUivl0= niten@socrates"
       ];
       home-directory = "/home/niten";
-      # home-manager-generator = home-generator.generate-config {
-      #   username = "niten";
-      #   user-email = "niten@fudo.org";
-      #   home-dir = "/home/niten";
-      # };
       k5login = [
         "niten/root@FUDO.ORG"
         "niten/admin@FUDO.ORG"
@@ -195,11 +191,6 @@ in {
       ldap-hashed-passwd = "{MD5}iecbyMpyVkmOaMBzSFy58Q==";
       login-hashed-passwd =
         "$6$C8lYHrK7KvdKm/RE$cHZ2hg5gEOEjTV8Zoayik8sz5h.Vh0.ClCgOlQn8l/2Qx/qdxqZ7xCsAZ1GZ.IEyESfhJeJbjLpykXDwPpfVF0";
-      # home-manager-generator = home-generator.generate-config {
-      #   username = "xiaoxuan";
-      #   user-email = "xiaoxuan@fudo.org";
-      #   home-dir = "/home/fudo/xiaoxuan";
-      # };
       email = "xiaoxuan@fudo.org";
     };
 
@@ -483,11 +474,6 @@ in {
       uid = 10115;
       primary-group = "informis";
       common-name = "Viator";
-      # home-manager-generator = home-generator.generate-config {
-      #   username = "viator";
-      #   user-email = "viator@informis.land";
-      #   home-dir = "/home/viator";
-      # };
       ldap-hashed-passwd = "{SSHA}dF/5NGkafL8M1kpa3LYZKdh0Pc7a02gA";
       login-hashed-passwd =
         "$6$a1q2Duoe35hd5$IaZGXPfqyGv9uq5DQm7DZq0vIHsUs39sLktBiBBqMiwl/f/Z4jSvNZLJp9DZJYe5u2qGBYh1ca.jsXvQA8FPZ/";
diff --git a/lib/default.nix b/lib/default.nix
index f48fb3f..a54d000 100644
--- a/lib/default.nix
+++ b/lib/default.nix
@@ -20,6 +20,7 @@ with lib; {
     ./fudo/global.nix
     ./fudo/grafana.nix
     ./fudo/hosts.nix
+    ./fudo/initrd-network.nix
     ./fudo/ipfs.nix
     ./fudo/kdc.nix
     ./fudo/ldap.nix
diff --git a/lib/fudo/hosts.nix b/lib/fudo/hosts.nix
index 7986484..a5c9c59 100644
--- a/lib/fudo/hosts.nix
+++ b/lib/fudo/hosts.nix
@@ -106,8 +106,6 @@ in {
       autoPrune.enable = true;
     };
 
-    boot.tmpOnTmpfs = host-cfg.tmp-on-tmpfs;
-
     fudo = let
       try-attr = attr: set: if (hasAttr attr set) then set.${attr} else null;
 
@@ -153,6 +151,8 @@ in {
       members = config.instance.local-admins;
     };
 
+    boot.tmpOnTmpfs = host-cfg.tmp-on-tmpfs;
+
     # programs.ssh.knownHosts = let
     #   keyed-hosts =
     #     filterAttrs (host: opts: opts.ssh-pubkeys != []) config.fudo.hosts;
diff --git a/lib/fudo/initrd-network.nix b/lib/fudo/initrd-network.nix
new file mode 100644
index 0000000..d2a3744
--- /dev/null
+++ b/lib/fudo/initrd-network.nix
@@ -0,0 +1,92 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+  hostname = config.instance.hostname;
+  host-cfg = config.fudo.hosts.${hostname};
+  ip = host-cfg.initrd-ip;
+
+  gen-host-keys = hostname: pkgs.stdenv.mkDerivation {
+    name = "${hostname}-initrd-ssh-keys";
+
+    phases = [ "installPhase" ];
+
+    buildInputs = with pkgs; [ openssh ];
+
+    installPhase = ''
+      mkdir $out
+      ssh-keygen -q -t ed25519 -N "" -f $out/ssh_host_ed25519_key
+    '';
+  };
+
+  gen-sshfp-records = host: key-pkg: pkgs.stdenv.mkDerivation {
+    name = "${hostname}-initrd-ssh-fingerprints";
+
+    phases = [ "installPhase" ];
+
+    buildInputs = with pkgs; [ openssh ];
+
+    installPhase = ''
+      mkdir $out
+      ssh-keygen -r REMOVEME -f "${key-pkg}/ssh_host_ed25519_key" | sed 's/^REMOVEME IN SSHFP //' >> $out/ssh_host_ed25519_key.sshfp
+    '';
+  };
+
+  host-keys = genAttrs (attrNames config.instance.local-hosts)
+    (hostname: gen-host-keys hostname);
+
+in {
+  config = mkIf (ip != null) {
+    boot = {
+      kernelParams = [
+        "ip=${ip}"
+      ];
+      initrd = let
+        host-key-pkg = host-keys.${config.instance.hostname};
+        host-privkey = "${key-pkg}/ssh_host_ed25519_key";
+        initrd-keypath = "/var/run/secrets/ssh/ssh_host_ed25519_key";
+      in {
+        secrets = {
+          "${initrd-keypath}" = host-privkey;
+        };
+
+        network = {
+          enable = true;
+
+          ssh = let
+            admin-ssh-keys =
+              concatMap (admin: config.fudo.users.${admin}.ssh-authorized-keys)
+                config.instance.local-admins;
+          in {
+            enable = true;
+            port = 22;
+            authorizedKeys = admin-ssh-keys;
+            hostKeys = [
+              initrd-keypath
+            ];
+          };
+        };
+      };
+    };
+
+    fudo = {
+      local-network = {
+        network-definition.hosts = mapAttrs'
+          (hostname: hostOpts: nameValuePair "${hostname}-recovery"
+            {
+              ipv4-address = config.fudo.hosts.${hostname}.initrd-ip;
+              description = "${hostname} initrd host";
+            })
+          config.instance.local-hosts;
+
+        extra-records =
+          mapAttrs
+            (hostname: key-pkg: let
+              sshfp-pkg = gen-sshfp-records hostname key-pkg;
+              sshfps = read-lines "${sshfp-pkg}/ssh_host_ed25519_key.sshfp";
+            in map (sshfp: "${hostname} IN SSHFP ${sshfp}") sshfps)
+            host-keys;
+      };
+    };
+  };
+}
diff --git a/lib/fudo/local-network.nix b/lib/fudo/local-network.nix
index 55421b9..cbb7f44 100644
--- a/lib/fudo/local-network.nix
+++ b/lib/fudo/local-network.nix
@@ -74,13 +74,19 @@ in {
       default = [ ];
     };
 
-    network-definition =
-      let networkOpts = import ../types/network-definition.nix { inherit lib; };
-      in mkOption {
-        type = submodule networkOpts;
-        description = "Definition of network to be served by local server.";
-        default = { };
-      };
+    network-definition = let
+      networkOpts = import ../types/network-definition.nix { inherit lib; };
+    in mkOption {
+      type = submodule networkOpts;
+      description = "Definition of network to be served by local server.";
+      default = { };
+    };
+
+    extra-records = mkOption {
+      type = listOf str;
+      description = "Extra records to add to the local zone.";
+      default = [ ];
+    };
   };
 
   config = mkIf cfg.enable {
@@ -224,6 +230,7 @@ in {
           ${join-lines (mapAttrsToList cnameRecord network.aliases)}
           ${join-lines network.verbatim-dns-records}
           ${pkgs.lib.fudo.dns.srvRecordsToBindZone network.srv-records}
+          ${join-lines cfg.extra-records}
         '';
       }] ++ blockZones;
     };
diff --git a/lib/fudo/ssh.nix b/lib/fudo/ssh.nix
index 2c8f254..2d573e4 100644
--- a/lib/fudo/ssh.nix
+++ b/lib/fudo/ssh.nix
@@ -51,8 +51,6 @@ in {
             filename = sshfp-filename hostname keypair;
           in read-lines "${fingerprint-derivation}/${filename}") keypairs;
       }) config.fudo.secrets.files.host-ssh-keypairs;
-
-
     };
 
     services.openssh.hostKeys = map (keypair: {
diff --git a/lib/types/host.nix b/lib/types/host.nix
index 41eda4e..f186d5f 100644
--- a/lib/types/host.nix
+++ b/lib/types/host.nix
@@ -176,6 +176,38 @@ rec {
       };
 
       android-dev = mkEnableOption "Enable ADB on the host.";
+
+      # FIXME: This probably belongs elsewhere...
+      initrd-ip = mkOption {
+        type = nullOr str;
+        description = "IP to assign to the kernel/initrd, to allow access when boot fails.";
+        default = null;
+      };
+
+      initrd-ssh-keypair = let
+        keypair = { ... }: {
+          options = {
+            public-key = mkOption {
+              type = str;
+              description = "SSH public key.";
+            };
+
+            private-key = mkOption {
+              type = str;
+              description = "SSH private key.";
+            };
+
+            type = mkOption {
+              type = enum [ "rsa" "ecdsa" "ed25519" ];
+              description = "SSH key type."
+            };
+          };
+        };
+      in mkOption {
+        type = nullOr (submodule keypair);
+        description = "SSH Keypair to use for initrd.";
+        default = null;
+      };
     };
   };
 }