diff options
Diffstat (limited to 'sys/auth/openssh.nix')
| -rw-r--r-- | sys/auth/openssh.nix | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/sys/auth/openssh.nix b/sys/auth/openssh.nix new file mode 100644 index 0000000..44fb49a --- /dev/null +++ b/sys/auth/openssh.nix @@ -0,0 +1,193 @@ +{ + config, + lib, + pkgs, + ... +}: +with lib; let + cfg = config.local.auth.openssh; + withOath = config.local.auth.oath.enable; + withPassword = config.local.auth.openssh.passwordAuthentication; + + port = + if cfg.shiftPortNumber + then 2234 + else 22; + restrict = cfg.restrictListen; + + exemptList = optionals config.local.net.fail2ban.enable config.services.fail2ban.ignoreIP; +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 = nullOr str; + default = null; + }; + + vsockCid = mkOption { + type = nullOr ints.u32; + default = null; + }; + }; + }); + }; + + passwordAuthentication = mkOption { + type = types.bool; + default = false; + }; + + 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"; + } + { + assertion = restrict != null -> (restrict.vsockCid != null -> (restrict.interface == null && restrict.addresses == [])); + message = "SSH vsock restrict requires disabling inet"; + } + { + assertion = restrict != null -> (restrict.vsockCid != null -> config.services.openssh.startWhenNeeded); + message = "SSH vsock restrict requires socket activation"; + } + { + assertion = restrict != null -> (restrict.vsockCid != null -> config.local.virt.enable); + message = "SSH vsock restrict requires nixvirt"; + } + { + assertion = any (key: key) (attrValues cfg.hostKeys); + message = "No OpenSSH host keys were enabled"; + } + ]; + + local.boot.impermanence.files = + flatten (map (key: [key.path "${key.path}.pub"]) config.services.openssh.hostKeys); + + networking.firewall = { + interfaces = optionalAttrs (restrict != null && restrict.interface != null) { + ${restrict.interface}.allowedTCPPorts = [port]; + }; + + allowedTCPPorts = optional (restrict == null || restrict.interface == null) port; + }; + + services.openssh = { + enable = true; + + ports = optional (restrict != null -> restrict.addresses != []) port; + startWhenNeeded = mkDefault (!config.services.fail2ban.enable); + + extraConfig = + optionalString (exemptList != []) '' + PerSourcePenaltyExemptList ${concatStringsSep "," exemptList} + '' + + 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 = config.local.seat.enable && config.local.seat.graphical; + PermitRootLogin = "prohibit-password"; + PasswordAuthentication = withOath || withPassword; # Necesario para oath, no reemplaza a oath + }; + + listenAddresses = + mkIf (restrict != null) + (map (addr: {inherit addr;}) restrict.addresses); + }; + + systemd.sockets = mkIf (restrict != null && restrict.vsockCid != null) { + sshd = let + kernelMod = "modprobe@${ + if restrict.vsockCid == 2 + then "vhost_" + else "" + }vsock.service"; + in { + after = [kernelMod]; + wants = [kernelMod]; + + socketConfig.ListenStream = mkForce ["vsock:${toString restrict.vsockCid}:${toString port}"]; + }; + }; + + 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"; + }; + }; + }; +} |
