YubiKeyとSSH – macOS

前置きに続いて早速ed25519-sk鍵タイプを試していきます。

Contents

macOS: 準備

YubiKeyの選択の仕方は前置きをご覧ください。青いYubiKeyでもFIDO U2FかFIDO2の機能があれば使えるはずです。今回はfirmware 5.2.4の青いSecurity Keyシリーズで確認しています。5.2.3未満の場合はecdsa-skでお試しください。 ecdsa-skはP-256楕円曲線だけなので使う理由があるのかは謎です。

2021-11-22追記: Montereyで標準のOpenSSHのバージョンが-sk対応の8.6になりました。Appleのカスタマイズは OpenSSH-267.40.5 という版数でされたようです。ビルド時に –with-security-key-builtin が付いていないようなので、そのままでは -sk 鍵タイプを扱うことはできませんでした。使う場合は以下のBig Surと同じような手順を踏むことになります。一方でOpenSSH 8.6p1を prefix=~/openssh/ でビルドしてinstall、export SSH_SK_HELPER=~/openssh/libexec/ssh-sk-helper 、それに加えて無理くり sk-usbhid.c をコンパイルして /usr/local/lib/libsk-libfido2.dylib として置き、 export SSH_SK_PROVIDER=/usr/local/lib/libsk-libfido2.dylib とすることで /usr/bin/ssh-agent と /usr/bin/ssh-add -K の組み合わせで discoverable credential(resident identity)の追加はできたので部分的に対応できるようですが、ざっと動かして/usr/bin/ssh-agentにdiscoverable credential追加する以外の動作を確認することはできませんでした。SKヘルパーとSKプロバイダーの提供か内蔵で -sk が使えるようになるにはまだかかりそうです。またAppleが独自に追加して本家とぶつかっていた ssh-add のKeychain用のオプションが変更になっています。末尾に雑ですが記録を追加しておきます。

Big Sur標準のOpenSSHのバージョンが-sk非対応の8.2未満なのでHomebrewを使います。macOS付属のOpenSSHが8.2以上になり、 /usr/libexec/ssh-sk-helper が追加された暁にはクライアント側までスキップしてください。

libfido2もインストールされました。ありがたいです。権限周りはどうにかして欲しいですが… Intel Macであれば何もしてなければ /usr/binより前に/usr/local/bin にPATHが通っているのでそのまま使えるはずです。/usr/localを前に出すのもPATHに入れるのも躊躇する派(危険性うんちゃらよりもデフォルトとの違い重視、POSIX標準でないGNUのツールが前に来ると泣いちゃうからですが、/usr/local/binにユーザが書けるというのはどうでしょう。その人専用機前提ですね…)なので~/.zshrc(お使いの$SHELLに合わせて)でaliasしておきます。後ほど再度いじります。

良さそうです。

macOS: クライアント側

クライアント側を整えていきます。

FIDO2対応のYubiKeyの場合はYubiKeyのFIDO2 PINを訊かれます。入力するとピカピカ光ってタッチを要求されます。タッチすると鍵情報を保存するファイル名を訊かれます。入力すると鍵情報ファイルを暗号化するためのパスフレーズを訊かれます。このパスフレーズは-O residentを指定した場合のYubiKey内の鍵情報には適用されません。あくまでもファイル(ここでは鍵ハンドルが格納されている~/.ssh/id_ed25519_sk)の暗号化のためのものです。またFIDO2の -O verify-required についてはOpenSSH 8.4からとなっていて現時点(as of 2021-10-15)でソースからのビルドが必要な環境が出てくるので後日検証にしてしまいます。今回は -O オプションの指定はしないで進行します。

ssh-agent周りのあれこれ

macOS付属のssh-agentはがっつりSIP(電話ではなく)に守られた /System/Library/LaunchAgents/com.openssh.ssh-agent.plist で起動します。なので戦わずに共存する道を探ります。macOS付属のOpenSSHが8.2以上になった暁にはサーバ側までスキップしてください。またYubiKey使う旨みが減りそうですがssh-agentを使わないで試す場合にもスキップしてください。今回は2つの方法を試しました。

macOSでAppleがカスタマイズしていないssh-agentを使う – 方法1

何からssh-agentを起動するかはmacOSなのでlaunchdが便利です。launchdがmacOS付属のssh-agent用の環境変数SSH_AUTH_SOCKを設定するため、これを上書きする手順はなんにせよ必要になります。 /System/Library/LaunchAgents/com.openssh.ssh-agent.plist で使われている SecureSocketWithKey はソケットに通信が発生してからssh-agentを起動する、遅延起動式で、図にするとこんな感じになります。

これをproxyすればAppleがカスタマイズしていないssh-agentも使えるはずです。こんな感じです。

Appleがどのように手を入れているかはSource Browserで確認でき、ncやsocatではできないことがすぐにわかります。ncやsocatのパッチを作るのも良いかもしれません。あと引き数をコマンドライン以外から受けるパッチもでしょうか。というわけでpsコマンドなどで見えるコマンドラインにソケットの場所を書きたくないのもあり、さくっとproxyを書きます。C++でソケットプログラミングとか何年ぶりかわかりませんがc++XX情報のアップデートもしながら書いてみました。たのすぃ~。ひゅう~。C++ファイルひとつでMakefileもいらんだろうという…

-std=c++20が使えるコンパイラが無い場合はインストールします。

コンパイル、リンクします。

配置します。ここでは~/bin/をコマンド置き場、~/tmp/をデバッグログなどの出力先、 ~/Library/LaunchAgent をplistを置く場所とします。また設定ファイル内では ~/ は /Users/est/ としているので、ご自身の環境に合わせます。

~/Library/LaunchAgent/local.method1.plist を編集します。launchd-sock-proxyを置いた場所に合わせてください。ssh-agentが /usr/local/bin/ssh-agent ではない場合は、フルパスをlaunchd-sock-proxyの第一引き数に渡してください。直後に<string>/..(その場所)…./ssh-agent</string>を追加します。

plistの文法チェックをしてロードします。

zshをお使いならば.xshrcを参考に.zshrcに追記、kshをお使いならば.xshrcを参考に.kshrcに追記、tcsh, cshをお使いならば.cshrcを参考に~/.cshrcに追記します。SSH_AUTH_SOCKの上書きです。macOS標準のsshコマンド群も同時に使いたい場合は上書きしないでaliasなどで指定することもできるので、後述の方法2のaliasを参考にしてください。

新しいシェルを起動するか今のシェルに環境変数を適用してSSH_AUTH_SOCKが変わることを確認し、実際に動かします。

/usr/local/bin/ssh-agent など目的のssh-agentが動いているようでしたら、既存のシェルがどちらを利用する設定なのかわからなくなるので一度ログインしなおすか、再起動してしまうのが良いかもしれません。

macOSでAppleがカスタマイズしていないssh-agentを使う – 方法2

方法1と同じくlaunchdを使うとして、こちらは単純にssh-agentの遅延起動無しでさっさと起動してしまう方法です。ssh-agentがkillされた場合はソケットの場所が変わり、それを必要な人に通知する方法が必要です。コマンドラインでソケットの場所を指定するのは方法1同様に避けます。ストレートフォワードにこんな感じになるかと思います。

環境変数を .xshrc で上書きするのが -a で終わるファイル、実行時に取得してその場だけで使うのが -b と -c で終わるファイルです。-c で終わるファイルは、~/bin/ssh-add などに symlink して使います。どれでも状況に応じて好きなものをお使いください。

macOS: サーバ側

公開鍵をサーバまで持っていきログインするユーザの ~/.ssh/authorized_keys に追加、無ければ作成して追加します。

設定はこれだけで、既に8.2以降のOpenSSHサーバが動いている場合はそのまま利用できるので接続までスキップしてください。

macOS: サーバも同じ機械で動かす

同じ機械ですでにmacOS付属のOpenSSHサーバを動作させている場合は、間違わないように停止すると良いかもしれません。

システム環境設定 → 共有: リモートログインのチェックを外す

クライアントOSでわざわざsshdを自力でインストールして動かし続けるのを強くお勧めはしないので簡単に。万が一動かし続ける場合は適切な設定に加えてHomebrewおよびOpenSSHの脆弱性情報によく注意されてください。

/usr/local/etc/ssh/sshd_config を適切に設定します。macOS付属のOpenSSHと区別がつくように、ポートを設定します。HostKeyを明示している場合はEd25519の鍵を参照するように指定します。HostKeyを明示する場合は今の世の自分用にecdsa-skを使うとき以外では不要なECDSAを有効にする必要はないです。

起動します。止め忘れないようにフォアグラウンドで動かします。

別のターミナルから確認します。

macOS: 接続

いよいよ接続です。どんどんいきます。

まず鍵ハンドルファイルのパスフレーズを訊かれ、入力するとYubiKeyがピカピカし始めるので、タッチすればログインできます。念のため繰り返して、再度パスフレーズを訊かれることを確認しました。続いてssh-agentを試します。

ssh-add した際に訊かれたパスフレーズを最後に、あとはしれっとYubiKeyが点滅するのでタッチするだけです。点滅が目に入る場所にYubiKeyがない場合は、SSHあるあるの逆引きで手間取ってるのかと思って一息ついてしまうところです。-sk鍵タイプの場合はタッチ要求されるかもよと一言表示してもらえると嬉しいかもと思いました。

ssh-agent を使うと-sk鍵タイプ以外では何もなかったかのようにログインできるところを-sk鍵タイプではタッチが必要となり、期待していた安心感が得られそうなのでめでたしです。Appleがカスタマイズしているssh-addは-KオプションがKeychainに追加するために使われていますが、純正ssh-addの-Kはdiscoverable credentialsの読み込みとなっているのでどうなるでしょうか。

macOS: 番外編 THETIS

YubiKey以外にもFIDO U2Fデバイス持っていることを思い出したので試しました。もう近所の通販では買えないようですが、Thetis FIDO U2F Security Keyというものです。YubiKeyは鍵とぶつかり合ってUSBの接点が削れるような荒い使い方をしていたのでカバー付きのThetisを結構気に入ってましたが、荒い使い方はUSB-CのYubiKey 5Cにその座を奪われました。

こちらはP-256曲線のECDSAでちゃんと使えました。FIDO2デバイスではないのでPINの入力は求められず、-O residentによるdiscoverable credentials(CTAP2.1)も作成できませんでした。

macOS: Monterey

現状は以下のような感じでした。ご参考まで。

TODO

  • proxyのデータをインターセプトして-sk以外はmacOS付属のssh-agentに流すようにしてKeychainの恩恵を得られるようにする?面白いけどパスワードはKeePassXCなのでKeychainどうでもよいしOpenSSH 8.2以降に対応するまでの命だからどうだろ。

次回はUbuntu、その次はFreeBSD、その次はCygwinです。ごきげんよう。

コメントを残す

メールアドレスが公開されることはありません。