Commit e4e7527c8af6
Changed files (4)
home/common/shell/git.nix
@@ -31,8 +31,8 @@ let
sshkeyPerHost = {
# FIDO2 resident key (ssh:signing) - no touch required for signing
kyushu = "${pkgs.writeText "yubikey5-fido2-signing" "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIGF/BoGqFc5/pM40bF/2UhWzRFaDmS4hJ45VtpXjUh36AAAAC3NzaDpzaWduaW5n"}";
- # Okinawa uses a regular ed25519 key (no yubikey dependency)
- okinawa = "${pkgs.writeText "okinawa-ed25519" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILfT4qPT4nH+K6wfhnM4JCtflrUEIXPAYpqdN7W7TOBo vincent@okinawa-passage"}";
+ # Okinawa: TPM-sealed ecdsa key via ssh-tpm-agent (machine-bound, no touch)
+ okinawa = "${pkgs.writeText "okinawa-tpm" "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBODwU2/sE+S51ShfL8t+QA9IMcVuQL+VLYuENUc5VDVD4AVoVj97BggowbAhtqDW6hdc0S3XSVrZs+aOSd9ukbg= vincent@okinawa-tpm"}";
# aomi (Fedora): TPM-sealed ecdsa key via ssh-tpm-agent (machine-bound, no touch)
aomi = "${pkgs.writeText "aomi-tpm" "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGEL1A++UUsFnGmnrIR8S6A8IUFkR5WyxDPol2bs02TY0O+sWOPJFJZIAKqcWVSUIkxRoktUBMRe0mMZyiHa3jw= vdemeest@aomi-tpm"}";
};
@@ -48,7 +48,7 @@ let
allowedSigners = ''
vincent@aomi ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGEL1A++UUsFnGmnrIR8S6A8IUFkR5WyxDPol2bs02TY0O+sWOPJFJZIAKqcWVSUIkxRoktUBMRe0mMZyiHa3jw=
vincent@kyushu sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIGF/BoGqFc5/pM40bF/2UhWzRFaDmS4hJ45VtpXjUh36AAAAC3NzaDpzaWduaW5n
- vincent@okinawa ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILfT4qPT4nH+K6wfhnM4JCtflrUEIXPAYpqdN7W7TOBo
+ vincent@okinawa ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBODwU2/sE+S51ShfL8t+QA9IMcVuQL+VLYuENUc5VDVD4AVoVj97BggowbAhtqDW6hdc0S3XSVrZs+aOSd9ukbg=
'';
in
{
home/common/shell/openssh.nix
@@ -13,6 +13,7 @@ let
isAomi = hostname == "aomi";
isAion = hostname == "aion";
isOkinawa = hostname == "okinawa";
+ hasTPMAgent = isAomi || isOkinawa;
in
{
home.packages =
@@ -24,17 +25,19 @@ in
# so FIDO2 sk-key PIN prompts work with the home-manager ssh-agent.
++ lib.optionals isAomi [
openssh-askpass
+ ]
+ ++ lib.optionals hasTPMAgent [
ssh-tpm-agent
];
- # NixOS hosts use programs.ssh.startAgent (proper SSH_ASKPASS for FIDO2).
# aomi has no NixOS layer, so run a home-manager systemd user ssh-agent.
+ # NixOS hosts (okinawa) use programs.ssh.startAgent instead.
services.ssh-agent.enable = isAomi;
# aomi: ssh-tpm-agent is the *front* agent. It serves the machine-bound TPM
# SSH key and proxies (-A) the FIDO2 ssh-agent above for fallback, so a single
# socket (SSH_AUTH_SOCK) exposes both the TPM key and all FIDO2 sk-keys.
- systemd.user.sockets.ssh-tpm-agent = lib.mkIf isAomi {
+ systemd.user.sockets.ssh-tpm-agent = lib.mkIf hasTPMAgent {
Unit.Description = "SSH TPM agent socket";
Socket = {
ListenStream = "%t/ssh-tpm-agent.sock";
@@ -43,7 +46,7 @@ in
};
Install.WantedBy = [ "sockets.target" ];
};
- systemd.user.services.ssh-tpm-agent = lib.mkIf isAomi {
+ systemd.user.services.ssh-tpm-agent = lib.mkIf hasTPMAgent {
Unit = {
Description = "ssh-tpm-agent service";
Requires = [ "ssh-tpm-agent.socket" ];
@@ -62,7 +65,7 @@ in
# ssh-tpm-agent socket instead of the plain ssh-agent one. The original
# service runs dbus-update-activation-environment --systemd SSH_AUTH_SOCK
# which overwrites environment.d values in the systemd user manager env.
- systemd.user.services.set-SSH_AUTH_SOCK = lib.mkIf isAomi {
+ systemd.user.services.set-SSH_AUTH_SOCK = lib.mkIf hasTPMAgent {
Service.ExecStart = lib.mkForce (
pkgs.writeScript "set-SSH_AUTH_SOCK" ''
#!/bin/sh
@@ -74,13 +77,17 @@ in
);
};
- # FIDO2 sk-keys spawn ssh-sk-helper which needs an askpass for the PIN.
- home.sessionVariables = lib.mkIf isAomi {
- SSH_ASKPASS = "${pkgs.openssh-askpass}/libexec/gtk-ssh-askpass";
- SSH_ASKPASS_REQUIRE = "prefer";
- # Route ssh through the front ssh-tpm-agent (TPM key + proxied FIDO2 keys).
- SSH_AUTH_SOCK = lib.mkForce "$XDG_RUNTIME_DIR/ssh-tpm-agent.sock";
- };
+ # Route ssh through the front ssh-tpm-agent (TPM key + proxied FIDO2 keys).
+ home.sessionVariables = lib.mkIf hasTPMAgent (
+ {
+ SSH_AUTH_SOCK = lib.mkForce "$XDG_RUNTIME_DIR/ssh-tpm-agent.sock";
+ }
+ # aomi (Fedora) needs its own askpass; NixOS sets SSH_ASKPASS via programs.ssh.startAgent.
+ // lib.optionalAttrs isAomi {
+ SSH_ASKPASS = "${pkgs.openssh-askpass}/libexec/gtk-ssh-askpass";
+ SSH_ASKPASS_REQUIRE = "prefer";
+ }
+ );
# Override the sshAuthSock module's shell initialization so all shells
# (bash, zsh, fish) point at the TPM agent socket, not the plain ssh-agent.
@@ -91,13 +98,13 @@ in
# which activates the upstream module's config block and forces a read of
# `.bash`/`.fish`/`.nushell` (no defaults) -> eval failure on non-aomi hosts.
# On aomi, services.ssh-agent supplies fish/nushell; we only override bash.
- sshAuthSock.initialization = lib.mkIf isAomi {
+ sshAuthSock.initialization = lib.mkIf hasTPMAgent {
bash = lib.mkForce ''export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-tpm-agent.sock"'';
};
# GUI terminals spawned under niri inherit the systemd user manager
# environment, so set SSH_AUTH_SOCK there too via environment.d.
- xdg.configFile = lib.mkIf isAomi {
+ xdg.configFile = lib.mkIf hasTPMAgent {
"environment.d/95-ssh-auth-sock.conf".text = ''
SSH_AUTH_SOCK=''${XDG_RUNTIME_DIR}/ssh-tpm-agent.sock
'';
@@ -128,13 +135,28 @@ in
"192.168.1.*".identityFile = "~/.ssh/id_homelab_sk";
"10.100.0.*".identityFile = "~/.ssh/id_homelab_sk";
};
- # Okinawa uses a single FIDO2 key (id_ed25519_sk) for everything
+ # Okinawa: route forges through TPM key (like aomi), FIDO2 sk-key as fallback via agent proxy
okinawaOverrides = lib.optionalAttrs isOkinawa {
- "github.com".identityFile = "~/.ssh/id_ed25519_sk";
- "gitlab.com".identityFile = "~/.ssh/id_ed25519_sk";
- "codeberg.org".identityFile = "~/.ssh/id_ed25519_sk";
- "git.sr.ht".identityFile = "~/.ssh/id_ed25519_sk";
- "*.redhat.com".identityFile = "~/.ssh/id_ed25519_sk";
+ "github.com" = {
+ identityFile = "~/.ssh/id_tpm_ecdsa.pub";
+ identitiesOnly = true;
+ };
+ "gitlab.com" = {
+ identityFile = "~/.ssh/id_tpm_ecdsa.pub";
+ identitiesOnly = true;
+ };
+ "codeberg.org" = {
+ identityFile = "~/.ssh/id_tpm_ecdsa.pub";
+ identitiesOnly = true;
+ };
+ "git.sr.ht" = {
+ identityFile = "~/.ssh/id_tpm_ecdsa.pub";
+ identitiesOnly = true;
+ };
+ "*.redhat.com" = {
+ identityFile = "~/.ssh/id_tpm_ecdsa.pub";
+ identitiesOnly = true;
+ };
};
# Special case for aomi and okinawa: no FIDO2 homelab key, use regular ed25519
# Override all homelab machine entries (generated by libx.sshConfigs and shpool aliases)
systems/okinawa/home.nix
@@ -1,7 +1,6 @@
{
pkgs,
lib,
- config,
inputs,
system,
...
@@ -69,8 +68,7 @@ in
home.sessionVariables = {
LLAMA_ARG_FLASH_ATTN = "off";
LLAMA_ARG_MAIN_GPU = "0";
- # Use local SSH key for passage instead of YubiKey identity
- PASSAGE_IDENTITIES_FILE = pkgs.lib.mkForce "${config.home.homeDirectory}/.ssh/id_ed25519";
+ # Use TPM + Yubikey identities for passage (set in home/common/desktop/passage.nix)
};
# Use Vulkan variant for GPU-accelerated transcription (RX 6700S / RDNA2)
globals.nix
@@ -68,6 +68,14 @@ _: {
gated = "passage-pull";
};
};
+ # okinawa user key: TPM-sealed ecdsa via ssh-tpm-agent (machine-bound, no touch)
+ okinawa-tpm = {
+ key = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBODwU2/sE+S51ShfL8t+QA9IMcVuQL+VLYuENUc5VDVD4AVoVj97BggowbAhtqDW6hdc0S3XSVrZs+aOSd9ukbg= vincent@okinawa-tpm";
+ access = {
+ vincent.default = "trusted";
+ root.default = "trusted";
+ };
+ };
# aomi user key: TPM-sealed ecdsa via ssh-tpm-agent (machine-bound, no touch)
# Gated to git push+pull on carthage only.
aomi-tpm = {