From 93aba545ede891fad65befb119416b3e4f970635 Mon Sep 17 00:00:00 2001 From: moons-14 Date: Thu, 25 Jun 2026 15:54:09 +0900 Subject: [PATCH] Revert commits after 089e185bd892 --- hosts/x1g13/default.nix | 3 + modules/applications/git/home.nix | 172 ++---------------- modules/applications/openssh.nix | 1 - modules/applications/ssh/default.nix | 69 ++----- modules/applications/ssh/home.nix | 263 +++------------------------ modules/applications/ssh/system.nix | 9 +- 6 files changed, 69 insertions(+), 448 deletions(-) diff --git a/hosts/x1g13/default.nix b/hosts/x1g13/default.nix index 1ef0617..be9db17 100644 --- a/hosts/x1g13/default.nix +++ b/hosts/x1g13/default.nix @@ -8,4 +8,7 @@ boot.initrd.luks.devices.cryptroot.device = "/dev/disk/by-partuuid/311d0f9c-f35f-42e6-b6fc-a4d67dd21b2e"; + my.applications.git.homeManager = { + signingKey = "~/.ssh/id_ed25519_sk_rk.pub"; + }; } diff --git a/modules/applications/git/home.nix b/modules/applications/git/home.nix index 4bd075f..9791d65 100644 --- a/modules/applications/git/home.nix +++ b/modules/applications/git/home.nix @@ -1,156 +1,32 @@ { - pkgs, lib, config, ... }: - let cfg = config.my.applications.git; hmCfg = config.my.applications.git.homeManager; - - sshCfg = config.my.applications.ssh; - - gitSshSigningKeyCommand = pkgs.writeShellScript "git-ssh-signing-key" '' - set -u - - expand_path() { - case "$1" in - "~") - printf '%s\n' "$HOME" - ;; - "~/"*) - printf '%s\n' "$HOME/''${1#"~/"}" - ;; - *) - printf '%s\n' "$1" - ;; - esac - } - - fido_present() { - ${pkgs.libfido2}/bin/fido2-token -L 2>/dev/null \ - | ${pkgs.gnugrep}/bin/grep -q . - } - - is_ssh_public_key() { - case "$1" in - ssh-*|ecdsa-*|sk-*) - return 0 - ;; - *) - return 1 - ;; - esac - } - - 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")" - - case "$identity_file" in - *.pub) - printf '%s\n' "$identity_file" - ;; - *) - printf '%s.pub\n' "$identity_file" - ;; - esac - } - - print_pubkey_file_as_git_key() { - public_key_file="$1" - - [ -r "$public_key_file" ] || return 1 - - IFS= read -r key < "$public_key_file" || return 1 - [ -n "$key" ] || return 1 - - print_git_key "$key" - } - - print_first_usable_agent_key() { - [ -n "''${SSH_AUTH_SOCK:-}" ] || return 1 - [ -S "$SSH_AUTH_SOCK" ] || return 1 - - has_fido=0 - if fido_present; then - has_fido=1 - fi - - ${pkgs.openssh}/bin/ssh-add -L 2>/dev/null \ - | while IFS= read -r key; do - is_ssh_public_key "$key" || continue - - # YubiKey が無いときに agent に残っている sk-* 鍵を選ぶと、 - # Git 署名時に "agent refused operation" になる。 - if is_fido_public_key "$key" && [ "$has_fido" -ne 1 ]; then - continue - fi - - 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" ( - identityFile: "add_identity_to_agent_and_print_pubkey ${lib.escapeShellArg identityFile} || true" - ) sshCfg.defaultIdentityFiles} - - printf '%s\n' "git-ssh-signing-key: no usable SSH signing key found" >&2 - exit 1 - ''; - in { options.my.applications.git.homeManager = { enable = lib.mkEnableOption "git home-manager configuration"; + + signingKey = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = "~/.ssh/id_ed25519_sk_rk.pub"; + example = "~/.ssh/id_ed25519.pub"; + description = "SSH public key path used for Git commit and tag signing."; + }; }; config = lib.mkIf hmCfg.enable { + assertions = [ + { + assertion = hmCfg.signingKey != null; + message = "my.applications.git.homeManager.signingKey must be set per host."; + } + ]; + home-manager.sharedModules = [ { programs.git = { @@ -162,6 +38,12 @@ in "!.envrc.example" ]; + signing = { + key = hmCfg.signingKey; + format = "ssh"; + signByDefault = true; + }; + settings = { user.name = cfg.userName; user.email = cfg.userEmail; @@ -173,20 +55,6 @@ in log.date = "iso"; merge.conflictStyle = "diff3"; - # SSH signing - gpg.format = "ssh"; - - # Git の SSH signing backend はデフォルトでも ssh-keygen だが、 - # store path に固定して PATH 依存を避ける。 - gpg.ssh.program = "${pkgs.openssh}/bin/ssh-keygen"; - - # user.signingKey は固定しない。 - # 署名時にこの command が key::ssh-ed25519 ... を返す。 - gpg.ssh.defaultKeyCommand = "${gitSshSigningKeyCommand}"; - - commit.gpgSign = true; - tag.gpgSign = true; - alias = { br = "branch --sort=-committerdate"; co = "checkout"; diff --git a/modules/applications/openssh.nix b/modules/applications/openssh.nix index 53cc0dc..f45a857 100644 --- a/modules/applications/openssh.nix +++ b/modules/applications/openssh.nix @@ -16,7 +16,6 @@ in PermitRootLogin = "no"; PasswordAuthentication = false; KbdInteractiveAuthentication = false; - AllowAgentForwarding = true; PubkeyAuthentication = "yes"; }; }; diff --git a/modules/applications/ssh/default.nix b/modules/applications/ssh/default.nix index 1b6bfa6..0a5c0fd 100644 --- a/modules/applications/ssh/default.nix +++ b/modules/applications/ssh/default.nix @@ -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)"; }; }; diff --git a/modules/applications/ssh/home.nix b/modules/applications/ssh/home.nix index 8d94fb9..3b074ee 100644 --- a/modules/applications/ssh/home.nix +++ b/modules/applications/ssh/home.nix @@ -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"; + }; }; }; }; - } - ) + }; + } ]; } diff --git a/modules/applications/ssh/system.nix b/modules/applications/ssh/system.nix index bc1ecb5..9b34d19 100644 --- a/modules/applications/ssh/system.nix +++ b/modules/applications/ssh/system.nix @@ -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; }; }