Root User Provisioning Service#

This is one of the more controversial services I have, but I needed a way to restore the system without anything except the ISO and a password.

With this service I am setting up root provisioning via a web link. I will curl the link with a post request and then it will add SSH keys to the root user on the server.

Is this dangerous? Yes, however I understand the risks associated. I also tried to design the service to only run if the system was net new. The service will exit if the done file already exists /var/lib/nik3sx/boot-unlock-service/done.

Generate a bcrypt password:

nix-shell -p whois --run "mkpasswd -m bcrypt -R 14 Password123"
echo "$2b$14$5y4Nqyb368wTd46jtRyq.e6GblLWW7U3Krmc5Ts7P.E2XPS59nq0u" > /var/lib/nik3sx/boot-unlock-service/password.hash
chmod 600 /var/lib/boot-unlock-service/password.hash
chown root:root /var/lib/boot-unlock-service/password.hash

To Build:

CGO_ENABLED=0 go build -o boot_unlock_service main.go

The functions to note include writeTLSSecret:

...
type UnlockRequest struct {
        PasswordInput string `json:"password_input"`
        SSHPublicKey  string `json:"ssh_public_key"`
}

...
const (
        certDir  = "/var/lib/nik3sx/boot-unlock-service/certs"
        doneFile = "/var/lib/nik3sx/boot-unlock-service/done"
)

...
func main() {
        outFile := "/var/lib/nik3sx/boot-unlock-service/boot-unlock-tls.yaml"
        secretName := "boot-unlock-tls"
        namespace := "kube-system"
        writeTLSSecret(certDir, outFile, secretName, namespace)

        if fileExists(doneFile) {
                log.Println("Already done")
                os.Exit(0)
        }

        os.MkdirAll(certDir, 0700)

        caCert, caKey := ensureCA()
        serverCert, serverKey := ensureServerCert(caCert, caKey)
        writeTLSSecret(certDir, outFile, secretName, namespace)

        mux := http.NewServeMux()
        mux.HandleFunc("/health", func(w http.ResponseWriter, _ *http.Request) {
                w.Write([]byte("ok"))
        })
        mux.HandleFunc("/unlock", unlockHandler)

        srv := &http.Server{
                Addr:    ":8443",
                Handler: mux,
        }

        startCAHTTPServer()
        log.Println("HTTPS server listening on :8443")
        log.Fatal(srv.ListenAndServeTLS(serverCert, serverKey))
}

...
// writeTLSSecret generates a Kubernetes TLS Secret YAML from cert/key files and writes it to outFile
func writeTLSSecret(certDir, outFile, secretName, namespace string) {

        crtFile := filepath.Join(certDir, "server.crt")
        keyFile := filepath.Join(certDir, "server.key")

        // Check if both files exist
        if !fileExists(crtFile) {
                log.Printf("Certificate file does not exist: %s", crtFile)
                return
        }
        if !fileExists(keyFile) {
                log.Printf("Key file does not exist: %s", keyFile)
                return
        }

        crtEncoded := encodeFile(crtFile)
        keyEncoded := encodeFile(keyFile)

        yamlContent := fmt.Sprintf(`apiVersion: v1
kind: Secret
metadata:
  name: %s
  namespace: %s
type: kubernetes.io/tls
data:
  tls.crt: %s
  tls.key: %s
`, secretName, namespace, crtEncoded, keyEncoded)

        if err := os.WriteFile(outFile, []byte(yamlContent), 0644); err != nil {
                log.Fatalf("Failed to write YAML file: %v", err)
        }

        fmt.Printf("Secret YAML written to %s\n", outFile)
}

...
func checkPassword(input string) error {
        hashBytes, err := os.ReadFile("/var/lib/nik3sx/boot-unlock-service/password.hash")
        if err != nil {
                return err
        }

        hash := strings.TrimSpace(string(hashBytes))
        return bcrypt.CompareHashAndPassword([]byte(hash), []byte(input))
}

func validateSSHPublicKey(key string) error {
        _, _, _, _, err := ssh.ParseAuthorizedKey([]byte(key))
        return err
}

...
func addRootKey(pubkey string) error {
        dir := "/root/.ssh"
        authKeys := dir + "/authorized_keys"

        if err := os.MkdirAll(dir, 0700); err != nil {
                return err
        }

        f, err := os.OpenFile(authKeys,
                os.O_APPEND|os.O_CREATE|os.O_WRONLY,
                0600,
        )
        if err != nil {
                return err
        }
        defer f.Close()

        _, err = f.WriteString(pubkey + "\n")
        return err
}

modules/boot-unlock-service.nix#

{
  pkgs,
  lib,
  ...
}: {
  environment.etc."boot_unlock_service/boot_unlock_service".source = ../boot-unlock-service/bin/boot_unlock_service;
  environment.etc."boot_unlock_service/password.hash".source = ../secrets/password.hash;
  # Ensure /var/lib folders exist
  systemd.tmpfiles.rules = [
    "d /var/lib/nik3sx/boot-unlock-service 0755 root root -"
    "d /var/lib/nik3sx/boot-unlock-service/certs 0700 root root -"

    # Optional: copy the binary here (could also run from Nix store directly)
    "f /var/lib/nik3sx/boot-unlock-service/password.hash 0700 root root - /etc/boot_unlock_service/password.hash"
    "f /var/lib/nik3sx/boot-unlock-service/boot_unlock_service 0755 root root - /etc/boot_unlock_service/boot_unlock_service"
  ];

  # Systemd service
  systemd.services.boot-unlock-service = {
    description = "Self-Signed HTTPS Boot Unlock Service";
    after = ["network-online.target"];
    wants = ["network-online.target"];

    serviceConfig = {
      Type = "oneshot";
      ConditionPathExists = "!/var/lib/nik3sx/boot-unlock-service/done";
      ExecStartPre = "${pkgs.coreutils}/bin/install -Dm700 /etc/boot_unlock_service/password.hash /var/lib/nik3sx/boot-unlock-service/password.hash";
      ExecStart = "${pkgs.bash}/bin/bash -c '/var/lib/nik3sx/boot-unlock-service/boot_unlock_service'"; # points to copied binary
      ExecStartPost = "${pkgs.coreutils}/bin/touch /var/lib/nik3sx/boot-unlock-service/done";
      User = "root";
      Group = "root";
      ReadWritePaths = ["/var/lib/nik3sx/boot-unlock-service" "/root/.ssh"];
      CapabilityBoundingSet = "";
      NoNewPrivileges = false;
      PrivateTmp = true;
      RemainAfterExit = "no";
    };

    wantedBy = ["multi-user.target"];
  };
}