普通に libpam-google-authenticator を PAM の設定に追加するだけだと公開鍵認証の時に使われなくて二要素認証として嬉しくなかったのと、 libpam-google-authenticator による二要素認証をいきなり全ユーザーに導入してしまうと google-authenticator コマンドによるトークン作成をしていないユーザーが入れなくなってしまったり、リモートバックアップ処理の自動実行などで入れなくなったりして困るので、 一部のユーザーだけ二要素認証が必須になる設定を考えてみました。

対象バージョン

  • Debian GNU/Linux 8.4 (jessie)
  • openssh-server 1:6.7p1-5+deb8u1
  • libpam-google-authenticator 20130529-2

設定時の注意

PAM の設定変更は失敗するとログインできなくなって危険なので、設定を戻したりできるシェルを最低一個は残した状態で設定を変更することをおすすめします。

PAM の設定

PAM の設定では @include common-auth の代わりに pam_unix.sopam_google_authenticator.so に置き換えた設定を /etc/pam.d/sshd に追加しました。

これで keyboard-interactive 認証では unix password による認証は使えなくなって libpam-google-authenticator による認証だけになります。

ワンタイムパスワードなので、入力している値を見られても困らないし、実際 GitHub などでの入力画面では隠されていないので、 /usr/share/doc/libpam-google-authenticator/README.gz にも書いてある echo_verification_code の設定も追加してエコーバックされるようにしてみました。

/etc/pam.d/sshd:

+auth [success=1 default=ignore] pam_google_authenticator.so echo_verification_code
+auth requisite pam_deny.so
+auth required pam_permit.so
 # Standard Un*x authentication.
-@include common-auth
+#@include common-auth

sshd の設定

他の pam_google_authenticator.so 導入記事にも書いてあるように ChallengeResponseAuthenticationyes に変更します。 この設定を変更しないと Verification code: の入力プロンプトが出てこなくて、 認証コードの入力ができません。

/etc/ssh/sshd_config:

ChallengeResponseAuthentication yes

最後に適当なグループ (今回は /var/log/ のログファイルのグループなどに利用されている adm グループを利用しましたが sudo グループなどでも良いかもしれません) を Match で指定して、そのグループに属するユーザーの時だけ AuthenticationMethods で公開鍵認証と keyboard-interactive 認証の両方を必須にしました。

/etc/ssh/sshd_config:

Match Group adm
AuthenticationMethods publickey,keyboard-interactive

トークンを生成しているユーザーだけ有効にする設定

google-authenticator コマンドで ~/.google-authenticator を生成しているユーザーだけ有効にすることができたので、その方法もメモしておきます。

方法としては pam_exec を使ってファイルの存在チェックをすれば可能でした。 pam_exec.so の引数部分では直接環境変数展開ができなかったので、別途外部に実行ファイルを用意する方法がデバッグもしやすくておすすめです。

存在チェックが成功すればそのまま次の行に進んで、存在しなければ後続の 2 行を飛ばして pam_permit.so で許可するようにしました。

PAM の設定の詳細については大統一Debian勉強会 特大号 東京エリア/関西Debian勉強会のPDF か、大統一Debian勉強会 の「Linux-PAMの設定について」の発表資料を参考にしてください。

pam_exec.soquiet をつけないと ~/.google-authenticator がない場合に毎回 /usr/local/bin/check_google_authenticator.sh failed: exit code 1 が出るので、 quiet をつけて抑制するようにしました。 Authenticated with partial success. というメッセージは ssh が出しているので消せませんでした。

/etc/pam.d/sshd:

auth [success=ignore default=2] pam_exec.so quiet /usr/local/bin/check_google_authenticator.sh
auth [success=1 default=ignore] pam_google_authenticator.so echo_verification_code
auth requisite pam_deny.so
auth required pam_permit.so

存在のチェック用スクリプトは pam_exec 経由で実行された時には HOME 環境変数が設定されていなくて、代わりに PAM_USER などが設定されているのを利用して HOME を設定されていなければ設定するようにしました。

/usr/local/bin/check_google_authenticator.sh:

#!/bin/sh
: ${HOME:=$(getent passwd "$PAM_USER" | awk -F: '{print $6}')}
test -f "$HOME/.google_authenticator"

/etc/pam.d/sshd にまとめる書き方

発表資料の PDF を確認して気付いたのですが、 [ ] でくくれば空白の入った引数も渡せるので、シェルを経由するようにすれば変数展開付きのコマンドを含められました。

/etc/pam.d/sshd:

auth [success=ignore default=2] pam_exec.so quiet /bin/sh -c [: ${HOME:=$(getent passwd "$PAM_USER" | awk -F: '{print $6}')}; test -f "$HOME/.google_authenticator"]
auth [success=1 default=ignore] pam_google_authenticator.so echo_verification_code
auth requisite pam_deny.so
auth required pam_permit.so

google-authenticator コマンドによるトークンの作成

二要素認証を使うユーザーで google-authenticator コマンドを実行してトークンを作成して、 iOS なら Google Authenticator のアプリに、 Android なら Google 認証システムアプリに QR コードを読み込ませておきます。 google-authenticator コマンドの質問は全部 y で良いと思います。

設定は ~/.google_authenticator に保存されています。

テスト環境では QR コードは読み込ませずに emergency scratch codes を使っていたのですが、 emergency scratch codes は使っていくと ~/.google_authenticator からどんどん減っていくので、適当なタイミングで google-authenticator コマンドを使って再生成させないと入れなくなりそうでした。

失敗した設定例

MatchChallengeResponseAuthentication を設定しようとしましたが、 Directive 'ChallengeResponseAuthentication' is not allowed within a Match block というエラーで設定できませんでした。

公開鍵ごとに二要素認証の設定ができないか、検討してみましたが、使えそうな設定項目が見つかりませんでした。

Disqus Comments

Kazuhiro NISHIYAMA

Ruby のコミッターとかやってます。 フルスタックエンジニア(って何?)かもしれません。 About znzに主なアカウントをまとめました。

znz znz


Published