SSHでも二要素認証を使いたい

2024年12月06日 金曜日


【この記事を書いた人】
田口 景介

社会人生活の半分をフリーランス、半分をIIJで過ごすエンジニア。元々はアプリケーション屋だったはずが、クラウドと出会ったばかりに半身をインフラ屋に売り渡す羽目に。現在はコンテナ技術に傾倒中だが語りだすと長いので割愛。タグをつけるならコンテナ、クラウド、ロードバイク、うどん。

「SSHでも二要素認証を使いたい」のイメージ

IIJ 2024 TECHアドベントカレンダー 12/6の記事です】

今年のIIJアドベントカレンダーは「運用」がテーマということなので、運用に欠かせない必携ツール筆頭であるSSHを取り上げ、SSHの秘密鍵を安全に管理する方法について考えたいと思います。

  • たとえSSH秘密鍵が漏洩しても、安全を確保する方法
  • 踏み台サーバにSSH秘密鍵を置かずに利用する方法

SSH秘密鍵の安全な置き場所を考える

SSH秘密鍵は一般的に ~/.sshにファイルとして管理されていると思いますが、不安に感じることはありませんか?

  • ノートPCに保存しておいて、もしそのPCを紛失してしまったら?
  • リモートワークに利用しているPCで、どのように鍵を管理するべきなのか?

SSHの認証に用いられる公開鍵認証は、非常に強力な認証・暗号化の手段ではありますが、それはネットワークの経路上における安全に対してであり、秘密鍵の保管方法が不十分ではとても安全とは言えません。多くの場合、ファイルシステム上でのアクセス制御とパスフレーズで守られていると思いますが、モバイルデバイスやリモートワークを考えるとそれで十分とは言い切れません。

昨今ではWebアプリケーションへの認証に二要素認証を必須とする組織も増えていますが、それならばSSHでも二要素認証を活用したいところです。

SSHで二要素認証を利用するということ

SSHで二要素認証を要求するということは、次の条件を満たすということです。

  1. 事前に登録したデバイスからのみSSHクライアントでログインできる
  2. SSHでログインする際に、生体認証またはPINを要求する
  3. 踏み台サーバ(bastion server、jump serverなどとも呼ぶ)に鍵を保存することなく、目的のホストへログインできる

1と2でもって二要素認証とするのは言うまでもありませんが、3も重要なポイントです。なにしろ二要素認証を有効化すると、特定のデバイスからしかログインできなくなる(秘密鍵をデバイスの外に持ち出せない)にも関わらず、SSHで目的のホストへログインするにはまず踏み台サーバへ一度ログインするのが一般的です。すると、踏み台サーバから目的のホストへログインするにはどうすればいいのでしょう?この矛盾を解決する方法については後述します。

OpenSSH 8.2以降はFIDOをサポート

実のところ、OpenSSHはバージョン8.2(https://www.openssh.com/txt/release-8.2)以降でFIDOに対応しており、既に多くの環境で二要素認証を利用可能です。

実際にはOpenSSHだけでなく、各OSの対応や生体認証デバイスの対応なども併せて整える必要がありますが、今回は次の構成で実践してみます。なお、SSHで二要素認証を利用する場合でもサーバ側に特別な対応は必須ではないので、クライアント側の環境を整備すればひとまずOKです。

  • SSHクライアント
    • Windows 11 23H2(おそらく22H2では利用不可)
    • Windows for OpenSSH 9.8.1( https://github.com/powershell/Win32-OpenSSH
      • Windows 11標準のOpenSSHは利用不可
      • WinGetでインストールされるパッケージでは適切な権限設定が行われないため、MSIからのインストールを推奨(2024/11/11現在)
    • Dell XPS 13(指紋リーダー搭載)
  • sshd サーバ
    • Ubuntu 22.04
    • OpenSSH 8.2p1(ディストリビューション標準。特別な設定なし)

二要素認証用のSSH鍵を生成する

それでは早速実践してみましょう。

SSHで二要素認証を利用する手順は驚くほど普段のオペレーションと変わりません。具体的な違いは次の2点だけです。

  1. ssh-keygenを使って、二要素認証を有効化した鍵を生成する
  2. SSHでログインする際に、パスフレーズに加えて生体認証やPINを入力する

最近では鍵タイプにed25519を指定することが多いと思いますが、二要素認証を利用するには下記二種類のどちらかを利用する必要があります(skはsecurity keyの略)。もっとも、今のところed25519-skを利用できる環境が限られているため、通常はecdsa-skを選択すると良いでしょう(注1)。

  • ed25519-sk
  • ecdsa-sk

注1: おそらく、TPM(Trusted Platform Module)でサポートされる鍵タイプがECDSAであり、ほとんどのデバイスではED25519がサポートされていないことに起因する。Windows HelloはTPM2を前提としており、この仕様に引きずられているものと思われる。一方、WebAuthn QR Codeに対応したスマートフォンとAuthenticatorがあればed25519-skを選択してパスキーとして利用できるはずだが、筆者の手元では環境を整えることができなかったので断念した。生体認証デバイスを持たないデスクトップPCのことを考えると、「ed25519-sk + passkey + bluetooth経由でのスマートフォンによる生体認証」が広く普及する際の環境ではないかと思う。

ここでは例としてecdsa-skを選択します。すると、いつものようにパスフレーズを入力したあと、なんらかのセキュリティキーを利用した認証が追加で求められます。この環境ではWindows Helloを通じて指紋リーダーがセットアップされており、PCにオンボードで搭載されているTPMがセキュリティキーとして利用されます。

PS> ssh-keygen -t ecdsa-sk
Generating public/private ecdsa-sk key pair.
You may need to touch your authenticator to authorize key generation.
Enter file in which to save the key (C:\Users\hogehoge/.ssh/id_ecdsa_sk):
Created directory 'C:\\Users\\hogehoge/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in C:\Users\hogehoge/.ssh/id_ecdsa_sk
Your public key has been saved in C:\Users\hogehoge/.ssh/id_ecdsa_sk.pub
The key fingerprint is:
SHA256:SC6DxwCycnAgvz30MDC7p6zaREXFY+SPOS9oWUMN984 hogehoge@example.com
The key's randomart image is:
+-[ECDSA-SK 256]--+
|*.+ .++ .        |
|o* = .++ .       |
|o = =.+.. .      |
|.. X B = o       |
|  = O X S E      |
| o + B +         |
|  + + . .        |
| + .   .         |
|+ .              |
+----[SHA256]-----+

 

以上の作業が成功すると、いつものようにファイルid_ecdsa_skとid_ecdas_sk.pubに鍵が保存されます。

二要素認証を利用してログインする

あとの作業もいつもと変わりません。

  • id_ecdsa_sk.pubの内容をリモートホストのauthorized_keysに登録する
  • id_ecdsa_skをsshクライアントにidentity fileとして指定する

次のようにSSHを実行するとパスフレーズを求められるのはいつものとおりですが、続いて指紋認証が要求されます。もちろん、指紋認証に失敗すればログインできません。

秘密鍵を他環境に持ち出してみる

次に、ファイルid_ecdsaが漏洩した想定で他PCへコピーし、同様にログインを試みてみましょう。

結果はごらんのとおり、パスフレーズの入力に成功しても、続いてセキュリティーキーへのアクセスを試みます。ですが、そんなものは存在しないのでここで手詰まりです。このように、SSH秘密鍵が漏洩しても二要素認証を有効化していればリスクを軽減できるというわけです。

ssh-agentを利用する

最後に、踏み台サーバを経由してログインする場合について解説します。このユースケースへの回答はごくシンプルで、ssh-agentを利用するというものです。また、ログイン時にforward agentを有効化するのがポイントです。

  1. ssh-agentを起動し、秘密鍵を保存する
  2. SSHクライアントで踏み台サーバへログインする際、オプション-Aを指定してforward agentを有効化する

こうすると、踏み台サーバから目的のリモートホストへログインする際にスタート地点にいるssh-agentと通信し、あたかもそのデバイスから直接ログインを試みているかのように指紋認証が行われます。

それにしても、サービスとして実行されているssh-agentがどうやって生体認証を要求するのだろうと思いましたが、内部ではssh-agentがリクエストを受け付けるとssh-sk-helperをキックし、そのヘルパープログラムがセキュリティキーを使った認証を行っているようです。

まとめ

まだ環境が十分に整っているとは言い難い状況ですが、そろそろSSHでも二要素認証を考えても良いのではないでしょうか。

今やPCにしろスマートフォンにしろ、大概のデバイスにはTPMが搭載され、別途セキュリティキーが必須というわけでもありません。生体認証デバイスがなくとも、PINを利用すると良いでしょう(デバイス紛失時のリスクが気になりますが)。それに、サーバサイドには何一つ手を加えることなく、クライアント側のアップデートだけで利用できるので、思いのほかハードルが低いことをお判りいただけたのではないでしょうか。

ぜひ試してみてください。

IIJ Engineers blog読者プレゼントキャンペーン

Xのフォロー&条件付きツイートで、「IoT米」と「バリーくんシール」のセットを抽選でプレゼント!
応募期間は2024/12/02~2024/12/31まで。詳細はこちらをご覧ください。
今すぐポストするならこちら→ フォローもお忘れなく!

田口 景介

2024年12月06日 金曜日

社会人生活の半分をフリーランス、半分をIIJで過ごすエンジニア。元々はアプリケーション屋だったはずが、クラウドと出会ったばかりに半身をインフラ屋に売り渡す羽目に。現在はコンテナ技術に傾倒中だが語りだすと長いので割愛。タグをつけるならコンテナ、クラウド、ロードバイク、うどん。

Related
関連記事