{ config, lib, pkgs, ... }: with lib; let cfg = config.local.auth.openssh; withOath = config.local.auth.oath.enable; port = if cfg.shiftPortNumber then 2234 else 22; in { options.local.auth.openssh = { enable = mkEnableOption "openssh"; tunnel.enable = mkEnableOption "ssh tunnel user"; #TODO: Desfasar ecdsa, inseguro hostKeys = listToAttrs (map (name: { inherit name; value = mkOption { type = types.bool; default = false; }; }) [ "ecdsa" "ed25519" "rsa" ]); restrictListen = mkOption { default = null; type = with types; nullOr (submodule { options = { addresses = mkOption { type = listOf str; }; interface = mkOption { type = str; }; }; }); }; shiftPortNumber = mkOption { type = types.bool; default = true; }; withDeployKeys = mkOption { type = types.bool; default = false; }; }; config = lib.mkIf cfg.enable { assertions = [ { assertion = cfg.tunnel.enable -> withOath; message = "SSH tunnel requires oath"; } ]; local.boot.impermanence.files = flatten (map (key: [ key.path "${key.path}.pub" ]) config.services.openssh.hostKeys); networking.firewall.interfaces = optionalAttrs (cfg.restrictListen != null) { ${cfg.restrictListen.interface}.allowedTCPPorts = [ port ]; }; services.openssh = { enable = true; ports = [ port ]; openFirewall = cfg.restrictListen == null; startWhenNeeded = !config.services.fail2ban.enable; extraConfig = optionalString cfg.tunnel.enable '' # User 'tunnel' has no password. Use PAM OATH # and connect with -N, forward with -R. Match User tunnel AllowTcpForwarding remote AllowStreamLocalForwarding no X11Forwarding no PermitTunnel no GatewayPorts no AllowAgentForwarding no PermitOpen none PermitListen 60220 60221 60222 60223 60224 60225 60226 60227 60228 60229 Banner ${pkgs.writeText "tunnel-banner" '' This is a reverse tunnel ''} ''; hostKeys = map (name: { path = "/etc/ssh/ssh_host_${name}_key"; type = name; } // optionalAttrs (name == "rsa") { bits = 4096; }) (attrNames (filterAttrs (name: enable: enable) cfg.hostKeys)); settings = { X11Forwarding = true; PermitRootLogin = "prohibit-password"; PasswordAuthentication = withOath; # Necesario para oath, no reemplaza a oath }; listenAddresses = mkIf (cfg.restrictListen != null) (map (addr: { inherit addr; }) cfg.restrictListen.addresses); }; users.users = { root = mkIf cfg.withDeployKeys { openssh.authorizedKeys.keyFiles = [ ./ssh-key.pub ]; }; tunnel = mkIf cfg.tunnel.enable { uid = 1100; group = "nogroup"; isSystemUser = true; # Requiere oath password = "tunnel"; home = "/var/empty"; shell = "${pkgs.coreutils}/bin/true"; }; }; }; }