Revert commits after 089e185bd8

This commit is contained in:
2026-06-25 15:54:09 +09:00
parent 5cb560f3d1
commit 93aba545ed
6 changed files with 69 additions and 448 deletions
+15 -54
View File
@@ -3,7 +3,6 @@
config,
...
}:
let
cfg = config.my.applications.ssh;
in
@@ -14,71 +13,33 @@ in
];
options.my.applications.ssh = {
enable = lib.mkEnableOption "OpenSSH client and agent configuration";
enable = lib.mkEnableOption "OpenSSH client";
defaultIdentityFiles = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [
"~/.ssh/id_ed25519"
];
description = ''
Default local SSH identity files.
These are used as the normal fallback identities when no agent key
is accepted, or when no forwarded agent is available.
'';
};
fidoIdentityFile = lib.mkOption {
defaultIdentityFile = lib.mkOption {
type = lib.types.str;
default = "~/.ssh/id_ed25519_sk_rk";
description = ''
Local FIDO2 resident-key SSH identity handle.
This file is only added to SSH identity candidates when a FIDO2
device is actually visible. Do not use file existence to decide
whether this key is usable.
'';
};
githubIdentityFiles = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = ''
Extra GitHub-specific SSH identity files.
Leave this empty if GitHub should use the normal agent, FIDO key,
and default identity fallback order.
'';
default = "~/.ssh/id_ed25519";
description = "Default SSH identity file";
};
addKeysToAgent = lib.mkOption {
type = lib.types.str;
default = "no";
example = "1h";
description = ''
Value for OpenSSH AddKeysToAgent.
Recommended default is "no" for this setup, because FIDO resident-key
handle files should not be added to the agent accidentally.
'';
description = "Add keys to SSH agent";
};
matchBlocks = lib.mkOption {
type = lib.types.attrsOf lib.types.anything;
type = lib.types.attrs;
default = { };
description = ''
Additional Home Manager OpenSSH settings blocks.
description = "SSH match blocks";
};
Use this for host-specific options such as ForwardAgent = true.
'';
example = lib.literalExpression ''
{
"proxmox-* *.home.arpa *.internal" = {
ForwardAgent = true;
};
}
'';
githubIdentityFiles = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [
"~/.ssh/id_ed25519_sk_rk"
"~/.ssh/id_ed25519"
];
description = "SSH identity files for GitHub (tried in order)";
};
};
+29 -234
View File
@@ -4,146 +4,9 @@
config,
...
}:
let
cfg = config.my.applications.ssh;
hmCfg = config.my.applications.ssh.homeManager;
shellPathExpr =
path:
if lib.hasPrefix "~/" path then
''"$HOME/${lib.removePrefix "~/" path}"''
else
lib.escapeShellArg path;
fidoIdentityExpr = shellPathExpr cfg.fidoIdentityFile;
hasFidoDevice = pkgs.writeShellScript "ssh-has-fido-device" ''
${pkgs.libfido2}/bin/fido2-token -L 2>/dev/null \
| ${pkgs.gnugrep}/bin/grep -q .
'';
sshYubikeyAgentSync = pkgs.writeShellApplication {
name = "ssh-yubikey-agent-sync";
runtimeInputs = with pkgs; [
openssh
libfido2
coreutils
gnugrep
gawk
];
text = ''
set -u
force=0
case "''${1:-}" in
"")
;;
"--force")
force=1
;;
*)
printf '%s\n' "usage: ssh-yubikey-agent-sync [--force]" >&2
exit 2
;;
esac
if [ -z "''${XDG_RUNTIME_DIR:-}" ]; then
exit 0
fi
export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent"
if [ ! -S "$SSH_AUTH_SOCK" ]; then
exit 0
fi
fido_identity=${fidoIdentityExpr}
fido_public_key="$fido_identity.pub"
state_dir="$XDG_RUNTIME_DIR/ssh-yubikey-agent-sync"
state_file="$state_dir/fido-device-state"
mkdir -p "$state_dir"
fido_present() {
fido2-token -L 2>/dev/null | grep -q .
}
fido_state() {
fido2-token -L 2>/dev/null | sha256sum | awk '{ print $1 }'
}
pub_fingerprint() {
[ -r "$1" ] || return 1
ssh-keygen -lf "$1" -E sha256 2>/dev/null | awk '{ print $2 }'
}
agent_has_public_key() {
public_key_file="$1"
fingerprint="$(pub_fingerprint "$public_key_file")" || return 1
ssh-add -l -E sha256 2>/dev/null \
| grep -Fq "$fingerprint"
}
remove_fido_from_agent() {
ssh-add -d "$fido_identity" >/dev/null 2>&1 || true
ssh-add -d "$fido_public_key" >/dev/null 2>&1 || true
}
add_fido_to_agent() {
[ -r "$fido_identity" ] || exit 0
[ -r "$fido_public_key" ] || exit 0
remove_fido_from_agent
ssh-add -q -t "''${SSH_YUBIKEY_AGENT_LIFETIME:-24h}" "$fido_identity" >/dev/null 2>&1 || exit 0
}
if fido_present; then
new_state="$(fido_state)"
old_state="$(cat "$state_file" 2>/dev/null || true)"
if [ "$force" -eq 1 ] \
|| ! agent_has_public_key "$fido_public_key" \
|| [ "$new_state" != "$old_state" ]; then
add_fido_to_agent
printf '%s\n' "$new_state" > "$state_file"
fi
else
remove_fido_from_agent
rm -f "$state_file"
fi
'';
};
userMatchBlockNames = lib.attrNames (cfg.matchBlocks or { });
userMatchBlocks = lib.mapAttrs (
_name: value: lib.hm.dag.entryBefore [ "my-github" "my-default" ] value
) (cfg.matchBlocks or { });
githubBlock = {
header = "Host github.com";
HostName = "github.com";
User = "git";
IdentityAgent = "SSH_AUTH_SOCK";
IdentitiesOnly = false;
ForwardAgent = false;
AddKeysToAgent = cfg.addKeysToAgent;
}
// lib.optionalAttrs (cfg.githubIdentityFiles != [ ]) {
IdentityFile = cfg.githubIdentityFiles;
};
in
{
options.my.applications.ssh.homeManager = {
@@ -151,108 +14,40 @@ in
};
config.home-manager.sharedModules = [
(
{ lib, ... }:
{
config = lib.mkIf hmCfg.enable {
home.packages = [
sshYubikeyAgentSync
];
{
config = lib.mkIf hmCfg.enable {
home.packages = [
pkgs.openssh
];
systemd.user.services.ssh-yubikey-agent-sync = {
Unit = {
Description = "Synchronize YubiKey SSH key with ssh-agent";
systemd.user.sockets.gcr-ssh-agent.Install.WantedBy = lib.mkForce [ ];
services.ssh-agent.enable = true;
home.sessionVariables = {
SSH_AUTH_SOCK = "\${XDG_RUNTIME_DIR}/ssh-agent";
};
programs.ssh = {
enable = true;
enableDefaultConfig = false;
settings = cfg.matchBlocks // {
"github.com" = {
IdentityFile = cfg.githubIdentityFiles;
AddKeysToAgent = cfg.addKeysToAgent;
};
Service = {
Type = "oneshot";
# NixOS programs.ssh.startAgent の socket。
Environment = [
"SSH_AUTH_SOCK=%t/ssh-agent"
"SSH_YUBIKEY_AGENT_LIFETIME=24h"
];
ExecStart = "${sshYubikeyAgentSync}/bin/ssh-yubikey-agent-sync";
};
};
systemd.user.timers.ssh-yubikey-agent-sync = {
Unit = {
Description = "Periodically synchronize YubiKey SSH key with ssh-agent";
};
Timer = {
OnBootSec = "5s";
OnUnitActiveSec = "10s";
AccuracySec = "2s";
Unit = "ssh-yubikey-agent-sync.service";
};
Install = {
WantedBy = [ "timers.target" ];
};
};
programs.ssh = {
enable = true;
enableDefaultConfig = false;
settings = userMatchBlocks // {
"my-local-fido-sk-rk" =
lib.hm.dag.entryBefore
(
[
"my-github"
"my-default"
]
++ userMatchBlockNames
)
{
header = ''Match exec "${hasFidoDevice}"'';
IdentityFile = cfg.fidoIdentityFile;
# FIDO key の agent 登録は ssh-yubikey-agent-sync に任せる。
#
# ここで AddKeysToAgent を有効にすると、
# YubiKey 抜き差し後に stale な agent entry が残りやすい。
AddKeysToAgent = "no";
};
"my-github" = lib.hm.dag.entryBefore [ "my-default" ] githubBlock;
"my-default" =
lib.hm.dag.entryAfter
(
[
"my-local-fido-sk-rk"
"my-github"
]
++ userMatchBlockNames
)
{
header = "Host *";
IdentityAgent = "SSH_AUTH_SOCK";
IdentitiesOnly = false;
# default deny。
# agent forwarding したい host だけ cfg.matchBlocks 側で true にする。
ForwardAgent = false;
IdentityFile = cfg.defaultIdentityFiles;
AddKeysToAgent = cfg.addKeysToAgent;
SetEnv = {
TERM = "xterm";
};
};
"*" = {
IdentityFile = cfg.defaultIdentityFile;
AddKeysToAgent = cfg.addKeysToAgent;
SetEnv = {
TERM = "xterm";
};
};
};
};
}
)
};
}
];
}
+2 -7
View File
@@ -15,14 +15,9 @@ in
config = lib.mkIf cfg.enable {
environment.systemPackages = with pkgs; [
openssh # OpenSSH client and server
libfido2 # FIDO2 support for SSH
];
programs.ssh = {
startAgent = true;
agentTimeout = "24h";
};
programs.gnupg.agent.enableSSHSupport = lib.mkForce false;
services.gnome.gcr-ssh-agent.enable = lib.mkForce false;
programs.ssh.startAgent = false;
services.gnome.gcr-ssh-agent.enable = false;
};
}