{ ... }: { _class = "clan.service"; manifest.name = "clan-core/sshd"; manifest.description = "Enables secure remote access to the machine over SSH"; manifest.categories = [ "System" "Network" ]; manifest.readme = builtins.readFile ./README.md; roles.client = { interface = { lib, ... }: { options.certificate = { searchDomains = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ ]; example = [ "mydomain.com" ]; description = '' List of domains to include in the certificate. This option will prepend the machine name in front of each domain before adding it to the certificate. ''; }; }; }; perInstance = { settings, ... }: { nixosModule = { config, lib, pkgs, ... }: { clan.core.vars.generators.openssh-ca = lib.mkIf (settings.certificate.searchDomains != [ ]) { share = true; files.id_ed25519.deploy = false; files."id_ed25519.pub" = { deploy = false; secret = false; }; runtimeInputs = [ pkgs.openssh ]; script = '' ssh-keygen -t ed25519 -N "" -C "" -f "$out"/id_ed25519 ''; }; programs.ssh.knownHosts.ssh-ca = lib.mkIf (settings.certificate.searchDomains != [ ]) { certAuthority = true; extraHostNames = builtins.map (domain: "*.${domain}") settings.certificate.searchDomains; publicKey = config.clan.core.vars.generators.openssh-ca.files."id_ed25519.pub".value; }; }; }; }; roles.server = { interface = { lib, ... }: { options = { hostKeys.rsa.enable = lib.mkEnableOption "Generate RSA host key"; certificate = { searchDomains = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ ]; example = [ "mydomain.com" ]; description = '' List of domains to include in the certificate. This option will prepend the machine name in front of each domain before adding it to the certificate. ''; }; }; }; }; perInstance = { settings, ... }: { nixosModule = { config, lib, pkgs, ... }: { clan.core.vars.generators = { openssh-ca = lib.mkIf (settings.certificate.searchDomains != [ ]) { share = true; files.id_ed25519.deploy = false; files."id_ed25519.pub" = { deploy = false; secret = false; }; runtimeInputs = [ pkgs.openssh ]; script = '' ssh-keygen -t ed25519 -N "" -C "" -f "$out"/id_ed25519 ''; }; openssh-cert = lib.mkIf (settings.certificate.searchDomains != [ ]) { files."ssh.id_ed25519-cert.pub".secret = false; dependencies = [ "openssh" "openssh-ca" ]; validation = { name = config.clan.core.settings.machine.name; domains = lib.genAttrs settings.certificate.searchDomains lib.id; }; runtimeInputs = [ pkgs.openssh pkgs.jq ]; script = let stringSet = list: builtins.attrNames (builtins.groupBy lib.id list); domains = stringSet settings.certificate.searchDomains; in '' ssh-keygen \ -s $in/openssh-ca/id_ed25519 \ -I ${config.clan.core.settings.machine.name} \ -h \ -n ${lib.concatMapStringsSep "," (d: "${config.clan.core.settings.machine.name}.${d}") domains} \ $in/openssh/ssh.id_ed25519.pub mv $in/openssh/ssh.id_ed25519-cert.pub "$out"/ssh.id_ed25519-cert.pub ''; }; openssh-rsa = lib.mkIf settings.hostKeys.rsa.enable { files."ssh.id_rsa" = { }; files."ssh.id_rsa.pub".secret = false; runtimeInputs = [ pkgs.coreutils pkgs.openssh ]; script = '' ssh-keygen -t rsa -b 4096 -N "" -C "" -f "$out"/ssh.id_rsa ''; }; openssh = { files."ssh.id_ed25519" = { }; files."ssh.id_ed25519.pub".secret = false; migrateFact = "openssh"; runtimeInputs = [ pkgs.coreutils pkgs.openssh ]; script = '' ssh-keygen -t ed25519 -N "" -C "" -f "$out"/ssh.id_ed25519 ''; }; }; programs.ssh.knownHosts.ssh-ca = lib.mkIf (settings.certificate.searchDomains != [ ]) { certAuthority = true; extraHostNames = builtins.map (domain: "*.${domain}") settings.certificate.searchDomains; publicKey = config.clan.core.vars.generators.openssh-ca.files."id_ed25519.pub".value; }; services.openssh = { enable = true; settings.PasswordAuthentication = false; settings.HostCertificate = lib.mkIf ( settings.certificate.searchDomains != [ ] ) config.clan.core.vars.generators.openssh-cert.files."ssh.id_ed25519-cert.pub".path; hostKeys = [ { path = config.clan.core.vars.generators.openssh.files."ssh.id_ed25519".path; type = "ed25519"; } ] ++ lib.optional settings.hostKeys.rsa.enable { path = config.clan.core.vars.generators.openssh-rsa.files."ssh.id_rsa".path; type = "rsa"; }; }; programs.ssh.knownHosts.clan-sshd-self-ed25519 = { hostNames = [ "localhost" config.networking.hostName ] ++ (lib.optional (config.networking.domain != null) config.networking.fqdn); publicKey = config.clan.core.vars.generators.openssh.files."ssh.id_ed25519.pub".value; }; }; }; }; }