diff --git a/modules/core/ssh-bootstrap.nix b/modules/core/ssh-bootstrap.nix new file mode 100644 index 0000000..7ed7b83 --- /dev/null +++ b/modules/core/ssh-bootstrap.nix @@ -0,0 +1,54 @@ +{ config, pkgs, lib, ... }: + +let + userName = "free"; + keyPath = "/home/${userName}/.ssh/factory_login"; +in +{ + # Ensure SSH dirs exist with correct perms + systemd.tmpfiles.rules = [ + "d /root/.ssh 0700 root root -" + "d /home/${userName}/.ssh 0700 ${userName} users -" + ]; + + # Generate keypair if missing (runs once) + systemd.services.factory-ssh-keygen = { + description = "Generate factory SSH key for ${userName} if missing"; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + path = [ pkgs.openssh pkgs.coreutils ]; + script = '' + if [ ! -f "${keyPath}" ]; then + ssh-keygen -q -N "gosovransystems" -t ed25519 -f "${keyPath}" + chown ${userName}:users "${keyPath}" "${keyPath}.pub" + chmod 600 "${keyPath}" + chmod 644 "${keyPath}.pub" + fi + ''; + }; + + # Pull the public key into root's authorized_keys once it exists + systemd.services.factory-ssh-authorize = { + description = "Authorize factory SSH key for root"; + wantedBy = [ "multi-user.target" ]; + after = [ "factory-ssh-keygen.service" ]; + requires = [ "factory-ssh-keygen.service" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + path = [ pkgs.coreutils ]; + script = '' + if [ -f "${keyPath}.pub" ]; then + PUB=$(cat "${keyPath}.pub") + mkdir -p /root/.ssh + touch /root/.ssh/authorized_keys + grep -qxF "$PUB" /root/.ssh/authorized_keys || echo "$PUB" >> /root/.ssh/authorized_keys + chmod 600 /root/.ssh/authorized_keys + fi + ''; + }; +} \ No newline at end of file diff --git a/modules/modules.nix b/modules/modules.nix index 1fef452..7529fda 100755 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -7,6 +7,7 @@ ./core/role-logic.nix ./core/caddy.nix ./core/njalla.nix + ./core/ssh-bootstrap.nix ./core/sovran-manage-domains.nix # ── Always on (no flag) ───────────────────────────────────