セキュリティキーを利用した多要素認証は、これまでも「利用者本人のみが所有するもの」という側面から、有効な認証の要素の一つとして利用されてきました。Googleでも2017年初頭からセキュリティキーを導入してから、アカウントの乗っ取りは報告されていないとコメントしています (2018年7月の記事です) 。
また、2019年3月にFIDO2の構成技術の一つであるWebAuthnがW3Cでも勧告 され、セキュリティキーや生体認証、モバイルデバイスなどにより、より簡単で安全にログインできるWeb認証が利用可能となりました。筆者もFIDO2準拠のセキュリティキーを購入したこともあり、今回はUbuntuでセキュリティキーを利用した多要素認証を試してみました。
セキュリティキーの選定
検索サイトなどで「FIDO2 セキュリティキー」のキーワードで検索すると、セキュリティキーの大手でもあるYubico社のYubikeyなどが出てきますが、今回筆者はYubikeyと互換性があり、Linuxにも対応しているSoloKeys社 のSoloをAmazon.com経由で3,000円弱(送料込み)で購入しました[1] 。形状としてはUSBメモリと似た外観でボタンのみが付いている、いたってシンプルなセキュリティキーです。
[1] Solokeysが販売するセキュリティキーはオープンハードウェアであり、Github 上にセキュリティキーのハードウェア設計図のリポジトリを置いています。腕に自信のある方は挑戦してみるのもよいかもしれません。
図1 セキュリティキーSoloの外観
本記事では、このSoloの利用を前提として多要素認証を試しています。他のセキュリティキーを使った場合でも、以降で説明するセキュリティキーの挿抜時におけるデバイス検出の設定を行うudevでのパラメータが異なること[2] を除くと、ほぼ同じような内容になるかと思います。
セキュリティキーの認識
セキュリティキーはUSBデバイスのため、udevを利用してデバイスを認識できるようにします。今回は「/etc/udev/rules.d/」上に管理者権限で「70-solokeys-access.rules」を作成し、以下の内容を追加します。
ACTION=="add", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", ATTRS{product}=="Solo*", TAG+="uaccess", GROUP="plugdev", KERNEL=="hidraw*", SUBSYSTEM=="hidraw"
udevadmコマンドでudevのルールを反映します。
$ sudo udevadm control --reload-rules && sudo udevadm trigger
udevのルールを反映後、セキュリティキーを挿入すると「/dev」配下に「hidraw*」( *は任意の数字)がデバイスとして追加されます。一般ユーザーでcatやechoを利用してエラーが出ないことを確認できれば、デバイスとしては正しく認識している状況です(以下は「/dev」配下に「hidraw0」として認識された場合で確認) 。
$ cat /dev/hidraw0
$ echo "Hello, Ubuntu" > /dev/hidraw0
WebAuthn+CTAP2を試してみる
セキュリティキーが検出できたところで少し寄り道となりますが、セキュリティキーの動作確認も兼ねて、FIDO2の中心的な構成要素であるWebAuthn+CTAP2を試してみましょう。
具体的なWebAuthnやCTAP2の概要に関しては、技術評論社の新春企画 やFIDO Allianceのサイト で紹介されているため、詳しい説明は今回省略します。
今回、WebAuthn+CTAP2の動作確認としてwebauthn.me というサイト利用します。このサイトではセキュリティキー(authenticator) 、ブラウザー(browser) 、サーバー(relying party)がどのようにしてWebAuthn+CTAP2を提供しているかをビジュアルで確認できます。
前項でデバイス認識が可能になったセキュリティキーを挿し、WebAuthnに対応したブラウザ[3] でアクセスして以下の流れを試してみましょう。
図2 webautn.me
「Register Your User」で、適当なユーザー名を入れ「REGISTER」ボタンを押す。
「Touch Your Authenticator」で、ブラウザからセキュリティキーをタッチするように要求される。ここでセキュリティキーのボタン(または、タッチパネルなど)を押す。
「Your New Credential」で、サーバ側に公開鍵情報などが登録される。「 NEXT」ボタンを押す。
「Authenticate With Your Credential」で、「 LOGIN」ボタンを押す
「Touch Your Authenticator」で、ブラウザからセキュリティキーをタッチするように要求される。ここでもセキュリティキーのボタン(または、タッチパネルなど)を押す。
「Login Successful」となる。
2や5のタイミングでセキュリティキーのボタンやタッチパネルを押しても次の挙動に移らない場合、セキュリティキーを認識していないことが考えられるため、再度デバイスとして認識しているか確かめてみてください。
執筆時点でWebAuthn+CTAP2にセキュリティキーを利用できるサイトは、筆者の知る限りではwebauthn.meのようなデモサイトが中心となりますが、Ubuntu上でも気軽に試すことができるでしょう[4] 。
[4] WebAuthn+CTAP2はDropboxで対応しています 。また、FIDO2仕様公開前からセキュリティキーを利用した多要素認証に対応していたサイト(Googleなど)は、FIDO1.0の仕様であるU2F(Universal 2nd Factor)を利用してるため、今後はWebAuthn+CTAP2に移行していくと思われます(FIDO2は後方互換性があるため、U2Fにも対応しています) 。
U2FをUbuntuで利用する
さて、UbuntuなどLinuxでの認証は、PAM(Pluggable Authentication Modules)を利用した認証がほとんどかと思います。
PAMはセキュリティキーが提供するU2F(Universal 2nd Factor)と連携することで、GUIログインやsudoの多要素認証でセキュリティキーを利用できます。アカウントの認証時、パスワードを入力した後に他要素認証としてセキュリティキーをタッチすることで、ログインやsudoが可能になるとイメージすればよいでしょう。
U2FをUbuntuに連携させる前に
PAMとU2Fを連携した後、様々な理由(セキュリティキーの紛失や破損、設定の誤りなど)で、GUIログインやsudoができなくなる可能性があります。このような状況に出くわした場合、セキュリティキーを利用せずにシステムの復旧を行うことになるでしょう。このため、もしもの場合の復旧方法について事前に想定しておくことを『強く』おすすめします。
例として、openssh-serverを導入してSSH経由でログイン、シングルユーザーモードでのログイン、HDDを別システムにマウントさせてアクセス、従来のパスワードログインだけのユーザーアカウントを作成など、様々な方法があります。利用環境の状況にあわせて想定しておきましょう[5] 。
[5] 筆者の場合、従来のパスワードログインのみユーザーアカウントを作成し、もしもの場合はこのユーザーでメインのアカウントのU2F設定を削除できるようにしています。セキュリティとしては従来と同様になる可能性はありますが、大事なものを失うよりはよっぽどマシであろうとの認識です。
また、GoogleやFacebookなどのWebサービスだけで多要素認証が利用したいだけである場合は、これまでの設定で利用できるので以降の設定は不要です。
事前準備
事前準備として、設定に必要となるpamu2fcfgとlibpam-u2fを導入します。18.04LTSあればuniverseで提供されています。
$ sudo apt install pamu2fcfg libpam-u2f
以下のようにU2F対応にするアカウントで、設定に必要となるディレクトリ「~/.config/Yubico」を作成した後、pamu2fcfgコマンドでこのディレクトリに、U2F実行時のユーザー名とトークンのマッピングとなる「u2f_keys」ファイルを作成します。
$ mkdir ~/.config/Yubico
$ pamu2fcfg > ~/.config/Yubico/u2f_keys
ポイントとして、pamu2fcfgコマンドを実行したタイミングで、セキュリティキーのボタン押す(またはタッチパネルをタッチ)必要があります。押されてない場合は、しばらくすると「Unable to generate registration challenge, error in transport layer (-2)」と表示されます。この場合は再度pamu2fcfgコマンドからやり直ししましょう。
ここまで完了したら、U2F対応の事前準備は完了です。
sudoをU2F対応にする
sudoをU2F対応させる場合、「 /etc/pam.d/sudo」ファイルにPAMの設定を追加します。このファイル内にある「@include common-auth」直下に、以下の行を管理者権限で追記します。
auth required pam_u2f.so nouserok cue
PAMの細かい仕様については省略しますが、上記はsudoのパスワード認証後にu2fによる認証を行う設定です。オプションである「nouserok」は「~/.config/Yubico/u2f_keys」ファイルがないユーザーを無条件で認可する設定で、「 cue」は「~/.config/Yubico/u2f_keys」ファイルを持つユーザーに対して、セキュリティキーのボタンを押すようにプロンプトを表示させる設定です。設定の反映については次回実行時から反映されます。
では、以下のようにsudoコマンドを試してみましょう。パスワード認証の後に、セキュリティキーのボタンを押すようにプロンプトが表示されます。
$ sudo echo "Hello"
[sudo] noa のパスワード:
Please touch the device.
この状態でセキュリティキーのボタンを押すと、以下のようにechoコマンドが実行されます。
Hello
なお、リモートアクセス先として利用する環境でU2F対応を行うと、リモートから物理的にセキュリティキーを押すことができないため、sudoの実行ができなくなります。導入に際してご注意ください。
GUIログインをU2F対応にする
GUIログインでU2F対応を行う場合、対応するディスプレイマネージャーが利用するPAMの設定にU2Fを関連付けます。今回はUbuntuのデフォルトの環境となるGnomeのディスプレイマネージャーの設定ファイル「/etc/pam.d/gdm-password」にPAMの設定を追加します。このファイル内にある「@include common-auth」の直下に、以下の行を管理者権限で追記します。
auth required pam_u2f.so nouserok
前述のsudoの設定から「cue」が抜けているだけですが、これはGUIログインであるためプロンプトが不要となるからです。設定の反映についてもsudo同様、次回実行時から反映されます。
これにより、U2F対象となるアカウントで、パスワード認証後にセキュリティキーのボタンを押すとログインが可能になりました。なお、スクリーンロックから復活する際にもセキュリティキーが必要となるのでご注意ください。
セキュリティキーを抜いたらスクリーンをロックする
セキュリティキーを抜いた際にスクリーンロックできるようにすると、うっかりロックを忘れることもないでしょう。仕組みとしては、セキュリティキーを抜いた際にudevがスクリーンロックを行うコマンドを実行すれば実現できます。
まずは、スクリーンをロックするコマンドの作成を行います。Gnomeの場合、D-Bus経由でスクリーンロックをするのがよさそうです。以下のスクリプトは、各ユーザでデスクトップを起動しているセッションを探し、存在する場合はスクリーンロックを行うスクリプトです。このファイルを「/usr/local/bin」以下に「gnome_lock_all_sessions」の名前でファイルを作成し、管理者権限で保存します。
#!/bin/sh
for bus in /run/user/*/bus; do
uid=$(basename $(dirname $bus))
if [ $uid -ge 1000 ]; then
user=$(id -un $uid)
export DBUS_SESSION_BUS_ADDRESS=unix:path=$bus
if su -c 'dbus-send --session --dest=org.freedesktop.DBus --type=method_call --print-reply /org/freedesktop/DBus org.freedesktop.DBus.ListNames' $user | grep org.gnome.ScreenSaver; then
su -c 'dbus-send --session --type=method_call --dest=org.gnome.ScreenSaver /org/gnome/ScreenSaver org.gnome.ScreenSaver.Lock' $user
su -c 'logger "Secure key removed."'
fi
fi
done
作成した「/usr/local/bin/gnome_lock_all_sessions」ファイルに実行権限を与えます。
$ sudo chmod +x /usr/local/bin/gnome_lock_all_sessions
『セキュリティキーの検出』の項で作成した「/etc/udev/rules.d/70-solokeys-access.rules」に管理者権限で以下のudevルールを追加します。
ACTION=="remove", SUBSYSTEM=="usb", ENV{PRODUCT}=="483/a2ca/100", RUN+="/usr/local/bin/gnome_lock_all_sessions"
このudevルールはSoloでの場合のため、その他のセキュリティキーの場合は「ENV{PRODUCT}==」の値が異なるでしょう。その場合は以下のようにudevadmコマンドを実行し、セキュリティキーを抜いたタイミングで出力される環境変数を参考にして設定しましょう。
$ udevadm monitor --environment --udev -s usb
udevルールの追加ができたら、先ほどと同様にudevadmコマンドでudevルールを反映します。
$ sudo udevadm control --reload-rules && sudo udevadm trigger
セキュリティキーを抜いたタイミングでスクリーンロックが行われていることを確認してみてください。スクリーンロックが行われない場合は、udevのルールを見直してみるとよいかもしれません。