SSH keys in the TPM

#| file: modules/nixos/desktop/ssh-tpm.nix
{
  lib,
  config,
  pkgs,
  ...
}:
let
  cfg = config.mjm.desktop;
in
{
  config = lib.mkIf (cfg.enable && config.security.tpm2.enable) {
    <<config>>
  };
}

On desktop machines that have a TPM, I like to use it for SSH keys using ssh-tpm-agent. So far, I've found this to be one of the nicer SSH key experiences. On a machine without it, I'll use a YubiKey instead, but it's not quite as nice of an experience.

users.users.mjm.extraGroups = [ config.security.tpm2.tssGroup ];

Users that need to access the TPM need to be in the appropriate group, so I add my user to that group if I'm going to be using ssh-tpm-agent.

systemd.user.sockets.ssh-tpm-agent = {
  wantedBy = [ "sockets.target" ];
  description = "SSH TPM agent socket";
  documentation = [
    "man:ssh-agent(1)"
    "man:ssh-add(1)"
    "man:ssh(1)"
  ];

  socketConfig = {
    ListenStream = "%t/ssh-tpm-agent.sock";
    SocketMode = "0600";
  };
};

The ssh-tpm-agent runs as a socket-activated user unit in systemd, so it will be available for any user who wants to use it and tries to communicate with its socket.

systemd.user.services.ssh-tpm-agent = {
  requires = [ "ssh-tpm-agent.socket" ];
  description = "ssh-tpm-agent service";
  documentation = [
    "man:ssh-agent(1)"
    "man:ssh-add(1)"
    "man:ssh(1)"
  ];

  unitConfig.ConditionEnvironment = [ "!SSH_AGENT_PID" ];

  environment.SSH_TPM_AUTH_SOCK = "%t/ssh-tpm-agent.sock";

  serviceConfig = {
    Type = "simple";
    ExecStart = lib.getExe pkgs.ssh-tpm-agent;
    SuccessExitStatus = 2;
  };
};

The service only runs as needed by someone trying to use it. The configuration is largely copied from the upstream project's unit files. Since the agent is running as a user unit, it should get all the necessary environment variables to be able to proxy to the normal SSH agent and ask for passwords using a GUI.

environment.systemPackages = [ pkgs.ssh-tpm-agent ];

The ssh-tpm-agent can mostly be interacted with like a normal SSH agent, but generating a key does require a special command it provides, so it's installed as a system package for that reason.

Proxy Information
Original URL
gemini://midna.dev/homelab/modules/nixos/desktop/ssh-tpm.gmi
Status Code
Success (20)
Meta
text/gemini;lang=en-US
Capsule Response Time
21.140038 milliseconds
Gemini-to-HTML Time
0.154916 milliseconds

This content has been proxied by September (UNKNO).