macOSでのTouch IDを使用したSSHキーの設定
Setting Up SSH Keys on macOS with Touch ID (nmattia.com)
要約
この記事は、macOSでTouch IDとSecure Enclaveを活用してSSHキーを安全に設定する方法を解説しています。まず、3つの簡単なコマンドでSSHキーを作成し、SSHがそれを使用できるように設定し、GitHubに登録する手順を説明します。次に、Secure Enclave、SSHキーチェーン、およびSSHサインインフローの仕組みについて詳細な技術的解説を提供します。
全文翻訳
macOSでのTouch IDを使用したSSHキーの設定
2026年10月19日
[画像: ブログ記事ソーシャルカード]
この記事の前半では、MacでSSHキーを作成するシンプルで安全な方法(GitHubのサポートを含む3つのコマンド)を紹介します。後半では、好奇心旺盛な読者のために、実際に何が起こっているのかを深く掘り下げて説明します。
Macには、盗むことが絶対に不可能な「ID」を作成できる、いわゆるSecure Enclaveが組み込まれています(おそらく国家に敵を作らない限り)。これらのIDはTouch IDで保護されており、SSH認証に使用できます。従来のSSHキーファイルを使用するよりも、いくつかの大きな利点があります。
- プライベートな素材は抽出できず、表示されず、盗むこともできません。
- IDが使用されるたびにプロンプトが表示されます。
- ファイルシステムに(
~/.ssh/id_ed25519.pubのような)キーファイルが散らばらず、誤って削除するリスクもありません。
この追加のセキュリティは、SSH、git-over-ssh(GitHubなど)を含むSSHを使用する際に有効になります。世界で最も広く普及しているコンピューターのいくつかに高度なセキュリティ技術がデフォルトで利用可能であることは素晴らしいことです!数年前、このようなものはCERNやダン・ブラウンの小説でしか見つけられませんでした。それをあなたのコンシューマーグレードのMacでどのように設定できるか見てみましょう。
人間インターフェースは使いやすさを考慮して設計されるべきであり、ユーザーが保護メカニズムを常に正しく適用できるようにする必要があります。
- Saltzer and Schroeder, “The Protection of Information in Computer Systems”
クイックセットアップ
Secure Enclaveに安全なIDを作成し、SSHに認証に使用する方法を教え、最後にGitHubにキーを追加します。
ステップ1:このMacで使用するIDを作成します:
sc_auth create-ctk-identity -l ssh-key -k p-256-ne -t bio # IDを作成するために一度実行
「Touch ID」に触れるように求められます。これでIDが作成され、安全に保存されました(パラメータについては詳細で説明します)。
ステップ2:SSHにIDを使用するように指示します(PINを求められたら、Enterキーを押すだけです):
ssh-add -K -S /usr/lib/ssh-keychain.dylib # 再起動後に実行
ここから、SSHは再起動後にリマインダーが必要ですが、SSH経由で接続する際にSecure EnclaveからのIDを使用するように認識します。
ステップ3:新しいサーバー(GitHubなど)にキーを登録する必要があるときはいつでも、このコマンドを実行します:
ssh-add -L # 公開キーが必要なときに実行
複数のIDがリストされている場合は、sk-ecdsa-sha2-nistp256...で始まる行を使用してください。これはIDの共有可能なハンドルであり、GitHubが尋ねるSSHキーです。
[画像: image]
ssh-add -Lの出力はGitHub SSHキーとして追加できます
これで、非常に安全なセットアップは完了です!新しいIDはSSHで使用できるようになり、認証中にTouch IDを求められます。
git push # Touch IDプロンプトをトリガーします
誰もあなたのIDを盗むことはできません(まあ、Secure Enclaveから抽出できないため、自分で意図的に譲渡することもできません)が、偉大な力には等々:Macが壊れたら、IDも壊れ、新しいIDを作成し(必要に応じてGitHubなどで再登録する必要があります)。
[画像: image]
gitがSSHで認証しようとすると、Touch IDプロンプトが表示されます
仕組みに興味がある場合は、読み進めてください!
内部の仕組み
ここでは、内部で何が起こっているのかを理解しようとします。Secure Enclaveでの実際のID作成から始め、次にSSHがssh-keychain.dylibでSecure Enclaveとインターフェースすることを許可する方法を見て、最後に完全なSSHサインインフローで何が起こるかを見ていきます。
これは、投稿(arianvpによるこの素晴らしい調査など)を読み、マニュアルページを参照し、実験した結果です。この多くは文書化されておらず、これが何が起こっているのかを理解し、それが実際に機能することを確認するために必要な最小限の情報です。
以下のコマンド出力の一部は、読みやすさのためにトリミングされています。完全な体験を得たい場合は、ローカルで実行することをお勧めします!
Secure EnclaveでのIDの作成
IDはsc_authコマンド(sc_はSmart Cardの略)で管理されます。Appleの言葉では、これらは「CryptoTokenKit」ID、または略してCTK IDです。なぜSmart Card Identityではないのですか?Smart Cardとは何ですか?わかりません!奇妙なAppleの語彙はたくさんありますが、実際にはSecure Enclaveに保存された秘密鍵です。
$ sc_auth list-ctk-identities
Key Type Public Key Hash Prot Label
p-256-ne 458F712F281B53C683F23FC02E69D44DAFDAA3DE bio ssh-key
クイックセットアップに従った場合、ここに1つのIDがあるはずです。これはsc_auth create-ctk-identityコマンドを実行したときに作成されました。create-ctk-identityコマンドを詳しく見てみましょう。
sc_auth create-ctk-identity -l <label> -k <key type> -t <protection>
p-256-neキータイプを使用すると、このコマンドはSecure EnclaveでIDを作成します。おそらく、まずエントロピーを収集し、次に秘密鍵マテリアルを生成し、ブックキーピングに必要なものを割り当て、指紋でのみアクセスできるようにします。
ラベルは自由形式で、キーに付けられた注釈にすぎません。キータイプは暗号設定(使用される楕円曲線)です。執筆時点では、次の値が受け入れられます:p-256|p-384|p-521|p-256-ne|p-384-ne。-neサフィックスは「Non-Extractable」を意味し、キーはエンクレーブ自体によって生成され、Secure Enclaveから抽出することはできません。SSHには署名のみが必要であり、これはSecure Enclave自体によって(そしてその上で)行われ、秘密鍵をエクスポートする必要はありません(または望ましくありません)。p-384曲線は(Open)SSHでサポートされていないため、これはp-256-neに絞られます。
最後に、protectionはbioまたはnoneのいずれかです。bioに設定すると、キーの使用には生体認証(Touch IDなど)が必要です。noneの場合、キーは依然として抽出(つまり盗難)できませんが、プログラムはSSHをサイレントに使用できます。bioの使用をお勧めしますが、YMMVです。git pullのたびにTouch IDプロンプトが表示されることにうんざりしている場合は、ここでnoneを使用したいかもしれません。
これでSecure Enclaveに掴みどころのないIDがいくつかできたので、SSHに認証に使用するように指示する方法を見てみましょう。
SSHとSecure Enclave間の翻訳
インピーダンスの不一致が少しあり、sshはデフォルトではIDを使用する方法を知りません。
$ ssh -T [email protected]
[email protected]: Permission denied (publickey).
SSHエージェントはSecure Enclave IDをそのまま使用できませんが、Appleはssh-keychain.dylibという小さな翻訳レイヤーを提供しており、これはすべての最近のmacOSバージョンでネイティブに利用可能なdlopen可能なライブラリです。
$ ssh-add -K -S /usr/lib/ssh-keychain.dylib
...
Resident identity added: ECDSA-SK SHA256:QZ+Cx6/AkS9sek9INtsXt6t7wuHOtA555CLJu8a8V7w
ここでは、-Kパラメータを介したFIDOスタイルの認証子に対するssh-addの組み込みサポートに依存しています。これにより、SSHエージェントは標準の秘密鍵(例:~/.ssh/id_ed25519)を読み取るのではなく、キーが「外部」(より良い言葉が見つからない)に保存されていると想定する必要があることを認識します。-Kのみの場合、ssh-addはUSBデバイス(YubiKeyを考える)から公開鍵を検索します。ただし、-S <provider>で「セキュリティキープロバイダー」を登録することで、この動作をカスタマイズできます。このプロバイダーはステートレスな動的にロード可能なライブラリである必要があり、まさに/usr/lib/ssh-keychain.dylibがそれです。インターフェースは文書化されていません(少なくとも私が意味のある方法で処理できるような方法では)、しかしssh-keychain.dylibが公開するものを調べることができます。
$ dyld_info -exports /usr/lib/ssh-keychain.dylib
/usr/lib/ssh-keychain.dylib:
-exports:
offset symbol
0x00001A2C _C_GetFunctionList
0x00000F30 _sk_api_version
0x00000F38 _sk_enroll
0x0000136C _sk_load_resident_keys
0x00000F40 _sk_sign
最も可能性が高いのは、_sk_load_resident_keysが(公開鍵の)IDのリストを返し、_sk_signが指定されたID(ここでは、residentは「例えばSecure Enclaveに常駐する」という意味)を使用してペイロードに署名することです。
IDがSecure Enclaveでどのように作成され、理論的にはSSHエージェントによってどのように使用できるかを見てきました。これをテストして、SSH接続が作成されたときに何が起こるかを見てみましょう。
ssh-keychainプロバイダーを使用したSSHサインインフロー
リモートSSHサーバーに認証するために何が必要か見てみましょう。常に、SSHエージェントは(1)認証に使用できる(公開)鍵のリスト、および(2)それらの鍵のいずれかに対する秘密鍵を持っていることをサーバーに証明する方法が必要です。
ssh-addが-S <provider>で最初に呼び出されると、_sk_load_resident_keysルーチンが呼び出され、FIDOスタイルの認証子上のすべての常駐鍵の公開鍵が返されます。これらはSSHエージェントに(対応するプロバイダー、つまりssh-keychain.dylibと共に)格納され、後で接続しようとするリモートSSHサーバーの候補として提供されます。(また、SSHエージェントが以前作成したSecure Enclave IDを認識したので、ssh-add -Lで対応するSSHスタイルの公開鍵を表示できます。)
SSH接続が開始されたとしましょう。リモートはエージェントによって提供された鍵の1つを受け入れ、「チャレンジ」してクライアントにそのIDを証明させます。エージェントは_sk_signを呼び出して、秘密鍵(受け入れられた公開鍵に対応)とチャレンジ(大まかに言えば)を使用して署名を作成します。これはSecure Enclaveに転送され、Touch IDをプロンプトし、承認されると、チャレンジに対する署名を返します。署名はサーバーに転送され、サーバーはクライアント(つまり私たち)が対応する秘密鍵を持っていることを確認できます。
これが実際にはどのように見えるか見てみましょう。
$ ssh -T [email protected]
[email protected]: Permission denied (publickey).
$ ssh-add -K -S /usr/lib/ssh-keychain.dylib
Enter PIN for authenticator:
Resident identity added: ...
$ ssh -vvv -T [email protected]
debug1: get_agent_identities: agent returned 1 keys
debug1: Offering public key: ssh: ECDSA-SK SHA256:QZ+Cx6/AkS9sek9INtsXt6t7wuHOtA555CLJu8a8V7w authenticator agent
debug1: Server accepts key: ssh: ECDSA-SK SHA256:QZ+Cx6/AkS9sek9INtsXt6t7wuHOtA555CLJu8a8V7w authenticator agent
debug3: sign_and_send_pubkey: signing using [email protected] SHA256:QZ+Cx6/AkS9sek9INtsXt6t7wuHOtA555CLJu8a8V7w
<この時点で、Touch IDプロンプトが表示されます>
Authenticated to github.com ([20.250.119.67]:22) using "publickey".
Hi nmattia! You've successfully authenticated, but GitHub does not provide shell access.
sshのデバッグログは、1つの鍵がエージェントによって提供され、受け入れられ、署名を作成するために使用されていることを示しています。サーバーが署名を確認した後、認証が付与されます(ただし、「GitHubはシェルアクセスを提供しません」)。
注意点:IDをSSHエージェントに登録するたびに、ssh-addはPINを求めます。これはどういうことですか?空のPINを入力しても機能するのはなぜですか?これは非常に安全ではないのではないでしょうか?
まあ、安全でないわけではありません!ssh-addにFIDOスタイルの認証子を使用するように指示すると、デフォルトの動作はPINを求めることだと推測します。これはUSB、YubiKeyスタイルの認証子を使用すると想定しているためです。しかし、ssh-keychain.dylibでそのすべてをショートカットします(そしてセキュリティはPINからではなく、指先の柔らかい皮膚から来ています。もっとクールです)。ユーザビリティの点ではあまり良くありませんが、理にかなっていると思います。(複数のFIDO認証子がある場合にどうなるかはわかりません。GitHubで私をサポートしてください。YubiKeyのコレクションを購入して実験します。)
結論
要約すると、やや不可解で文書化の少ない「Smart Card」ツールを使用して、「Secure Enclave」に「CryptoTokenKit」IDを作成できます。次に、文書化の少ないssh-keychain.dylibを使用して、Appleのsshが使用できる署名を生成するためにそのIDを使用できます。これらの文書化されていない情報が「実用的には非常に危険なので使用しないでください」と言わないという保証はありませんが、まあ、Appleのセキュリティに関するすべての話、彼らは私たちをだまさないでしょう、右?*
冗談はさておき、ほとんどの最新デバイスに組み込まれたSFスタイルのセキュリティモジュールはかなりクールです。より多くの人々がそれらを使用し、オープン性を推進すればするほど、企業からのサポートはより良くなるでしょう。私たちは良いものを持つことができます!
繰り返しになりますが、この多くはこのgistから派生しました。読むことを強くお勧めし、必要であればディスカッションで質問してください。
[この記事を楽しんだら、お知らせいただくか、ディスカッションに参加してください!購読して更新情報を受け取ることもできます。
macOSに関するその他のトピックは次のとおりです。