YubiKeyを使ったSSH公開鍵認証(FIDO)

はじめに

YubiKey を使ってSSHをセキュアにする方法がYubico の公式サイトに掲載されていました。

簡単に整理すると下記のようなことができるようです。

  • SSHの公開鍵認証 - クライアント側にYubiKey を挿す
    • PIV(Smart Card)※PKCS #11
    • PGP
    • FIDO2 ※OpenSSH 8.2 のFIDO ハードウェア認証機能を使う
  • SSHサーバの2要素認証の実装 - サーバ側にYubiKey を挿す
    • OTP

この中のFIDO2 を使ったSSHの公開鍵認証を試してみたので、その手順などを解説します。

FIDO2 を使ったSSHの公開鍵認証

  • OpenSSH 8.2p1(2020.2.14リリース) でFIDO ハードウェア認証がサポートされた
  • YubiKey 5 などのFIDOデバイスは、OpenSSH に追加された公開鍵暗号方式“ecdsa-sk” と “ed25519-sk” にサポートされている

つまり、ssh-keygen の-t オプションで“ecdsa-sk” または “ed25519-sk” を指定すると、FIDOトークンに紐づいた鍵を生成することができ、その後パソコンにFIDOデバイスが接続されていれば、他の公開鍵暗号方式の鍵と同じように、SSHサーバに接続することができます。
YubiKey の場合、SSHサーバへの接続時にユーザーにYubiKey のタッチを求めて、タッチしたことをユーザーが接続を明示的に許可したこととして扱うようになっています。

だからどう安全なのかというと、第三者が鍵だけを窃取しても、鍵と紐づいているYubiKey が物理的に手元にないと、鍵を窃取した第三者はSSHサーバに接続することはできない、ということになります。

環境

クライアント側の環境

  • MacBook Pro 2022(macOS Monterey 12.4)
  • OpenSSH client
    • macOSにバンドルでインストール (8.6p1)
    • Homebrew でインストール(9.0p1) ※当手順に記載
  • YubiKey Manager
    • GUIツール (1.2.4)
    • CLIツール (4.0.7)
  • YubiKey 5 NFC(Firmware 5.4.3)

サーバ側の環境

  • Ubuntu 20.04.4 LTS
  • OpenSSH server 8.2p1

YubiKey の初期設定

1. YubiKey のFIDO2 のPINを登録

出荷時の状態のYubiKey にはFIDO2 のPIN が登録されていないので、YubiKey Manager を使って登録します。
YubiKey Manager にはGUIツールとCLIツールの2つありますが、どちらを使ってもPIN の登録ができます。
ちなみに、PIN を登録しないと、CLIツール のFIDO 関連のコマンドが下記のように機能してくれませんでした。(コマンドの実行にPIN の入力が必要な2つ目と3つ目のコマンドがエラーになってる)

% ykman fido info
PIN is not set.

% ykman fido access verify-pin
Error: This feature requires having a PIN. Set a PIN first.

% ykman fido credentials list
Error: Credential Management requires having a PIN. Set a PIN first.

ここでは、GUIツール を使ってFIDO2 のPIN を登録します。

GUIツールを起動してYubiKey をパソコンに挿入し、メニューの[Applications] > [FIDO2] をクリックします。

YubiKey Manager(GUI) FIDO2 PIN(未登録)

FIDO2 PIN のところに”No PIN is set” と表示されています。
[Set PIN] をクリックします。

YubiKey Manager(GUI) FIDO2 PIN(登録)

登録するPINNew PINConfirm PIN の2ヶ所に入力して[Set PIN] をクリックします。
PIN は4文字以上の英数字

YubiKey Manager(GUI) FIDO2 PIN(登録済)

元の画面に戻りました。
A PIN is set, 8 retries left” の表示に変わりました。
PIN が登録され、PIN の入力失敗が8回再試行できる状態になっています。
登録したパスワードは忘れないようパスワードマネージャー等に保存しておきましょう

PIN の登録が完了したので、再度CLI ツールのコマンドを実行してみます。

% ykman fido info
PIN is set, with 8 attempt(s) remaining.

% ykman fido access verify-pin
Enter your PIN:
PIN verified.

% ykman fido credentials list
Enter your PIN:

今回はエラーになりませんでした。
コマンドについての簡単な説明を以下、記載しておきます。

  • ykman fido info
    • FIDO2 アプリの状態を表示するコマンド
    • PIN の登録状態、PIN 入力のリトライ回数が表示される
  • ykman fido access verify-pin
    • FIDO2 をサポートするYubiKey の場合、PIN 入力のリトライ回数をリセットするコマンド
    • コマンド実行時にPIN の入力が求められる
    • 他のPIN 入力が必要なコマンドを実行するとPIN のリトライ回数がリセットされるので、このコマンドが役に立つことはなさそう。失敗する時はこのコマンドも実行できないわけで。。
  • ykman fido credentials list
    • FIDO2 アプリの登録情報を一覧表示するコマンド
    • コマンド実行時にPIN の入力が求められる

GUI ツールを使ったPIN の登録の解説はここまでで、
参考まで、CLI ツールのPIN を登録するコマンドを載せておきます。

ykman fido access change-pin -n<設定するPIN>

鍵の生成〜サーバに鍵を登録〜SSH接続

1. macOSにバンドルでインストールされていたOpenSSHを使って鍵を生成(失敗)

ed25519-sk” を指定してssh-keygen を実行します。

% ssh-keygen -t ed25519-sk
Generating public/private ecdsa-sk key pair.
You may need to touch your authenticator to authorize key generation
Key enrollment failed: unknown or unsupported key type

失敗しました。
不明もしくはサポートされていない鍵タイプ” だそうです。

Yubico のDeveloper 向けサイトに「Disabled by Apple on the bundled version of OpenSSH in MacOS as of the last update to this page」という記載が見つかりました。macOS にバンドルされているOpenSSH は“ecdsa-sk” と “ed25519-sk” が無効にされているみたいです。

Apple のDeveloper 向けサイト等に何か情報がないか探しましたが、何も見つかりませんでした。これ以上突っ込まないで先に進みます。

2. Homebrew でインストールしたOpenSSHを使って鍵を生成

Homebrew でインストールしたOpenSSH であれば鍵生成のコマンドを実行できたという情報が見つかったので試してみました。(結論、成功)

Homebrew でOpenSSH をインストールします。

brew install openssh

Homebrew でインストールしたOpenSSH のコマンドにPATH を通します。
~/.zshrc に下記を追記します。
(2022.6.16 削除)

export PATH=$(brew --prefix openssh)/bin:$PATH

source ~/.zshrc を実行して設定を反映します。 (2022.6.16 削除)

Homebrew でインストールしたOpenSSH のコマンドにPATH が通っていることを確認します。(2022.6.16 追記)

% which ssh
/opt/homebrew/bin/ssh

% ls -l $(which ssh)
lrwxr-xr-x  1 Capybara admin  31  6 16 13:49 /opt/homebrew/bin/ssh -> ../Cellar/openssh/9.0p1/bin/ssh

ed25519-sk” を指定してssh-keygen を実行します。
今回は成功したので、作成された鍵ファイルを削除して、追加で幾つかのオプションを付けて再度実行しました。

% ssh-keygen -t ed25519-sk
 → 成功
% rm ~/.ssh/id_ed25519-sk*
 → 鍵を削除

% ssh-keygen -t ed25519-sk -O resident -O application=ssh:Capybara
Generating public/private ed25519-sk key pair.
You may need to touch your authenticator to authorize key generation.
 → ここでYubiKey をタッチ👆
Enter PIN for authenticator:
 → ここで登録したFIDO2のPIN を入力

Enter file in which to save the key (/Users/Capybara/.ssh/id_ed25519_sk):
 → ここで生成する鍵のファイル名を入力(何も入力せずEnterも可)
Enter passphrase (empty for no passphrase):
 → ここで生成する秘密鍵のパスフレーズを入力
Enter same passphrase again:
 → パスフレーズを再度入力
Your identification has been saved in /Users/Capybara/.ssh/id_ed25519_sk
Your public key has been saved in /Users/Capybara/.ssh/id_ed25519_sk.pub
The key fingerprint is:
SHA256:z0xxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxxxxxxd0 [email protected]
The key's randomart image is:
+[ED25519-SK 256]-+
|        ......   |
|        ......   |
|        ......   |
+----[SHA256]-----+

% ls -l ~/.ssh
-rw-------  1 Capybara staff   525  5 29 16:31 id_ed25519_sk
-rw-r--r--  1 Capybara staff   159  5 29 16:31 id_ed25519_sk.pub

追加したssh-keygen のオプションの簡単な説明を記載しておきます。

  • -O resident
    • 鍵をFIDO 認証器内に保存する
    • このオプションの有無に関係なく、~/.ssh フォルダに鍵ペアは作成される
    • FIDO 認証器内に鍵を保存しておくと、ssh-keygen -K でカレントディレクトリに秘密鍵と公開鍵のファイルを書き出すことができる
  • -O application=ssh:<your-key-name>
    • 生成する鍵の名前を指定する
    • 指定する場合、“ssh:” に続けて任意の名前を指定する必要がある
    • このオプションを指定しない場合、デフォルトの“ssh:” で作成される
    • ここで指定した名前は、CLI ツールで鍵を削除する際に使われる(例:ykman fido credentials delete ‘ssh:Capybara’

-O resident オプションを付けたので、CLI ツールでYubiKey 内に保存された鍵を確認します。

% ykman fido credentials list
Enter your PIN:
ssh:Capybara 0000000000000000000000000000000000000000000000000000000000000000 openssh

-O application オプションで指定した名前が先頭にある行が1行出力されました。
ALLゼロが何なのかよく分かりませんが、とりあえずYubiKey 内に保存されているようです。

3. 公開鍵をサーバにアップロード&登録

サーバに公開鍵をアップロードします。

scp id_ed25519_sk.pub [email protected]:~/

サーバにSSHで接続して、接続ユーザの~/.ssh/authorized_keys公開鍵を登録します。

% ssh [email protected]

$ mkdir ~/.ssh
$ chmod 700 ~/.ssh
$ cat id_ed25519_sk.pub >> ~/.ssh/authorized_keys
$ chmod 600 ~/.ssh/authorized_keys

4. 公開鍵認証でサーバにSSH接続

SSH の公開鍵認証でサーバに接続できるか確認します。

% ssh [email protected]
Enter passphrase for key '/Users/Capybara/.ssh/id_ed25519_sk':
 → パスフレーズを入力
Confirm user presence for key ED25519-SK SHA256:z0xxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxxxxxxd0
 → YubiKey をタッチ👆
User presence confirmed

パスフレーズ + YubiKey をタッチ2要素認証でサーバに接続することができました。

5. パスワード認証を不許可に設定

SSHサーバの設定/etc/ssh/sshd_config でパスワード認証を不許可にすれば、登録した公開鍵を使った 認証しかできなくなります。

PubkeyAuthentication yes

Match User ubuntu
  PasswordAuthentication no
  AuthorizedKeysFile /home/ubuntu/.ssh/authorized_keys

systemctl reload sshd を実行して設定を反映します。

ssh-agent を使う

ついでにssh-agent を使えばパスフレーズはssh-agent が代理入力してYubiKey のタッチだけでSSH接続できるのではと試したら、SSH接続のコマンドでエラーになりました。
使ったSSHクライアントはHomebrew でインストールしたOpenSSH です。
エラーの原因や解消する方法を調べましたが見つからなかったので、記録として残しておきます。

1. ssh-agentに秘密鍵の登録〜SSH接続(失敗)

% ssh-add id_ed25519_sk
Enter passphrase for id_ed25519_sk:
 → ssh-agentへの登録は成功

% ssh [email protected]
sign_and_send_pubkey: signing failed for ED25519-SK "/Users/Capybara/.ssh/id_ed25519_sk" from agent: agent refused operation
 → サーバの接続は失敗

% ssh-add -D
All identities removed.
 → 後片付けとして、ssh-agentの登録を削除

ちなみに、SSHサーバの設定でパスワード認証を不許可にしないでおくと、SSH接続でエラーになるけれどもパスワード入力が求められ、パスワード認証を使ってSSH接続することはできました。

2. keychain関連のオプション

更についでに、ssh-add のkeychain関連のオプションを使ってみたらエラーになりました。不正なオプションとのことです。
そもそも、Homebrew でインストールしたOpenSSH にはkeychain関連のオプションがありませんでした。macOS にバンドルされているOpenSSH 限定のオプションだったようです。

% ssh-add --apple-use-keychain
ssh-add: illegal option -- -
 → 秘密鍵のパスフレーズをキーチェーンに登録しようとしたら失敗

Apple のDeveloper 向けサイトに掲載されているmacOS 10.12.2 (Sierra) のOpenSSH の更新のページに、Keychain とssh-agent の変更について書かれていました。書きっぷりがmacOS に搭載されているOpenSSH の更新と見えなくもないです。
一応リンクを貼っておきます。

YubiKey のFIDO2 を無効にする設定

YubiKey Manager にYubiKey のFIDO2 を無効にする機能があったので、こちらもどのように機能するか試してみました。

  • GUIツールとCLIツールのどちらでも無効にすることはできます
  • この設定は前述のPIN の登録をしなくてもできます

1. YubiKey のFIDO2 を無効にする

GUIツールのメニューの[Interfaces] をクリックします。

YubiKey Manager(GUI) Interfaces FIDO2(有効)

左のUSB のFIDO2 のチェックをOFF にして[Save Interfaces] をクリックします。

YubiKey Manager(GUI) Interfaces FIDO2(無効)

CLI ツールでFIDO2無効になっていることを確認します。

% ykman info
Device type: YubiKey 5 NFC
Serial number: 99999999
Firmware version: 5.4.3
Form factor: Keychain (USB-A)
Enabled USB interfaces: OTP, FIDO, CCID
NFC transport is enabled.

Applications	USB     	NFC
FIDO2       	Disabled	Enabled
OTP         	Enabled 	Enabled
FIDO U2F    	Enabled 	Enabled
OATH        	Enabled 	Enabled
YubiHSM Auth	Disabled	Disabled
OpenPGP     	Enabled 	Enabled
PIV         	Enabled 	Enabled

% ykman config usb --list
OTP
FIDO U2F
OATH
PIV
OpenPGP

10行目のFIDO2 のUSB 欄がDisabled になっています。
また、18行目のコマンドの結果にFIDO2 が出力されていないです。

2. FIDO2 が無効の状態でSSH接続を試行

% ssh [email protected]
Enter passphrase for key '/Users/Capybara/.ssh/id_ed25519_sk':
 → パスフレーズを入力
Confirm user presence for key ED25519-SK SHA256:z0xxxxxxxxxxxxxxxxxxxxxxxxxx/xxxxxxxxxxxxd0
sign_and_send_pubkey: signing failed for ED25519-SK "/Users/Capybara/.ssh/id_ed25519_sk": device not found
[email protected]: Permission denied (publickey).

パスフレーズの入力後にエラーになりました。

この後、再度有効にして接続できるか試したら接続できました。
無効にしてもFIDO2 の登録情報は削除されずに残ります。

参考まで、CLI ツールのFIDO2 を無効・有効にするコマンドを載せておきます。

% ykman config usb -d FIDO2
Disable FIDO2.
Configure USB? [y/N]: y
 → 無効になる ※オプション[--disable] も同じ

% ykman config usb -e FIDO2
Enable FIDO2.
Configure USB? [y/N]: y
 → 有効になる ※オプション[--enable] も同じ
  • 上記のコマンドを実行するとYubiKey が点滅するのでタップしてみると、OTP のスロットに設定したYubico OTPの44文字が入力され「Error: invalid input」になった。点滅するけれどもタッチは不要です
  • GUIツールを開いた状態でCLIツールで有効・無効を変更してもGUIツールの表示は変わらない。変更をGUIツールの表示に反映するにはGUIアプリの再起動かYubiKey の再接続が必要

3. FIDO2 が無効の状態でTwitter のログインを試行

以前の投稿「YubiKeyでTwitterアカウントを保護する」でセキュリティキーを使った2段階認証の設定をしていたので、このYubiKey の有効・無効の影響を試してみました。

Yubico のサイトにはTwitter はFIDO2U2F がサポートされていると書かれていました。

Twitter Security protocol support (U2F FIDO2)

実際に試した結果は下記の通りです。

FIDO2FIDO U2Fログイン試行の結果
無効有効ログイン成功
有効無効ログイン成功
有効有効ログイン成功
無効無効ログイン失敗

FIDO2FIDO U2F の両方を無効にした場合のみログインに失敗しました。
振る舞いとしては、1段階目のパスワード入力後、2段階目でパソコンに挿入したYubiKey が点滅せず、タップしても無反応でした。

ちなみに、前述のFIDO2 の登録情報を確認するykman fido credentials list を実行すると、ssh-keygen -t ed25519-sk -O residentで作成した鍵は表示されますが、Twitter の情報は表示されませんでした。
Yubico の下記リンク先に書かれていることが関係していそうな雰囲気があります。(セキュリティ観点で表示されないようにファームウェアがアップデートされた?)
表示されない理由が分かっても解消する訳ではなさそうなので深掘りするのは止めておきます。

参考