diff --git a/modules/hosts/john-pc/default.nix b/modules/hosts/john-pc/default.nix index 7d3716b..889f5a5 100644 --- a/modules/hosts/john-pc/default.nix +++ b/modules/hosts/john-pc/default.nix @@ -61,6 +61,9 @@ in }; ssh = { certificates.enable = true; + knownHosts = [ + "fded:fb16:653e:25da:be24:11ff:fea0:753f ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ9ZqiWPrCwHjxFCiu0lT4rlQs7KyMapxKJQQ5PJP1eh" + ]; matchSets = { certs = true; appdaemon = true; diff --git a/modules/programs/onepassword.nix b/modules/programs/onepassword.nix index 6d07a3a..a6821e8 100644 --- a/modules/programs/onepassword.nix +++ b/modules/programs/onepassword.nix @@ -1,16 +1,10 @@ { self, inputs, ... }: { - flake.modules.homeManager.onepassword = { config, pkgs, lib, ... }: { + flake.modules.homeManager.onepassword = { config, ... }: { home.file.".config/1Password/ssh/agent.toml".text = '' # https://developer.1password.com/docs/ssh/agent/config [[ssh-keys]] vault = "Private" ''; - programs.ssh = { - enable = true; - extraConfig = '' - Host * - IdentityAgent ${config.home.homeDirectory}/.1password/agent.sock - ''; - }; + programs.ssh.matchBlocks."*".identityAgent = "${config.home.homeDirectory}/.1password/agent.sock"; }; } diff --git a/modules/programs/sops.nix b/modules/programs/sops.nix index 554bbf4..166dd61 100644 --- a/modules/programs/sops.nix +++ b/modules/programs/sops.nix @@ -64,8 +64,8 @@ in (writeShellScriptBin "gen-age-key" '' set -eu - if [ ! -f "${config.ssh.IdentityFile}" ]; then - ${echo} "SSH identity file not found: ${config.ssh.IdentityFile}" >&2 + if [ ! -f "${config.ssh.identityFile}" ]; then + ${echo} "SSH identity file not found: ${config.ssh.identityFile}" >&2 exit 1 fi @@ -75,7 +75,7 @@ in fi ${mkdir} -p "$(${dirname} "${cfg.ageKeyFile}")" - ${lib.getExe pkgs.ssh-to-age} -i ${config.ssh.IdentityFile} -private-key > ${cfg.ageKeyFile} + ${lib.getExe pkgs.ssh-to-age} -i ${config.ssh.identityFile} -private-key > ${cfg.ageKeyFile} ${echo} -n "Created ${cfg.ageKeyFile}: " ${echo} $(${lib.getExe show-age-key}) '') @@ -90,7 +90,7 @@ in sops = { defaultSopsFile = sopsSecretsPath; defaultSopsFormat = "yaml"; - age.sshKeyPaths = [ "${config.ssh.IdentityFile}" ]; + age.sshKeyPaths = [ "${config.ssh.identityFile}" ]; }; }; }; diff --git a/modules/programs/step-client.nix b/modules/programs/step-client.nix index 5c322e3..2a50df0 100644 --- a/modules/programs/step-client.nix +++ b/modules/programs/step-client.nix @@ -29,7 +29,7 @@ ${principalArgs} \ --provisioner "${cfg.provisioner}" \ --provisioner-password-file "${config.sops.secrets."janus/admin_jwk".path}" \ - "${firstPrincipal}" "${config.ssh.IdentityFile}.pub" + "${firstPrincipal}" "${config.ssh.identityFile}.pub" '') ]; }; diff --git a/modules/services/ssh.nix b/modules/services/ssh.nix index 0653589..bec4052 100644 --- a/modules/services/ssh.nix +++ b/modules/services/ssh.nix @@ -32,6 +32,7 @@ in }; config = { + cfg.certificates = lib.mkDefault true; services.openssh = { enable = true; # require public key authentication for better security @@ -65,52 +66,56 @@ in }; }; - flake.modules.homeManager.ssh = { pkgs, config, lib, ... }: + flake.modules.homeManager.ssh = { config, pkgs, lib, ... }: + let + cfg = config.ssh; + configDir = "${config.home.homeDirectory}/.ssh"; + identityFile = cfg.identityFile; + publicKeyFile = "${identityFile}.pub"; + certificateFile = "${identityFile}-cert.pub"; + in { - options.ssh = { - IdentityFile = lib.mkOption { + options.ssh = with lib; { + identityFile = mkOption { # Intentionally not using a path type here because that will end up with the private key getting copied into the store - type = lib.types.str; + type = types.str; default = "${config.home.homeDirectory}/.ssh/id_ed25519"; description = "Path to the SSH identity file."; }; certificates = { - enable = lib.mkEnableOption "Enable SSH user certificates"; - # sshCertProvisioner = lib.mkOption { - # type = lib.types.str; - # default = "admin"; - # }; + enable = mkEnableOption "Enable SSH client certificates"; }; - knownHostsFile = lib.mkOption { - type = lib.types.str; - default = "${config.home.homeDirectory}/.ssh/known_hosts"; + knownHostsFile = mkOption { + type = types.str; + default = "${configDir}/known_hosts"; + }; + + knownHosts = mkOption { + description = ""; + type = types.listOf types.str; + default = [ ]; }; matchSets = { - appdaemon = lib.mkEnableOption "Enable AppDaemon SSH targets"; - certs = lib.mkEnableOption "Enable Janus and Soteria SSH targets"; - homelab = lib.mkEnableOption "Enable various Homelab targets"; - dev = lib.mkEnableOption "Enable development targets"; + appdaemon = mkEnableOption "Enable AppDaemon SSH targets"; + certs = mkEnableOption "Enable Janus and Soteria SSH targets"; + homelab = mkEnableOption "Enable various Homelab targets"; + dev = mkEnableOption "Enable development targets"; }; }; # All this stuff has to be wrapped in a config attribute because of the presence of the options here? config = let - cfg = config.ssh; - identityFile = cfg.IdentityFile; - publicKeyFile = "${identityFile}.pub"; - certificateFile = "${identityFile}-cert.pub"; provisionerPasswordPath = config.sops.secrets."janus/admin_jwk".path; in { home.file.".ssh/known_hosts" = { text = lib.concatStringsSep "\n" ( - [ - "fded:fb16:653e:25da:be24:11ff:fea0:753f ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ9ZqiWPrCwHjxFCiu0lT4rlQs7KyMapxKJQQ5PJP1eh" + cfg.knownHosts ++ lib.optionals cfg.certificates.enable [ + "@cert-authority 192.168.1.* ${sshHostCAPubKey}" + "@cert-authority *.john-stream.com ${sshHostCAPubKey}" ] - ++ (lib.optional cfg.certificates.enable "@cert-authority 192.168.1.* ${sshHostCAPubKey}") - ++ (lib.optional cfg.certificates.enable "@cert-authority *.john-stream.com ${sshHostCAPubKey}") ); }; @@ -119,27 +124,29 @@ in enableDefaultConfig = false; extraConfig = '' SetEnv TERM="xterm-256color" - IdentityAgent ~/.1password/agent.sock ''; matchBlocks = lib.mkMerge [ { - "*" = { - user = "john"; + "*" = lib.mkMerge [ + { + user = "john"; - compression = false; - serverAliveInterval = 0; - serverAliveCountMax = 3; + compression = false; + serverAliveInterval = 0; + serverAliveCountMax = 3; - identitiesOnly = true; - inherit identityFile certificateFile; + identitiesOnly = true; + inherit identityFile; - hashKnownHosts = false; - userKnownHostsFile = cfg.knownHostsFile; + hashKnownHosts = false; + userKnownHostsFile = cfg.knownHostsFile; - addKeysToAgent = "yes"; - forwardAgent = false; - }; + addKeysToAgent = "yes"; + forwardAgent = false; + } + (lib.mkIf cfg.certificates.enable { inherit certificateFile; }) + ]; } (lib.mkIf cfg.matchSets.appdaemon { "appdaemon" = {