Skip to content

Instantly share code, notes, and snippets.

@frobware
Last active January 2, 2026 12:23
Show Gist options
  • Select an option

  • Save frobware/3eab824901e89bfe518d22abef86c763 to your computer and use it in GitHub Desktop.

Select an option

Save frobware/3eab824901e89bfe518d22abef86c763 to your computer and use it in GitHub Desktop.
TPM2-backed SSH Keys on NixOS with tpm2-pkcs11

TPM2-backed SSH Keys on NixOS

This describes how I set up TPM2 hardware-backed SSH keys using tpm2-pkcs11 on NixOS. Keys are generated inside the TPM and cannot be extracted, providing hardware-bound authentication.

Overview

  • Uses the kernel resource manager (/dev/tpmrm0) directly—no tpm2-abrmd daemon needed
  • Uses the esysdb backend instead of FAPI for simpler configuration
  • Integrates with pass for PIN storage (non-interactive operation)
  • Provides helper scripts for key management
  • Sets up a systemd user service for ssh-agent with the TPM2 PKCS#11 provider whitelisted

Helper Scripts

After enabling the module, these commands are available:

Command Description
ssh-tpm-keygen <label> [algorithm] Create a new key in the TPM
ssh-tpm-list Show public keys from the TPM
ssh-tpm-delkey <label> Remove a key from the TPM
ssh-tpm-load Load TPM keys into ssh-agent
ssh-tpm-unload Unload TPM keys from ssh-agent

Supported algorithms: ecc256 (default), ecc384, rsa2048, rsa3072, rsa4096

Initial Setup

1. Store your PIN in pass

pass insert tpm2/ssh-pin

2. Initialise the TPM2 PKCS#11 token

tpm2_ptool init --path ~/.local/share/tpm2-pkcs11
tpm2_ptool addtoken \
  --path ~/.local/share/tpm2-pkcs11 \
  --label ssh \
  --sopin <your-so-pin> \
  --userpin $(pass show tpm2/ssh-pin | head -1)

3. Generate a key

ssh-tpm-keygen my-tpm-key ecc256

This outputs the public key in OpenSSH format—add it to your ~/.ssh/authorized_keys or GitHub/GitLab.

4. Load keys into the agent

ssh-tpm-load
ssh-add -l   # verify

Environment Variables

The module sets these automatically:

TPM2_PKCS11_STORE = "~/.local/share/tpm2-pkcs11";
TPM2_PKCS11_BACKEND = "esysdb";
TPM2_PKCS11_LOG_LEVEL = "1";
TSS2_LOG = "fapi+NONE";
TSS2_TCTI = "device:/dev/tpmrm0";

NixOS System Requirements

# Enable TPM2
security.tpm2.enable = true;
security.tpm2.abrmd.enable = false;  # using kernel resource manager directly

# Add user to tss group for /dev/tpmrm0 access
users.users.youruser.extraGroups = [ "tss" ];

# System-wide environment (for ssh-pkcs11-helper)
environment.variables = {
  TPM2_PKCS11_BACKEND = "esysdb";
  TSS2_LOG = "fapi+NONE";
  TSS2_TCTI = "device:/dev/tpmrm0";
};

Commits

Commit 1: Add TPM2 PKCS#11 SSH key support

commit 0a13efce428fb3421a6e61e713c4dc5b4f56f5df
Author: Andrew McDermott <aim@frobware.com>
Date:   Sat Dec 27 19:57:27 2025 +0000

    Add TPM2 PKCS#11 SSH key support

    Introduce a home-manager module for TPM2-backed SSH keys using the
    tpm2-pkcs11 library. Keys are generated inside the TPM and cannot be
    extracted, providing hardware-bound authentication.

    Helper scripts:
    - ssh-tpm-keygen: create keys in TPM
    - ssh-tpm-list: show public keys
    - ssh-tpm-delkey: remove keys
    - ssh-tpm-load/unload: manage ssh-agent PKCS#11 provider

    The module creates a systemd user service running ssh-agent with the
    TPM2 PKCS#11 provider whitelisted. PIN is retrieved from pass
    (tpm2/ssh-pin) for non-interactive operation.

    Uses the kernel resource manager (/dev/tpmrm0) directly, avoiding the
    need for tpm2-abrmd. The esysdb backend is used instead of FAPI for
    simpler configuration.

Commit 2: Set TPM2 environment variables system-wide

commit aba7cc1f1d509ec4721fd3f9a923550b01c9584c
Author: Andrew McDermott <aim@frobware.com>
Date:   Sat Dec 27 20:02:54 2025 +0000

    Set TPM2 environment variables system-wide

    Move TPM2 PKCS#11 configuration to system environment so that
    ssh-pkcs11-helper inherits them. This suppresses the FAPI backend
    warnings that appeared during SSH operations using PKCS11Provider.

The Home Manager Module

The full module (home/configs/tpm2.nix):

{ config, lib, pkgs, ... }:

# TPM2 ssh-agent configuration with PKCS#11 support
#
# This creates a systemd user service for ssh-agent with the TPM2
# PKCS#11 provider whitelisted via the -P flag.
#
# Requirements:
# - TPM2 must be enabled at system level
# - User must be in the 'tss' group (for /dev/tpmrm0 access)
#
# Uses the kernel resource manager (/dev/tpmrm0) directly, no abrmd needed.
#
# Usage after enabling:
#   ssh-add -s ${pkgs.tpm2-pkcs11}/lib/libtpm2_pkcs11.so
#   ssh-keygen -D ${pkgs.tpm2-pkcs11}/lib/libtpm2_pkcs11.so  # export public key

with lib;
let
  cfg = config.frobware.configs.tpm2;
  gpgAgentCfg = config.frobware.configs.gpg-agent;
  sshAgentSocketDir = "${config.home.homeDirectory}/.ssh";
  sshAgentSocket = "${sshAgentSocketDir}/agent.sock";
in
{
  options.frobware.configs.tpm2 = {
    enable = mkEnableOption "TPM2 PKCS#11 configuration";

    enableSshAgent = mkOption {
      type = types.bool;
      default = true;
      description = "Enable ssh-agent with TPM2 PKCS#11 support.";
    };
  };

  config = mkIf cfg.enable {
    assertions = [
      {
        assertion = !(cfg.enableSshAgent && gpgAgentCfg.enable && gpgAgentCfg.enableSshSupport);
        message = "tpm2.enableSshAgent and gpg-agent.enableSshSupport are mutually exclusive. Both set SSH_AUTH_SOCK.";
      }
    ];
    home.packages = [
      pkgs.tpm2-pkcs11
      pkgs.tpm2-tools
      pkgs.yq-go

      # Helper script to create a new TPM SSH key
      (pkgs.writeShellScriptBin "ssh-tpm-keygen" ''
        set -e

        LABEL="''${1:-}"
        ALGORITHM="''${2:-ecc256}"

        if [ -z "$LABEL" ]; then
          echo "Usage: ssh-tpm-keygen <label> [algorithm]" >&2
          echo "Algorithms: ecc256 (default), ecc384, rsa2048, rsa3072, rsa4096" >&2
          exit 1
        fi

        case "$ALGORITHM" in
          ecc256|ecc) ALGORITHM="ecc256" ;;
          ecc384) ALGORITHM="ecc384" ;;
          rsa2048|rsa) ALGORITHM="rsa2048" ;;
          rsa3072) ALGORITHM="rsa3072" ;;
          rsa4096) ALGORITHM="rsa4096" ;;
          *) echo "Unknown algorithm: $ALGORITHM" >&2; exit 1 ;;
        esac

        PIN=$(pass show tpm2/ssh-pin 2>/dev/null | head -1)
        if [ -z "$PIN" ]; then
          echo "Error: Could not retrieve PIN from pass (tpm2/ssh-pin)" >&2
          exit 1
        fi

        tpm2_ptool addkey \
          --path "$TPM2_PKCS11_STORE" \
          --label ssh \
          --userpin "$PIN" \
          --key-label "$LABEL" \
          --algorithm "$ALGORITHM" >/dev/null

        ssh-keygen -D "$TPM2_PKCS11_LIB" 2>/dev/null | grep "$LABEL"
      '')

      # Helper script to list TPM SSH public keys
      (pkgs.writeShellScriptBin "ssh-tpm-list" ''
        OBJECTS=$(tpm2_ptool listobjects --path "$TPM2_PKCS11_STORE" --label ssh 2>/dev/null)
        if [ -z "$OBJECTS" ]; then
          exit 0
        fi

        askpass=$(mktemp)
        trap "rm -f $askpass" EXIT
        cat > "$askpass" << 'EOF'
#!/bin/sh
exec pass show tpm2/ssh-pin 2>/dev/null | head -1
EOF
        chmod +x "$askpass"

        SSH_ASKPASS="$askpass" SSH_ASKPASS_REQUIRE=force \
          ssh-keygen -D "$TPM2_PKCS11_LIB" 2>/dev/null
      '')

      # Helper script to delete a TPM SSH key
      (pkgs.writeShellScriptBin "ssh-tpm-delkey" ''
        set -e

        LABEL="''${1:-}"

        if [ -z "$LABEL" ]; then
          echo "Usage: ssh-tpm-delkey <label>" >&2
          exit 1
        fi

        OBJECTS=$(tpm2_ptool listobjects --path "$TPM2_PKCS11_STORE" --label ssh 2>/dev/null)
        IDS=$(echo "$OBJECTS" | ${pkgs.yq-go}/bin/yq -r ".[] | select(.CKA_LABEL == \"$LABEL\") | .id")

        if [ -z "$IDS" ]; then
          echo "Key not found: $LABEL" >&2
          exit 1
        fi

        for ID in $IDS; do
          tpm2_ptool objdel --path "$TPM2_PKCS11_STORE" "$ID" >/dev/null
        done
      '')

      # Helper script to load TPM SSH keys into agent using PIN from pass
      (pkgs.writeShellScriptBin "ssh-tpm-load" ''
        OBJECTS=$(tpm2_ptool listobjects --path "$TPM2_PKCS11_STORE" --label ssh 2>/dev/null)
        if [ -z "$OBJECTS" ]; then
          echo "No keys in TPM token" >&2
          exit 1
        fi

        ${pkgs.openssh}/bin/ssh-add -e ${pkgs.tpm2-pkcs11}/lib/libtpm2_pkcs11.so >/dev/null 2>&1 || true

        askpass=$(mktemp)
        trap "rm -f $askpass" EXIT
        cat > "$askpass" << 'EOF'
#!/bin/sh
exec pass show tpm2/ssh-pin 2>/dev/null | head -1
EOF
        chmod +x "$askpass"

        SSH_ASKPASS="$askpass" SSH_ASKPASS_REQUIRE=force \
          ${pkgs.openssh}/bin/ssh-add -s ${pkgs.tpm2-pkcs11}/lib/libtpm2_pkcs11.so >/dev/null
      '')

      # Helper script to unload TPM SSH keys from agent
      (pkgs.writeShellScriptBin "ssh-tpm-unload" ''
        ${pkgs.openssh}/bin/ssh-add -e ${pkgs.tpm2-pkcs11}/lib/libtpm2_pkcs11.so >/dev/null 2>&1 || true
      '')
    ];

    # TPM2 environment variables
    home.sessionVariables = {
      TPM2_PKCS11_STORE = "${config.home.homeDirectory}/.local/share/tpm2-pkcs11";
      TPM2_PKCS11_LIB = "${pkgs.tpm2-pkcs11}/lib/libtpm2_pkcs11.so";
      TPM2_PKCS11_BACKEND = "esysdb";
      TPM2_PKCS11_LOG_LEVEL = "1";
      TSS2_LOG = "fapi+NONE";
      TSS2_TCTI = "device:/dev/tpmrm0";
    } // optionalAttrs cfg.enableSshAgent {
      SSH_AUTH_SOCK = sshAgentSocket;
    };

    systemd.user.services.ssh-agent-tpm2 = mkIf cfg.enableSshAgent {
      Unit = {
        Description = "SSH Agent with TPM2 PKCS#11 support";
        Documentation = "man:ssh-agent(1)";
      };
      Install = {
        WantedBy = [ "default.target" ];
      };
      Service = {
        Type = "simple";
        Environment = [
          "TPM2_PKCS11_STORE=${config.home.homeDirectory}/.local/share/tpm2-pkcs11"
          "TPM2_PKCS11_BACKEND=esysdb"
          "TPM2_PKCS11_LOG_LEVEL=1"
          "TSS2_LOG=fapi+NONE"
          "TSS2_TCTI=device:/dev/tpmrm0"
        ];
        ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p ${sshAgentSocketDir}";
        ExecStart = "${pkgs.openssh}/bin/ssh-agent -D -a ${sshAgentSocket} -P '${pkgs.tpm2-pkcs11}/lib/*.so*'";
        Restart = "on-failure";
      };
    };
  };
}

Enabling in Home Manager

{
  frobware.configs = {
    gpg-agent.enable = true;
    gpg-agent.enableSshSupport = false;  # mutually exclusive with TPM2 ssh-agent
    tpm2.enable = true;
  };
}
commit 0a13efce428fb3421a6e61e713c4dc5b4f56f5df
Author: Andrew McDermott <aim@frobware.com>
Date: Sat Dec 27 19:57:27 2025 +0000
Add TPM2 PKCS#11 SSH key support
Introduce a home-manager module for TPM2-backed SSH keys using the
tpm2-pkcs11 library. Keys are generated inside the TPM and cannot be
extracted, providing hardware-bound authentication.
Helper scripts:
- ssh-tpm-keygen: create keys in TPM
- ssh-tpm-list: show public keys
- ssh-tpm-delkey: remove keys
- ssh-tpm-load/unload: manage ssh-agent PKCS#11 provider
The module creates a systemd user service running ssh-agent with the
TPM2 PKCS#11 provider whitelisted. PIN is retrieved from pass
(tpm2/ssh-pin) for non-interactive operation.
Uses the kernel resource manager (/dev/tpmrm0) directly, avoiding the
need for tpm2-abrmd. The esysdb backend is used instead of FAPI for
simpler configuration.
diff --git a/home/configs/default.nix b/home/configs/default.nix
index 146d4899..fdd53d8a 100644
--- a/home/configs/default.nix
+++ b/home/configs/default.nix
@@ -53,6 +53,7 @@
./ssh.nix
./terminfo.nix
./tmux
+ ./tpm2.nix
./wezterm.nix
./xdg.nix
./xresources.nix
diff --git a/home/configs/tpm2.nix b/home/configs/tpm2.nix
new file mode 100644
index 00000000..0c083d14
--- /dev/null
+++ b/home/configs/tpm2.nix
@@ -0,0 +1,213 @@
+{ config, lib, pkgs, ... }:
+
+# TPM2 ssh-agent configuration with PKCS#11 support
+#
+# This creates a systemd user service for ssh-agent with the TPM2
+# PKCS#11 provider whitelisted via the -P flag.
+#
+# Requirements:
+# - TPM2 must be enabled at system level
+# - User must be in the 'tss' group (for /dev/tpmrm0 access)
+#
+# Uses the kernel resource manager (/dev/tpmrm0) directly, no abrmd needed.
+#
+# Usage after enabling:
+# ssh-add -s ${pkgs.tpm2-pkcs11}/lib/libtpm2_pkcs11.so
+# ssh-keygen -D ${pkgs.tpm2-pkcs11}/lib/libtpm2_pkcs11.so # export public key
+
+with lib;
+let
+ cfg = config.frobware.configs.tpm2;
+ gpgAgentCfg = config.frobware.configs.gpg-agent;
+ sshAgentSocketDir = "${config.home.homeDirectory}/.ssh";
+ sshAgentSocket = "${sshAgentSocketDir}/agent.sock";
+in
+{
+ options.frobware.configs.tpm2 = {
+ enable = mkEnableOption "TPM2 PKCS#11 configuration";
+
+ enableSshAgent = mkOption {
+ type = types.bool;
+ default = true;
+ description = "Enable ssh-agent with TPM2 PKCS#11 support.";
+ };
+ };
+
+ config = mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = !(cfg.enableSshAgent && gpgAgentCfg.enable && gpgAgentCfg.enableSshSupport);
+ message = "tpm2.enableSshAgent and gpg-agent.enableSshSupport are mutually exclusive. Both set SSH_AUTH_SOCK.";
+ }
+ ];
+ home.packages = [
+ pkgs.tpm2-pkcs11
+ pkgs.tpm2-tools
+ pkgs.yq-go
+
+ # Helper script to create a new TPM SSH key
+ (pkgs.writeShellScriptBin "ssh-tpm-keygen" ''
+ set -e
+
+ LABEL="''${1:-}"
+ ALGORITHM="''${2:-ecc256}"
+
+ if [ -z "$LABEL" ]; then
+ echo "Usage: ssh-tpm-keygen <label> [algorithm]" >&2
+ echo "Algorithms: ecc256 (default), ecc384, rsa2048, rsa3072, rsa4096" >&2
+ exit 1
+ fi
+
+ case "$ALGORITHM" in
+ ecc256|ecc) ALGORITHM="ecc256" ;;
+ ecc384) ALGORITHM="ecc384" ;;
+ rsa2048|rsa) ALGORITHM="rsa2048" ;;
+ rsa3072) ALGORITHM="rsa3072" ;;
+ rsa4096) ALGORITHM="rsa4096" ;;
+ *) echo "Unknown algorithm: $ALGORITHM" >&2; exit 1 ;;
+ esac
+
+ PIN=$(pass show tpm2/ssh-pin 2>/dev/null | head -1)
+ if [ -z "$PIN" ]; then
+ echo "Error: Could not retrieve PIN from pass (tpm2/ssh-pin)" >&2
+ exit 1
+ fi
+
+ tpm2_ptool addkey \
+ --path "$TPM2_PKCS11_STORE" \
+ --label ssh \
+ --userpin "$PIN" \
+ --key-label "$LABEL" \
+ --algorithm "$ALGORITHM" >/dev/null
+
+ ssh-keygen -D "$TPM2_PKCS11_LIB" 2>/dev/null | grep "$LABEL"
+ '')
+
+ # Helper script to list TPM SSH public keys
+ (pkgs.writeShellScriptBin "ssh-tpm-list" ''
+ OBJECTS=$(tpm2_ptool listobjects --path "$TPM2_PKCS11_STORE" --label ssh 2>/dev/null)
+ if [ -z "$OBJECTS" ]; then
+ exit 0
+ fi
+
+ askpass=$(mktemp)
+ trap "rm -f $askpass" EXIT
+ cat > "$askpass" << 'EOF'
+#!/bin/sh
+exec pass show tpm2/ssh-pin 2>/dev/null | head -1
+EOF
+ chmod +x "$askpass"
+
+ SSH_ASKPASS="$askpass" SSH_ASKPASS_REQUIRE=force \
+ ssh-keygen -D "$TPM2_PKCS11_LIB" 2>/dev/null
+ '')
+
+ # Helper script to delete a TPM SSH key
+ (pkgs.writeShellScriptBin "ssh-tpm-delkey" ''
+ set -e
+
+ LABEL="''${1:-}"
+
+ if [ -z "$LABEL" ]; then
+ echo "Usage: ssh-tpm-delkey <label>" >&2
+ exit 1
+ fi
+
+ OBJECTS=$(tpm2_ptool listobjects --path "$TPM2_PKCS11_STORE" --label ssh 2>/dev/null)
+ IDS=$(echo "$OBJECTS" | ${pkgs.yq-go}/bin/yq -r ".[] | select(.CKA_LABEL == \"$LABEL\") | .id")
+
+ if [ -z "$IDS" ]; then
+ echo "Key not found: $LABEL" >&2
+ exit 1
+ fi
+
+ for ID in $IDS; do
+ tpm2_ptool objdel --path "$TPM2_PKCS11_STORE" "$ID" >/dev/null
+ done
+ '')
+
+ # Helper script to load TPM SSH keys into agent using PIN from pass
+ (pkgs.writeShellScriptBin "ssh-tpm-load" ''
+ OBJECTS=$(tpm2_ptool listobjects --path "$TPM2_PKCS11_STORE" --label ssh 2>/dev/null)
+ if [ -z "$OBJECTS" ]; then
+ echo "No keys in TPM token" >&2
+ exit 1
+ fi
+
+ ${pkgs.openssh}/bin/ssh-add -e ${pkgs.tpm2-pkcs11}/lib/libtpm2_pkcs11.so >/dev/null 2>&1 || true
+
+ askpass=$(mktemp)
+ trap "rm -f $askpass" EXIT
+ cat > "$askpass" << 'EOF'
+#!/bin/sh
+exec pass show tpm2/ssh-pin 2>/dev/null | head -1
+EOF
+ chmod +x "$askpass"
+
+ SSH_ASKPASS="$askpass" SSH_ASKPASS_REQUIRE=force \
+ ${pkgs.openssh}/bin/ssh-add -s ${pkgs.tpm2-pkcs11}/lib/libtpm2_pkcs11.so >/dev/null
+ '')
+
+ # Helper script to unload TPM SSH keys from agent
+ (pkgs.writeShellScriptBin "ssh-tpm-unload" ''
+ ${pkgs.openssh}/bin/ssh-add -e ${pkgs.tpm2-pkcs11}/lib/libtpm2_pkcs11.so >/dev/null 2>&1 || true
+ '')
+ ];
+
+ # TPM2 environment variables:
+ #
+ # TPM2_PKCS11_STORE - Directory containing the tpm2-pkcs11 database
+ # (tokens, keys). Created by `tpm2_ptool init`.
+ #
+ # TPM2_PKCS11_LIB - Path to the PKCS#11 provider library. Used by
+ # ssh-keygen -D and ssh-add -s to interact with TPM keys.
+ #
+ # TPM2_PKCS11_BACKEND - Database backend: "esysdb" uses SQLite with
+ # ESYS serialised objects (recommended), "fapi" uses the TPM2 Feature
+ # API. ESYS is simpler and avoids FAPI configuration requirements.
+ #
+ # TPM2_PKCS11_LOG_LEVEL - Logging verbosity: 0=none, 1=errors,
+ # 2=warnings, 3=info, 4=debug. Level 1 shows errors without noise.
+ #
+ # TSS2_LOG - Controls TSS2 library logging. "fapi+NONE" suppresses
+ # FAPI warnings when using the esysdb backend.
+ #
+ # TSS2_TCTI - TPM Command Transmission Interface. "device:/dev/tpmrm0"
+ # uses the kernel resource manager directly, avoiding the need for
+ # the tpm2-abrmd daemon.
+ home.sessionVariables = {
+ TPM2_PKCS11_STORE = "${config.home.homeDirectory}/.local/share/tpm2-pkcs11";
+ TPM2_PKCS11_LIB = "${pkgs.tpm2-pkcs11}/lib/libtpm2_pkcs11.so";
+ TPM2_PKCS11_BACKEND = "esysdb";
+ TPM2_PKCS11_LOG_LEVEL = "1";
+ TSS2_LOG = "fapi+NONE";
+ TSS2_TCTI = "device:/dev/tpmrm0";
+ } // optionalAttrs cfg.enableSshAgent {
+ SSH_AUTH_SOCK = sshAgentSocket;
+ };
+
+ systemd.user.services.ssh-agent-tpm2 = mkIf cfg.enableSshAgent {
+ Unit = {
+ Description = "SSH Agent with TPM2 PKCS#11 support";
+ Documentation = "man:ssh-agent(1)";
+ };
+ Install = {
+ WantedBy = [ "default.target" ];
+ };
+ Service = {
+ Type = "simple";
+ Environment = [
+ "TPM2_PKCS11_STORE=${config.home.homeDirectory}/.local/share/tpm2-pkcs11"
+ "TPM2_PKCS11_BACKEND=esysdb"
+ "TPM2_PKCS11_LOG_LEVEL=1"
+ "TSS2_LOG=fapi+NONE"
+ "TSS2_TCTI=device:/dev/tpmrm0"
+ ];
+ ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p ${sshAgentSocketDir}";
+ ExecStart = "${pkgs.openssh}/bin/ssh-agent -D -a ${sshAgentSocket} -P '${pkgs.tpm2-pkcs11}/lib/*.so*'";
+ Restart = "on-failure";
+ };
+ };
+
+ };
+}
diff --git a/home/hosts/spicy-hm.nix b/home/hosts/spicy-hm.nix
index d12eae78..2e54fe86 100644
--- a/home/hosts/spicy-hm.nix
+++ b/home/hosts/spicy-hm.nix
@@ -64,6 +64,8 @@ in
gnome-extensions.alacrittyLauncherBinary = "nixGLIntel alacritty";
gnome-extensions.enable = true;
gpg-agent.enable = true;
+ gpg-agent.enableSshSupport = false;
+ tpm2.enable = true;
jetbrains-tools.enable = false;
kubedev.enable = true;
openshift-haproxy-versions.enable = false;
diff --git a/home/hosts/spicy.nix b/home/hosts/spicy.nix
index d3d34a65..fb3bfd88 100644
--- a/home/hosts/spicy.nix
+++ b/home/hosts/spicy.nix
@@ -14,6 +14,8 @@
gnome-desktop.enable = true;
google-chrome.enable = true;
gpg-agent.enable = true;
+ gpg-agent.enableSshSupport = false;
+ tpm2.enable = true;
jetbrains-tools.enable = true;
kerberos.enable = true;
mail.enable = true;
diff --git a/nixos/hosts/x86_64-linux/spicy/configuration.nix b/nixos/hosts/x86_64-linux/spicy/configuration.nix
index 552025ee..3afc0a9b 100644
--- a/nixos/hosts/x86_64-linux/spicy/configuration.nix
+++ b/nixos/hosts/x86_64-linux/spicy/configuration.nix
@@ -75,8 +75,16 @@ in
pkgs.vdpauinfo
pkgs.vim
pkgs.wget
+
+ pkgs.tpm2-tools
+ pkgs.tpm2-pkcs11
];
+ # Canonical path for tpm2-pkcs11 library
+ # Allows: ssh-keygen -D /etc/pkcs11/libtpm2_pkcs11.so
+ environment.etc."pkcs11/libtpm2_pkcs11.so".source =
+ "${pkgs.tpm2-pkcs11}/lib/libtpm2_pkcs11.so";
+
fileSystems."/sys/kernel/tracing" = {
device = "tracefs";
fsType = "tracefs";
@@ -205,6 +213,10 @@ in
users.users.aim = {
isNormalUser = true;
- extraGroups = [ "wireshark" ];
+ extraGroups = [ "tss" "wireshark" ];
};
+
+ security.tpm2.enable = true;
+ # Using kernel resource manager (/dev/tpmrm0) directly, abrmd not needed
+ security.tpm2.abrmd.enable = false;
}
commit aba7cc1f1d509ec4721fd3f9a923550b01c9584c
Author: Andrew McDermott <aim@frobware.com>
Date: Sat Dec 27 20:02:54 2025 +0000
Set TPM2 environment variables system-wide
Move TPM2 PKCS#11 configuration to system environment so that
ssh-pkcs11-helper inherits them. This suppresses the FAPI backend
warnings that appeared during SSH operations using PKCS11Provider.
diff --git a/nixos/hosts/x86_64-linux/spicy/configuration.nix b/nixos/hosts/x86_64-linux/spicy/configuration.nix
index 3afc0a9b..79678fa0 100644
--- a/nixos/hosts/x86_64-linux/spicy/configuration.nix
+++ b/nixos/hosts/x86_64-linux/spicy/configuration.nix
@@ -61,6 +61,11 @@ in
environment.variables = {
VDPAU_DRIVER = lib.mkIf config.hardware.graphics.enable (lib.mkDefault "va_gl");
+
+ # TPM2 PKCS#11 configuration - system-wide so ssh-pkcs11-helper inherits them
+ TPM2_PKCS11_BACKEND = "esysdb";
+ TSS2_LOG = "fapi+NONE";
+ TSS2_TCTI = "device:/dev/tpmrm0";
};
environment.systemPackages = [
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment