yubikey配置:基于resident-key实现在任意设备上安全使用ssh密钥。
前言
YubiKey 是一款由 Yubico 出品的硬件安全密钥,主要用于多因素认证(MFA)、密码管理、数字签名以及 SSH 身份验证等场景。它通过 USB、NFC 或 Lightning 接口与设备连接,可以生成一次性密码(OTP)、支持 FIDO2/WebAuthn、PIV(智能卡)以及 OpenPGP 等多种安全协议。YubiKey 的核心优势在于私钥永不离开硬件设备,即使电脑或网络被攻破,密钥仍然安全。
驻留密钥(Resident Key, RK)是 YubiKey 和 OpenSSH 中的一项功能,允许将 SSH 私钥直接存储在硬件设备内部,而不是依赖本地文件系统。与传统的 SSH 私钥文件不同,驻留密钥具备以下特点:
- 便携性:密钥随 YubiKey 携带,无需在每台设备上复制私钥。
- 安全性:私钥不会离开硬件设备,即使设备被接入不可信计算机,也无法导出密钥。
- 便捷性:支持在陌生设备上即插即用,通过硬件认证即可完成 SSH 登录,无需额外传输私钥。
- 多密钥管理:同一个 YubiKey 可存储多个 SSH 驻留密钥,并通过用户名或服务器标识选择使用。
传统ssh需要在设备上提前配置好ssh密钥,与设备绑定在一起。一旦遇到突发情况,身边没有自己设备,需要在陌生设备上使用ssh密钥就会非常麻烦。
通过yubikey驻留密钥将ssh私钥储存在物理密钥中,这样只需要携带有yubikey,可以在任何设备上使用ssh密钥,也可以有效避免对密钥的误操作。
准备环境
openSSH在8.2后添加了对fido驻留密钥的支持,只需要安装openSSH版本大于8.2,并启用fido库即可使用。
Windows
Window11自带全部环境,插上即用,无须配置。(win易用性这块还是不错的)
Linux
主流发行版openSSH均支持驻留密钥,只需要安装fido库即可。如果不确定自己的openSSH版本是否支持可以使用ssh -V来检查。
Debian/Ubuntu
sudo apt install libfido2-1Fedora/RHEL
sudo dnf install libfido2macOS
从macOS12开始,默认openSSH已经支持驻留密钥。但不幸的,苹果出于一些原因在编译openSSH时添加了--disable-security-key参数禁用了安全密钥的支持。这使得在macOS12无法使用安全密钥功能,除非重新编译安装openSSH。但已有openSSH和icloud钥匙串存在联系,重新编译会破坏功能。我认为这并不是一个好的解决方案,所以不在考虑。幸运的,社区对苹果禁用安全密钥的问题作出了许多积极的反馈,在macOS Sonoma中安全密钥重新可用,只是不再提供中间件。本文基于此解决方案编写,仅适用于macOS Sonoma及以上。
基于社区的讨论,在macOS Sonoma之后的openSSH中已经可以使用安全密钥,只需要自己编译 libfido2 来提供自己的 SSH_SK_PROVIDER。 可以使用如下脚本来实现编译安装,脚本来自GitHub。
#!/bin/bash
################################################################################################# Last Updated: January 13, 2025## macOS OpenSSH Client Patcher for Hardware Security Key Support (ED25519-SK With YubiKey Etc.)# Check out https://gist.github.com/BertanT/9d222da115ca2d1274ef34735c4260cf for details!## Copyright 2025 Mehmet Bertan Tarakcioglu (github.com/BertanT), under the MIT License.################################################################################################
# Exit early if there is an errorset -e
printf "\n* Hello! This script compiles and installs the security key provider for the built-in macOS Open SSH client to enable support for hardware security keys (such as a YubiKey)."
# Check if the script is running as rootif [ "$(id -u)" -eq 0 ]; then printf "\n!!! Error: For safety reasons, this script cannot be run as root. If using sudo, please try again without it.\n" >&2 exit 1fi
# Function to compare macOS version stringsversion_ge() { [[ "$(echo -e "$1\n$2" | sort -V | head -n1)" == "$2" ]]}
# function to get the current macOS Versionmacos_version=$(sw_vers -productVersion | cut -d '.' -f1,2)
# Check if running at least macOS Sonomaif ! version_ge "$macos_version" "14.0"; then printf "\n!!! Error: macOS version is $macos_version. This script requires at least macOS Sonoma (14.0).\n" >&2 exit 1fiprintf "\n* macOS version is supported!"
# Check if Homebrew is installedif ! which brew &>/dev/null; then printf "\n!!! Error: This script requires Homebrew to install dependencies! Please install Homebrew and try again\n" >&2 exit 1fiprintf "\n* Homebrew is installed!"
printf "\n* Cloning the latest main branch of openssh-portable from GitHub. This may take a while..."git clone --quiet https://github.com/openssh/openssh-portable.gitcd openssh-portable
printf "\n* Installing dependencies from Homebrew: libfido2, openssl, autoconf, automake, libtool\n"brew install libfido2 openssl autoconf automake libtool pkgconf
printf "\n* Generating configuration script."autoreconf -i
printf "\n* Exporting flags."
# Determine the CPU architecture and set the appropriate Homebrew base pathif [[ "$(uname -m)" == "arm64" ]]; then BREW_PREFIX="/opt/homebrew"elif [[ "$(uname -m)" == "x86_64" ]]; then BREW_PREFIX="/usr/local"else echo "!!! Error: Unknown CPU architecture $(uname -m).\n" >&2 exit 1fi
# Get the appropriate paths for the Homebrew dependecies as they differ through versionBREW_OPENSSL_PATH=$(ls -d $BREW_PREFIX/Cellar/openssl@3/*)BREW_LIBFIDO2_PATH=$(ls -d $BREW_PREFIX/Cellar/libfido2/*)export CFLAGS="-L$BREW_OPENSSL_PATH/lib -I$BREW_OPENSSL_PATH/include -L$BREW_LIBFIDO2_PATH/lib -I$BREW_LIBFIDO2_PATH/include -Wno-error=implicit-function-declaration"export LDFLAGS="-L$BREW_OPENSSL_PATH/lib -L$BREW_LIBFIDO2_PATH/lib"
printf "\n* Configuring build. This may take a while..."./configure --quiet --with-security-key-standalone
printf "\n* Cleaning previous build for good measure."make --quiet clean
printf "\n* Building OpenSSH Portable."make --quiet
printf "\n* Copying the Security Key Provider library to /usr/local/lib."printf "\n We need root privileges to modify system files.\n"sudo mkdir -p /usr/local/libsudo mv sk-libfido2.dylib /usr/local/lib/
# Check if the script is running in ZSH. If not, give the user instructions.# Otherwise, modify .zshenv to set the environment variable if not already present.if [[ "$SHELL" == *zsh* ]]; then printf "\n* Configuring the ~/.zshenv for the System SSH use the Security Key Provider we just built" if ! grep -q "export SSH_SK_PROVIDER=/usr/local/lib/sk-libfido2.dylib" "$HOME/.zshenv" &>/dev/null; then echo "export SSH_SK_PROVIDER=/usr/local/lib/sk-libfido2.dylib" >> "$HOME/.zshenv" printf "\n* Added SSH_SK_PROVIDER to ~/.zshenv." else printf "\n* SSH_SK_PROVIDER is already configured in ~/.zshenv." fielse printf "*\n Since you are not on ZSH, you will need to manually configure your shell profile to tell the System SSH client to use the Security Key Provider we just built." printf "\n The shell profile should export the environment variable as follows:" printf "\n export SSH_SK_PROVIDER=/usr/local/lib/sk-libfido2.dylib"fi
printf "\n* Exiting the directory and deleting the repository we cloned. We don't need it anymore"cd ..rm -rf openssh-portable
printf "\n\n* That's it! After restarting your terminal session, you can plug in your hardware security key and test the installation using:"printf "\n ssh-keygen -t ed25519-sk -O resident -O verify-required -C \"Your Comment\""printf "\n\nHave a nice day! :)\n\n"yubikey配置
生成驻留密钥
创建 SSH 驻留密钥(Resident Key)非常简单,只需要在生成密钥时添加 -O resident 选项。
ssh-keygen \ -t ed25519-sk \ -O resident \ -O verify-required参数说明
- -t ed25519-sk:指定证书类型为Ed25519
- -O resident:将私钥存储在 YubiKey 内部(驻留密钥)
- -O verify-required:每次使用时需要验证pin码
之后安装提示输入PIN码并触碰金属触点即可完成配置。
从yubikey导出驻留密钥公钥
在新设备上使用驻留密钥也很简单,只需要使用使用
ssh-keygen -K即可从yubikey中导出所有驻留密钥的公钥。 之后把导出的文件移动到~/.ssh文件夹下,并重命名为id_ed25519_sk即可被ssh-agent自动加载。
到此配置完成,是不是非常简单。从此走向忘记密码的道路,enjoy it!
参考资料
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!