diff options
Diffstat (limited to '')
| -rw-r--r-- | modules/remote-unlock.nix | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/modules/remote-unlock.nix b/modules/remote-unlock.nix new file mode 100644 index 0000000..fea9345 --- /dev/null +++ b/modules/remote-unlock.nix @@ -0,0 +1,111 @@ +{ + config, + lib, + pkgs, + ... +}: + +with lib; + +let + cfg = config.services.remoteDiskUnlock; + + unlockScript = pkgs.writeShellScript "remote-disk-unlock" '' + #!/usr/bin/env bash + set -euo pipefail + + SSH_KEY="$CREDENTIALS_DIRECTORY/ssh-key" + PASSPHRASE_FILE="$CREDENTIALS_DIRECTORY/passphrase" + + for server in ${concatStringsSep " " cfg.hosts}; do + echo "Probing host $server on port 22" + if ${pkgs.netcat}/bin/nc -z -w 5 "$server" 22 2>/dev/null; then + echo "Host $server is already unlocked, skipping" + continue + fi + echo "No response on port 22, probing host $server on port 911" + if ${pkgs.netcat}/bin/nc -z -w 5 "$server" 911 2>/dev/null; then + echo "Host $server is waiting for unlock - unlocking" + ${pkgs.openssh}/bin/ssh -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null \ + -i "$SSH_KEY" -p 911 "root@$server" < "$PASSPHRASE_FILE" || true + else + echo "Host $server is down, retry later" + fi + done + ''; +in +{ + options.services.remoteDiskUnlock = { + enable = mkEnableOption "remote disk unlock service"; + + hosts = mkOption { + type = types.listOf types.str; + default = [ ]; + description = "List of hostnames/IPs to monitor and unlock"; + example = [ + "server1.local" + "192.168.1.100" + ]; + }; + + sshKeyPath = mkOption { + type = types.path; + description = "Path to SSH private key"; + example = "/run/agenix/disk-unlock-key"; + }; + + passphrasePath = mkOption { + type = types.path; + description = "Path to disk passphrase file"; + example = "/run/agenix/disk-passphrase"; + }; + + interval = mkOption { + type = types.str; + default = "10min"; + description = "How often to check hosts (systemd timer format)"; + }; + }; + + config = mkIf cfg.enable { + systemd.services.remote-disk-unlock = { + description = "Unlock remote encrypted disks"; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${unlockScript}"; + DynamicUser = true; + LoadCredential = [ + "ssh-key:${cfg.sshKeyPath}" + "passphrase:${cfg.passphrasePath}" + ]; + PrivateTmp = true; + ProtectSystem = "strict"; + ProtectHome = true; + NoNewPrivileges = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + "AF_UNIX" + ]; + RestrictNamespaces = true; + LockPersonality = true; + MemoryDenyWriteExecute = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + }; + }; + + systemd.timers.remote-disk-unlock = { + description = "Check and unlock remote disks periodically"; + wantedBy = [ "timers.target" ]; + timerConfig = { + OnBootSec = "1min"; + OnUnitActiveSec = cfg.interval; + Persistent = false; + }; + }; + }; +} |
