This commit is contained in:
2026-06-25 15:18:53 +09:00
parent dc9c7694b6
commit c68a4fe735
2 changed files with 87 additions and 38 deletions
-3
View File
@@ -8,7 +8,4 @@
boot.initrd.luks.devices.cryptroot.device = boot.initrd.luks.devices.cryptroot.device =
"/dev/disk/by-partuuid/311d0f9c-f35f-42e6-b6fc-a4d67dd21b2e"; "/dev/disk/by-partuuid/311d0f9c-f35f-42e6-b6fc-a4d67dd21b2e";
my.applications.git.homeManager = {
signingKey = "~/.ssh/id_ed25519_sk_rk.pub";
};
} }
+85 -33
View File
@@ -28,67 +28,119 @@ let
esac esac
} }
print_key_line() { fido_present() {
key="$1" ${pkgs.libfido2}/bin/fido2-token -L 2>/dev/null \
| ${pkgs.gnugrep}/bin/grep -q .
}
case "$key" in is_ssh_public_key() {
case "$1" in
ssh-*|ecdsa-*|sk-*) ssh-*|ecdsa-*|sk-*)
printf 'key::%s\n' "$key" return 0
exit 0 ;;
*)
return 1
;; ;;
esac esac
} }
print_pub_from_identity_file() { is_fido_public_key() {
case "$1" in
sk-*)
return 0
;;
*)
return 1
;;
esac
}
print_git_key() {
key="$1"
is_ssh_public_key "$key" || return 1
printf 'key::%s\n' "$key"
exit 0
}
pubkey_file_for_identity() {
identity_file="$(expand_path "$1")" identity_file="$(expand_path "$1")"
case "$identity_file" in case "$identity_file" in
*.pub) *.pub)
public_key_file="$identity_file" printf '%s\n' "$identity_file"
;; ;;
*) *)
public_key_file="$identity_file.pub" printf '%s.pub\n' "$identity_file"
;; ;;
esac esac
}
if [ ! -r "$public_key_file" ]; then print_pubkey_file_as_git_key() {
return 1 public_key_file="$1"
fi
[ -r "$public_key_file" ] || return 1
IFS= read -r key < "$public_key_file" || return 1 IFS= read -r key < "$public_key_file" || return 1
[ -n "$key" ] || return 1 [ -n "$key" ] || return 1
print_key_line "$key" print_git_key "$key"
} }
# 1. まず現在の SSH agent を優先する。 print_first_usable_agent_key() {
# [ -n "''${SSH_AUTH_SOCK:-}" ] || return 1
# ローカル端末なら NixOS の ssh-agent。 [ -S "$SSH_AUTH_SOCK" ] || return 1
# SSH agent forwarding 先なら forwarded agent。
# has_fido=0
# Git はここで返した公開鍵に対応する秘密鍵を ssh-agent 経由で使う。 if fido_present; then
if [ -n "''${SSH_AUTH_SOCK:-}" ] && [ -S "$SSH_AUTH_SOCK" ]; then has_fido=1
while IFS= read -r key; do
print_key_line "$key"
done <<EOF
$(${pkgs.openssh}/bin/ssh-add -L 2>/dev/null || true)
EOF
fi fi
# 2. agent に使える鍵が無ければ、YubiKey が見えている場合だけ _sk_rk を使う。 ${pkgs.openssh}/bin/ssh-add -L 2>/dev/null \
# | while IFS= read -r key; do
# _sk_rk ファイルの存在では判定しない。 is_ssh_public_key "$key" || continue
fido_devices="$(${pkgs.libfido2}/bin/fido2-token -L 2>/dev/null || true)"
if [ -n "$fido_devices" ]; then # YubiKey が無いときに agent に残っている sk-* 鍵を選ぶと、
print_pub_from_identity_file ${lib.escapeShellArg sshCfg.fidoIdentityFile} || true # Git 署名時に "agent refused operation" になる。
if is_fido_public_key "$key" && [ "$has_fido" -ne 1 ]; then
continue
fi fi
# 3. 最後に通常のローカル identity へ fallback する。 print_git_key "$key"
done
}
add_identity_to_agent_and_print_pubkey() {
identity_file="$(expand_path "$1")"
public_key_file="$(pubkey_file_for_identity "$1")"
[ -r "$identity_file" ] || return 1
[ -r "$public_key_file" ] || return 1
[ -n "''${SSH_AUTH_SOCK:-}" ] || return 1
[ -S "$SSH_AUTH_SOCK" ] || return 1
${pkgs.openssh}/bin/ssh-add -q "$identity_file" >/dev/null 2>&1 || return 1
print_pubkey_file_as_git_key "$public_key_file"
}
# 1. agent にすでにある鍵を優先する。
# ただし YubiKey が無い場合、stale な sk-* 鍵は無視する。
print_first_usable_agent_key || true
# 2. YubiKey が刺さっている場合だけ _sk_rk を追加して使う。
if fido_present; then
add_identity_to_agent_and_print_pubkey ${lib.escapeShellArg sshCfg.fidoIdentityFile} || true
fi
# 3. 最後に通常のローカル鍵を agent に追加して使う。
${lib.concatMapStringsSep "\n" ( ${lib.concatMapStringsSep "\n" (
identityFile: "print_pub_from_identity_file ${lib.escapeShellArg identityFile} || true" identityFile: "add_identity_to_agent_and_print_pubkey ${lib.escapeShellArg identityFile} || true"
) sshCfg.defaultIdentityFiles} ) sshCfg.defaultIdentityFiles}
printf '%s\n' "git-ssh-signing-key: no usable SSH signing public key found" >&2 printf '%s\n' "git-ssh-signing-key: no usable SSH signing key found" >&2
exit 1 exit 1
''; '';