YubikeyでLinuxサーバへの二要素認証sshログインを行う

Yubikeyというデバイスをご存じだろうか? 簡単に説明すると、鍵ファイルを中に保管しておくハードウェアトークンで、中央にある円をタップするとパスワード(基本はワンタイムパスワードだが、静的なパスワードも設定可能)が自動入力される。 鍵ファイルは直接読み込めず、パスワードで保護されている。 ハードウェアによる二要素認証に利用できる便利なツールだ。 ワンタイムパスワードカードの自動入力版と考えると分かりやすいかもしれない。

詳細については、以下の記事が良くまとまっているのでそちらを参照するとよいだろう。

今回はLinuxへのsshログインにおいて、二要素認証の一つとしてこのYubikeyによる認証を設定する。 環境として、クライアントおよびYubikeyの設定はWindows 10、サーバ側はCentOS 7およびUbuntu Server 16.04 LTSを用いる。 YubikeyはミドルエンドのYubikey4を用い、接続にはTeratermを用いる。二要素認証の方法としてはpamでのOATH OTP(Yubico OTPというものもあるのだが、オンライン状態じゃないとログインできなくなるので割愛)と通常のパスワード認証の2つを用いるものとする。

1. Yubikeyの設定

まずはYubikeyの設定を行う。

YubiKeyの諸々の設定を行うには、『Yubikey パーソナライゼーションツール』というものが必要になるので、これのWindows版をインストールしておく。

インストールについては.exeを実行するだけなので省略。

インストールが完了したら、スタートメニューから「YubiKey Personalization Tool」を起動する。 以下のように認証方式の一覧が表示されるので、「OATH HOTP Mode」を選択する。

作成Modeについては「Quick」を選択する。

この時点で、すでにシークレットキーなどはランダムに作成されているので、必要な個所だけ変更(OAHT Token Identifierのチェックを外してConfiguration SlotやHOTP Lengthの変更など)して「Write Configuration」をクリックし設定を書き込む。

CSVファイルでシークレットキーなどは出力されるので、それらは後程利用する。

2. sshサーバ側の設定

sshサーバ側では、まず以下のコマンドを実行しpamでOATHを利用できるようパッケージをインストールする。

sudo yum install -y epel-release;sudo yum install -y pam_oath oathtool policycoreutils-python # RHEL系の場合
sudo apt install -y libpam-oath oathtool # Debian/Ubuntu系の場合

パッケージインストール後、「/etc/pam.d/sshd」に以下の内容を追記し、sshログイン時に「pam_oath.so」を読み込むよう設定する。

auth required pam_oath.so usersfile=/etc/users.oath window=30 digits=8

CentOSなどの場合、SELinuxの権限回避のため「/etc/liboath」配下に設置するほうがいいだろう(SELinux無効化してるなら/etc直下でも問題なし)。

auth required pam_oath.so usersfile=/etc/liboath/users.oath window=30 digits=8
[root@BS-PUB-CENT7-01 ~]# cat /etc/pam.d/sshd
#%PAM-1.0
auth       required     pam_sepermit.so
auth       substack     password-auth
auth       required     pam_oath.so usersfile=/etc/liboath/users.oath window=30 digits=8
auth       include      postlogin
# Used with polkit to reauthorize users in remote sessions
-auth      optional     pam_reauthorize.so prepare
account    required     pam_nologin.so
account    include      password-auth
password   include      password-auth
# pam_selinux.so close should be the first session rule
session    required     pam_selinux.so close
session    required     pam_loginuid.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session    required     pam_selinux.so open env_params
session    required     pam_namespace.so
session    optional     pam_keyinit.so force revoke
session    include      password-auth
session    include      postlogin
# Used with polkit to reauthorize users in remote sessions
-session   optional     pam_reauthorize.so prepare

次に、「/etc/users.oath」ファイルを新規で作成する。

/etc/users.oath
#type username pin start seed HOTP <ユーザ名> <OATH Token Identifier(なければ「-」)> <シークレットキー>
[root@BS-PUB-CENT7-01 ~]# cat /etc/liboath/users.oath # CentOSなので/etc/liboath配下に設置
#type   username        pin     start seed
HOTP    root    -       a4fe20a4b209f6bc9ec9aa1a473d69f1bcabd039

ファイル作成後、パーミッションを600、所有者・グループともにrootにする。 CentOS の場合はさらにSELinux関係の権限についても設定を行う。

chmod 600 /etc/liboath/users.oath
semanage fcontext -a -t systemd_passwd_var_run_t '/etc/liboath(/.*)?' # SELinux対応
restorecon -rv /etc/liboath/ # SELinux対応

sshdの設定を変更し、以下の項目について変更する。

PasswordAuthentication no
ChallengeResponseAuthentication yes

設定変更完了後、sshdを再起動する。

systemctl restart sshd

3. ログインの実行

さて、設定が完了したら、実際にログインしてみよう。 クライアントにTeratermを使っている場合は接続時の方式としてチャレンジレスポンスを用いる。

最初にユーザのパスワードを求められる(/etc/pam.d/sshdでの記述の順番による)ので、入力する。

次にワンタイムパスワードを求められるので、Yubikeyをタッチしてワンタイムパスワードを入力してやる。

で、無事問題なければログイン完了。

ちなみに、sudo実行時にワンタイムパスワードを要求する場合は、「/etc/pam.d/sudo」の一番上に、以下の内容を記述してやることで設定できそうだ。

auth sufficient pam_oath.so usersfile=/etc/users.oath window=30 digits=8