Bitwarden as SSH agent

Bitwarden as SSH agent

SSH 密码登录由于安全/便利问题现在几乎不会推荐使用,使用密钥登录应该已经是基本操作。但是如何管理不同设备不同私钥是个大的问题,我之前的实践是同一份私钥复制到有登录需求的各个设备(几乎等于所有设备),毕竟为每台设备生成独立的密钥大幅提高了管理的难度。

今天偶然看到(RSS订阅突然多出了600+未读) Xuanwo 的文章: 2023-21: 我的 1Password 密钥管理实践,决定在安全方面优化一下 SSH 密钥管理体系。我日常使用 Bitwarden,搜索发现也支持了 SSH agent 功能1 。下面依次介绍不同平台的使用。

Windows 11 WSL2 #

参考文章 https://www.rebelpeon.com/bitwarden-ssh-agent-on-wsl2/

# host, you should install chocolate first
choco install npiperelay

# wsl2
sudo apt install socat

~/scripts/agent-bridge.sh, add source <path> to your shell rc.

export SSH_AUTH_SOCK=$HOME/.ssh/agent.sock
ss -a | grep -q $SSH_AUTH_SOCK
if [ $? -ne 0   ]; then
    rm -f $SSH_AUTH_SOCK
    ( setsid socat UNIX-LISTEN:$SSH_AUTH_SOCK,fork EXEC:"/mnt/c/ProgramData/chocolatey/lib/npiperelay/tools/npiperelay.exe -ei -s //./pipe/openssh-ssh-agent",nofork & ) >/dev/null 2>&1
fi

Then you can use ssh-add -l to test.

macOS #

export SSH_AUTH_SOCK=/Users/<user>/.bitwarden-ssh-agent.sock

linux GUI #

export SSH_AUTH_SOCK=/home/<user>/.bitwarden-ssh-agent.sock

linux CLI #

这个比较麻烦一点,因为官方的 CLI 客户端目前尚不支持 SSH agent 功能,不过可以通过自己手糊(LLM actually)脚本从 BW CLI 中读取私钥并添加进 ssh-agent 中。

#!/bin/bash

eval "$(ssh-agent -s)"

# 1. 在这里填入你想同步的 Bitwarden Object ID (空格分隔)
KEYS_TO_SYNC=(
    "uuid-1-xxxxxx"
    "uuid-2-yyyyyy"
    "uuid-3-zzzzzz"
)

# 2. 检查会话
if [ -z "$BW_SESSION" ]; then
    echo "❌ 错误: 请先运行 'export BW_SESSION=\$(bw unlock --raw)'"
    exit 1
fi

# 3. 准备内存临时目录
TEMP_DIR="/dev/shm/bw-ssh-keys"
[[ "$OSTYPE" == "darwin"* ]] && TEMP_DIR="/tmp/bw-ssh-keys"
mkdir -p -m 700 "$TEMP_DIR"

# 4. 退出时清理
trap 'rm -rf "$TEMP_DIR"; echo "🧹 临时文件已销毁"' EXIT

echo "🚀 开始按 ID 同步指定的 SSH 密钥..."

for ITEM_ID in "${KEYS_TO_SYNC[@]}"; do
    # 直接获取单个 Item
    ITEM_JSON=$(bw get item "$ITEM_ID" 2>/dev/null)
    
    if [ $? -ne 0 ] || [ -z "$ITEM_JSON" ]; then
        echo "⚠️  跳过: 无法获取 ID 为 $ITEM_ID 的条目 (请检查 ID 或是否已同步)"
        continue
    fi

    # 提取名称和私钥
    RAW_NAME=$(echo "$ITEM_JSON" | jq -r '.name')
    SAFE_NAME=$(echo "$RAW_NAME" | tr ' /' '__')
    KEY_DATA=$(echo "$ITEM_JSON" | jq -r '.sshKey.privateKey // .notes') # 优先找 sshKey,找不到尝试 notes

    if [ "$KEY_DATA" != "null" ] && [ -n "$KEY_DATA" ]; then
        TEMP_FILE="$TEMP_DIR/$SAFE_NAME"
        echo "$KEY_DATA" > "$TEMP_FILE"
        chmod 600 "$TEMP_FILE"

        # 添加到 Agent
        if ssh-add -t 4h "$TEMP_FILE" 2>/dev/null; then
            echo "✅ 已加载: $RAW_NAME"
        else
            echo "❌ 加载失败: $RAW_NAME (请确保内容是有效的私钥格式)"
        fi
    else
        echo "⚠️  跳过: 条目 $RAW_NAME 中没有找到私钥内容"
    fi
done

echo "---"
echo "Done. 运行 'ssh-add -l' 验证结果。"

One more thing: git commit sign #

阅读 Bitwarden 文档的时候发现GitHub2022年3月开始支持使用 SSH 密钥对 Git commit 进行签名和验证。以前刚推出这个功能的时候尝试了 GPG sign,因为过于麻烦放弃。既然现在支持 SSH 密钥了,顺便一起尝试一下,具体方法参考1 ,注意这里有个小坑,配置 .gitconfig时不能使用 ssh key name,需要写出公钥的具体内容。配置完成后在 commit 时也会提醒认证。

后续可以探索使用 Yubikey SSH 登录。

参考 #

windows 另一台机器部署出问题,Gemini 给出的解决思路