PAM について考える。pam_ssh.so とか。

以下の文書は様々なセキュリティリスクについてアセスメントしてないんで参考程度にとどめておいてください。

PAM の auth の流れ

ステート図については⇒【http://corvus.kek.jp/~manabe/pcf/pam.htm】を参照。

書式についてはいっぱいころがっているので省略。で,コントロールフラグについて。

コントロールフラグは PAM モジュールが「成功」「失敗」のステータスを返した時にどのような処理を行なうかを指定します。基本は required, requisite, sufficient, optional の四種類です。

required (必要条件)
そのモジュールから成功のステータスが返る事を要求します。required となっているモジュールが失敗のステータスを返すと他のモジュールの処理の結果にかかわらずログインに失敗します。ただし、処理は打ち切られる事なく次のモジュールに進みます。
requisite (必須条件)
required と似ていますが、requisite となっているモジュールが失敗するとその時点でそのモジュールタイプの処理は打ち切られます。
sufficient (充分条件)
sufficient となっているモジュールが成功のステータスを返すと、既に required のモジュールのどれかが失敗していない限り、そのモジュールタイプの処理は成功と見なされ、以降のモジュールは処理されません。
optional (オプション)
optional とされているモジュールは通常はそのステータスを無視されます。しかし、他のモジュールが全て「無視」のステータスを返した場合、optional のモジュールのステータスが使われます。
http://memo.blogdns.net/pamandnss.html

なるほど。厳密な挙動については等価な[...]オプションを考えるとわかりやすいかも。

Each of the four keywords: required; requisite; sufficient; and optional, have an equivalent expression in terms of the [...] syntax.

They are as follows:

required:
[success=ok new_authtok_reqd=ok ignore=ignore default=bad]
requisite:
[success=ok new_authtok_reqd=ok ignore=ignore default=die]
sufficient:
[success=done new_authtok_reqd=done default=ignore]
optional:
[success=ok new_authtok_reqd=ok default=ignore]

http://www.kernel.org/pub/linux/libs/pam/Linux-PAM-html/sag-configuration-file.html

実例をもとに

RedHat 系のデフォルトな /etc/pam.d/system-auth(-ac) の auth 部分は

#%PAM-1.0
auth        required      pam_env.so
auth        sufficient    pam_unix.so nullok try_first_pass
auth        requisite     pam_succeed_if.so uid >= 500 quiet
auth        required      pam_deny.so

... snip ...

となってます。

  • (pam_env.so で system-wide な環境変数を設定する?;今回の話としては無視してかまわないです)
  • pam_unix.so でローカル認証(/etc/passwd)を行う。
    • 成功したら,認証成功でおしまい(sufficient)。
    • ローカル認証に失敗した場合,pam_succeed_if.so により,
      • uid < 500 の場合,ログを残さず(quiet)認証失敗でおしまい(requisite)
      • uid >= 500 の場合,pam_deny.so により(常に)認証失敗でログを残しつつおしまい

たぶんこういうことなのではないかなぁ。

gdm ログイン時に同時に ssh-add したい (1)

って pam_ssh.so を使うだけの話なのですが。

pam_ssh.so は auth と session について使えます。

  • auth で使うと,ssh Private 鍵のパスフレーズをもとに認証
  • session で使うと,セッション持続中に ssh-agent を起動
    • さらに auth で pam_ssh が認証成功していると,その鍵を自動的に ssh-add

という仕組みになってます。なので,pam_unix の代わりに pam_ssh をログイン認証に使ってみます。

/etc/pam.d/gdm の auth 部は

auth        required      pam_env.so
auth        include       system-auth

のようになってます。つまり system-auth の内容に準ずるわけですが,system-auth(-ac) の内容は変わりうるので,コピペしてそれを改変してみます。

まずはコピペ。

auth        required      pam_env.so
auth        sufficient    pam_unix.so nullok try_first_pass
auth        requisite     pam_succeed_if.so uid >= 500 quiet
auth        required      pam_deny.so

pam_env.so は被るので削除しました。

で,pam_unix.so の代わりに pam_ssh.so を使うのでそのまま置き換えます。あと,session 部分にも pam_ssh.so を利用するよう書きます。

#%PAM-1.0
auth        required      pam_env.so
auth        sufficient    pam_ssh.so try_first_pass
auth        requisite     pam_succeed_if.so uid >= 500 quiet
auth        required      pam_deny.so

... snip ...

session    optional    pam_keyinit.so force revoke
session    include     system-auth
session    required    pam_loginuid.so
session    optional    pam_console.so
session    optional    pam_ssh.so

これで gdm で再ログインすると,パスワードを聞かれる際に passphrase を入れろ,といわれますんで鍵のパスフレーズを入力してログイン。ps すると ssh-agent が常駐しているのがわかります。で,外部ホストに ssh かけるとパスフレーズ入力なしでログインできます。便利便利。

これでローカルパスワードを削除するというのも運用ポリシーとしておもしろいかもしれません。

gdm ログイン時に同時に ssh-add したい (2)

これだと key pair を作っていないユーザがログインできないので

  • passphrase を入力するとログインでき ssh-add してくれてる
  • passphrase ではなく UNIX password を入力するとログインできる

というポリシーを考えてみます。

というものズバリが FedoraNews にころがってました(⇒http://fedoranews.org/cms/node/1461。んが,微妙に書いている内容が間違っている気がします。まだしも古い内容(http://fedoranews.org/mediawiki/index.php/Logging_into_KDE_with_your_SSH_passphrase)のほうが正確かも(設定が古いですが)。

先ほどと同じように system-auth(-ac) の auth 部分を /etc/pam.d/gdm にコピーして

#%PAM-1.0
auth        required      pam_env.so
auth        sufficient     pam_ssh.so try_first_pass
auth        sufficient    pam_unix.so nullok try_first_pass
auth        requisite     pam_succeed_if.so uid >= 500 quiet
auth        required      pam_deny.so

... snip ...

session    optional    pam_keyinit.so force revoke
session    include     system-auth
session    required    pam_loginuid.so
session    optional    pam_console.so
session    optional    pam_ssh.so

このように pam_unix.so より前に pam_ssh.so をもってきます。

両方とも sufficient になっているので,まず pam_ssh.so で認証してから,だめだったら pam_unix.so で認証,になってくれる,はずです。ためしていないです。

gdm ログイン時に同時に ssh-add したい (3)

次に以下のようなポリシーの場合を考えてみます。

  • 認証はローカル認証(pam_unix; /etc/passwd)の成否によって決定する
  • ローカル認証 DB(/etc/passwd)のパスワードと ssh 鍵の passphrase は同じ

なんてひどいポリシー!。実際問題これも (2) でいいと思うんですが,実は一番最初に取り組んだのがこの課題で,なかなか頭をつかったので,せっかくなので書いてみます。

問題は,sufficient なコントロールフラグだと,成功するとそこで処理が終わってしまうんですね。だから単純に

auth        sufficient    pam_unix.so nullok try_first_pass
auth        optional      pam_ssh.so try_first_pass

とすると,pam_unix.so が認証に成功した時点で pam_ssh.so に移らず ssh-add されません。

なので,あれこれ考えた結果が,以下のようなものです。

auth        required      pam_unix.so nullok try_first_pass
auth        optional      pam_ssh.so try_first_pass
auth        sufficient    pam_permit.so
auth        requisite     pam_succeed_if.so uid >= 500 quiet
auth        required      pam_deny.so

pam_unix.so のコントロールフラグを required にすることで,後続のモジュールにも制御がわたされるようにします。で,pam_permit.so というのは常に認証成功するモジュールなのですが,sufficient というコントロールフラグは,以前の required なモジュールで成功となっている場合のみ評価されるので,pam_unix.so が成功した場合は認証成功で認証打ち切り,pam_unix.so が失敗した場合は無視されて後続の pam_deny.so 等にうつる,という挙動になります。

pam_permit.so はめっちゃ注意して使えよ,と man にも書いてあるのであまりいい解とはいえないのですが,他の方法がおもいつきませんでした。