{ config, lib, pkgs, ... }: let cfg = config.myOptions.services.ssh; inherit (lib) getExe' mkEnableOption mkIf mkMerge mkOption; inherit (lib.types) attrsOf bool nullOr number str submodule; inherit (lib.strings) concatStrings; inherit (lib.attrsets) mapAttrsToList; ksshaskpass = getExe' pkgs.libsForQt5.ksshaskpass "ksshaskpass"; ssh-agent = getExe' pkgs.openssh "ssh-agent"; in { options.myOptions.services.ssh = { daemon = mkOption { description = "sshd options"; type = submodule { options = { enable = mkEnableOption "sshd"; passwordAuth = mkOption { description = "allow password auth"; default = false; type = bool; }; allowRoot = mkOption { description = "allow root login"; default = false; type = bool; }; }; }; }; agent = mkOption { description = "ssh agent options"; type = submodule { options = { enable = mkEnableOption "ssh-agent"; hostAliases = mkOption { description = "host aliases"; type = attrsOf (submodule { options = { hostName = mkOption { description = "hostname to ssh into"; type = str; }; port = mkOption { description = "port to ssh into"; type = nullOr number; default = null; }; user = mkOption { description = "ssh user"; type = str; default = "git"; }; publicKey = mkOption { description = "public key used for picking the correct key from the ssh-agent"; type = nullOr str; default = null; }; }; }); default = {}; }; }; }; }; }; config = mkMerge [ (mkIf cfg.daemon.enable { services.openssh = { enable = true; settings = { PasswordAuthentication = false; PermitRootLogin = "no"; LoginGraceTime = 0; }; }; }) (mkIf cfg.agent.enable { programs.ssh = { enableAskPassword = true; askPassword = ksshaskpass; extraConfig = '' AddKeysToAgent yes ${concatStrings (mapAttrsToList (name: value: '' Host ${name} HostName ${value.hostName} User ${value.user} ${ if value.port != null then "Port ${toString value.port}" else "" } ${ if value.publicKey != null then "IdentityFile ${pkgs.writeText "${name}.pub" value.publicKey}" else "" } '') cfg.agent.hostAliases)} ''; }; systemd.user.services.ssh-agent = { enable = true; description = "SSH key agent"; serviceConfig = { Type = "simple"; ExecStart = "${ssh-agent} -D -a $SSH_AUTH_SOCK"; }; environment = { SSH_AUTH_SOCK = "%t/ssh-agent.socket"; DISPLAY = ":0"; }; wantedBy = [ "default.target" ]; }; environment.sessionVariables = { SSH_AUTH_SOCK = "\$XDG_RUNTIME_DIR/ssh-agent.socket"; }; }) ]; }