main
  1{
  2  den,
  3  lib,
  4  ...
  5}: let
  6  hostKeys = [
  7    {
  8      path = "/etc/ssh/ssh_host_ed25519_key";
  9      type = "ed25519";
 10    }
 11    {
 12      path = "/etc/ssh/ssh_host_rsa_key";
 13      type = "rsa";
 14      bit = 4096;
 15    }
 16  ];
 17
 18  hostKeyFiles = builtins.concatMap (key: [key.path] ++ ["${key.path}.pub"]) hostKeys;
 19in {
 20  den.aspects.core.includes = [den.aspects.core.openssh];
 21
 22  den.aspects.core.openssh = {
 23    settings.host = {
 24      server = {
 25        enable = lib.mkEnableOption "Whether to start OpenSSH server";
 26        port = lib.mkOption {
 27          type = lib.types.port;
 28          default = 22;
 29        };
 30      };
 31      authorizedKeys = lib.mkOption {
 32        type = lib.types.listOf lib.types.str;
 33        default = [];
 34        description = "SSH authorized keys for root on this host.";
 35      };
 36    };
 37
 38    persist = {
 39      files =
 40        map (file: {
 41          inherit file;
 42          mode = "06${
 43            if lib.strings.hasSuffix ".pub" file
 44            then "44"
 45            else "00"
 46          }";
 47        })
 48        hostKeyFiles;
 49    };
 50    persistHome = {
 51      directories = [
 52        {
 53          directory = ".ssh";
 54          mode = "0700";
 55        }
 56      ];
 57    };
 58
 59    tailscaleGrant = {host, ...}:
 60      lib.optional (host.settings.core.openssh.server.enable) {
 61        src = ["*"];
 62        ip = lib.unique ["tcp:22" "tcp:${toString host.settings.core.openssh.server.port}"];
 63      };
 64
 65    nixos = {host, ...}: {
 66      services.openssh = {
 67        enable = host.settings.core.openssh.server.enable;
 68        # Serve on 22 port for Tailscale
 69        ports = lib.unique [22 host.settings.core.openssh.server.port];
 70        generateHostKeys = true;
 71        inherit hostKeys;
 72        settings = {
 73          PermitRootLogin = "prohibit-password";
 74          PasswordAuthentication = false;
 75        };
 76        # Mannualy open filewall
 77        openFirewall = false;
 78      };
 79
 80      programs.ssh = {
 81        extraConfig = ''
 82          Host github.com
 83            HostName ssh.github.com
 84            Port 443
 85            User git
 86
 87          Host git.trin.one
 88            HostName cyrene
 89            Port 22
 90            User git
 91        '';
 92      };
 93
 94      users.users.root.openssh.authorizedKeys.keys =
 95        host.settings.core.openssh.authorizedKeys;
 96
 97      networking.firewall.allowedTCPPorts = [
 98        host.settings.core.openssh.server.port
 99      ];
100
101      environment.enableAllTerminfo = host.settings.core.openssh.server.enable;
102    };
103
104    provides.to-users = {
105      user = {user, ...}: {
106        openssh.authorizedKeys.keys = user.identity.sshKeys;
107      };
108    };
109  };
110}