LoginSignup
8
10

More than 5 years have passed since last update.

PAMで特定のユーザだけ別の認証をしたい場合

Last updated at Posted at 2016-11-30

最近二要素認証だったりでPAMを使うことが増えました。
ですが、二要素目が keyboard-interactive になることが多く、複数の二要素認証を使い分けようとするとどうすれば良いか困ったのでメモとして残しておきます。

ただ、色々試していてこれで行けそうという感じなので、本当に理解が正しいかはわかりません(PAMの設定は難しすぎる)。
こういう意味だ、とかこうした方が良い、などありましたらご指摘下さい。

主に auth の箇所について書いてます。

環境

以下の環境で試しました。

  • OS
    • CentOS 6.5
  • PAM
    • 1.1.1
  • OpenSSH
    • 5.3p1

SSHの設定

今回はDUOYubikeyが利用したいとします。
その場合、sshd_configに分けて書ければ良いのですが、大体以下のようになってしまいます。

$ cat /etc/ssh/sshd_config
...
RequiredAuthentications2 publickey,keyboard-interactive

OpenSSHのバージョンによっては以下のようになります。

AuthenticationMethods publickey,keyboard-interactive

Yubikeyの場合もDUOの場合も keyboard-interactive となってしまいsshdの設定では使い分けできません。
そこで、何とか分けられないかなと思ってPAMの設定をしてみました。

PAMの設定

PAMでは成功した場合や失敗した場合の処理が設定可能です。
詳細は参考ページを見て頂けると分かると思います。

PAMでは基本的に上から順にチェックされていきます。
例えば、以下のように書いた場合だと success=2 というのが成功した場合に2行スキップされることを意味します(pam_permitへ行く)。
default=ignore は失敗した場合は無視して次の行へ移動することを意味しています。

auth    [success=2 default=ignore]  pam_unix.so nullok_secure
auth    [success=1 default=ignore]  pam_winbind.so krb5_auth  try_first_pass
auth    requisite           pam_deny.so
auth    required            pam_permit.so

このようにスキップをうまく使えばif文のように書けるので特定のユーザだけ別のPAMで認証させることができそうです。

pam_succeed_if.so というのがあるので、これを使ってみます。
以下のように書けるかと思います(コメントのあとは目印として記号を振っているだけです)。

auth      required pam_sepermit.so 
auth      [success=ignore ignore=ignore default=1] pam_succeed_if.so user in test1:test2 # - (a)
auth      [success=done default=die]        pam_duo.so # - (b)
auth      [success=done default=ignore] pam_yubico.so id=XXXXX key=hoge authfile=/etc/yubikey_mappings # - (c)
auth      required                      pam_deny.so # - (d)

(a) まず pam_succeed_if.so を使ってユーザの判定を行っています。
user in test1:test2 のところでtest1かtest2のユーザの場合のみ成功を返します。
success=ignore なので、成功した場合は次の行(b)へ行き、 pam_duo.so で認証が行われます。
失敗した場合はdefault=1なので1行スキップされ、 pam_yubico.so の認証(c)が行われます。
ちなみに ignore=ignore がないとエラーが出ますが、まだよく分かってません。

(b) ここでは success=done なので成功した場合は終了、 default=die なので失敗した場合も終了します。

(c) success=done なのでここで成功すれば終了で、 default=ignore なので失敗した場合は次の行(d)へ行きます。

(d) 最後に pam_deny.so に行き失敗します。

まとめるとユーザがtest1かtest2の場合はDUOで認証され、それ以外のユーザの場合はYubikeyで認証されます(多分そうなっているはず。。)

擬似コード

口で説明してもよくわからないと思うので pam_succeed_if.so 以降に関して擬似コードを書きました。
大枠こんな感じだろう、と僕の中では思ってますが、正確ではない可能性があります。
正確な挙動を知ってる人がいたら教えてください。

if user in ["test1", "test2"]:
    result = duo()
    if result == success:
        return success
    else:
        exit(1)
else:
    result = yubico()
    if result == success:
        return success
    else:
        deny()

参考

8
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
10