PAMを利用したGNU/Linuxのセキュリティ管理
PAMという語からカナダの某ブロンド女優を連想する人もいるかもしれないが、このサイトの読者ならLinuxセキュリティの基本的な要素であるPluggable Authentication Modulesだとわかるはずだ。本稿では、こちらのPAMのしくみを説明し、ちょっとした使用例を紹介する。
もしLinuxのアプリケーションごとに独自の認証ロジックを用意しないといけないとしたら、大変なことになっていたはずだ。すべてのアプリケーションに同じチェック機構が実装されていることを、どうすれば保証できただろうか。また、追加の制御機能はどのように実装できただろうか。
PAMは、こうした問題に対するシンプルな解決策だ。ユーザの認証を必要とするプログラムは、PAMのAPIを呼び出すだけでよい。あとは、PAMの設定ファイルに記述されたルールに従って、APIの向こう側が必要なチェックを行ってくれる。認証のメカニズムは、その場で変更することもできる。その場合、PAMに対応したすべてのアプリケーションは、自動的に新しい認証手法の利用を開始する。
では、指紋リーダーや虹彩スキャナなど、バイオメトリクス認証を利用したい場合はどうだろうか。ハードウェアメーカー側がPAMを提供していれば、それらの利用も可能だ。そのモジュールを設定ファイルに記述するだけで、新しいデバイスがすべてのアプリケーションで使えるようになる。
設定
PAMライブラリの機能は、次の4つの領域に分かれている。
- auth:ユーザ名およびパスワードの入力などにより、ユーザの認証を行う。
- account:正当なユーザであるか、その行為が許可されているかなど、アカウントの制約をチェックする。
- session:ログの記録など、接続に関する管理を行う。
- password:パスワード関連の機能を専門に扱う。
PAMを利用するアプリケーションごとに、設定ファイルを「/etc/pam.d」ディレクトリに用意する必要がある。ログインの設定であれば、「/etc/pam.d/login」ファイルに記述する (すべての設定を「/etc/pam.conf」というファイル1つで済ませるという旧来の方法もあるが、最近はほとんど使われていない)。また、操作の“スタック(stack)”を作成することにより、適用するモジュールをグループ別に定義する必要がある。要求が処理される際には必ず、該当するスタックのモジュールを介してPAMライブラリが実行される。ユーザの要求は、PAMモジュールの出力に応じて許可または拒否されることになる。
こうした処理を正しく実行するには、以下のリストに従って、所定のモジュールが必須であるかオプションであるかを指定する必要がある。
- requisite:処理を継続するには、requiredモジュールが“success(成功)”を返さなければならない。このモジュールが失敗すると、PAMライブラリは“failure(失敗)”を返し、スタック内のほかのモジュールはそれ以上実行されない。
- required:これも必須のモジュールであるが、失敗した場合、PAMのAPIは“failure”を返すものの、同じスタック内のモジュールの実行は継続される。
- sufficient:このモジュールが成功すると、PAMライブラリは、その他のモジュールを実行することなく直ちに“success”を返す。
- optional:このモジュールの成否に関わらず、スタック内のモジュールの実行は継続される。すべてのモジュールの実行が完了した時点でPAMライブラリの成否が確定していない場合、成功したoptionalモジュールが1つでもあれば承認が与えられる。
PAMの設定ファイルそのものは、単純な内容になっている。シャープ記号(“#”)は、コメントの開始を意味する。また、行末にバックスラッシュ(“\”)を付けると、その行の記述が次の行にも続いていると見なされる。それ以外の行は、コンテキストエリア(auth、account、session、passwordのいずれか)、制御フラグ(requisite、required、sufficient、optionalのいずれか)、実行されるモジュールのパス(場合によってはパラメータを伴う)の3つのフィールドで構成される (実際には、2番目のフィールドがもっと複雑になる可能性もあるが、その詳細についてはこちらを参照のこと。また、“auth include common-account”のように“include”を使って別のテキストファイルからルールをインクルードすることもできる)。
デフォルト値の設定については、“other”という名の特別なサービスが存在し、特定の設定ファイルを持たないアプリケーションには、そのルールが自動的に適用される。たとえば、すべての要求を拒否し(pam_deny.soモジュールの担当)、管理者に警告を送信する(pam_warn.soモジュール)という最も安全な設定にするには、次のように記述する。
# # default; denying everything is the safest way # auth required pam_deny.so auth required pam_warn.so account required pam_deny.so password required pam_deny.so password required pam_warn.so session required pam_deny.so
この例でpam_deny.so
の代わりにpam_unix.so
を使えば、標準の認証手法(ユーザ名とパスワード)が適用される (セキュリティを気にしないなら、代わりにpam_permit.so
を使うとすべての要求が許可されるが、自己責任で利用すること)。セキュリティ上の問題から、「/etc/pam.d」ディレクトリに使用しないアプリケーションの設定ファイルがあっても、名前を変えて残しておく。そうすれば、“other”の設定が適用されることになり、あとでそのアプリケーションが必要になった場合にも、該当する設定ファイルを元の名前に戻すだけで済む。
利用可能なモジュール
モジュールの正式な一覧は存在しないが、以下では、利用される可能性の高いモジュールについて説明する。通常、PAMモジュールは「/lib/security」(64ビット版の場合は「/lib64/security」)に用意されているが、ディストリビューションによっては「/usr/lib/security」になっていることもある。詳細については、「man <PAMモジュール名>
」を実行して確認してほしい。
-
pam_unix
およびpam_unix2
:「/etc/passwd」と「/etc/shadow」の各ファイルを利用した伝統的なUNIX形式の認証機能を提供する。Berkeley DBに対する認証には、pam_userdb
が使える。 -
pam_time
:「/etc/security/time.conf」ファイルに記述された曜日および現在時刻に基づき、サービスへのアクセスを制限できる。 -
pam_access
:「/etc/security/access.conf」ファイルに記述されたルールに基づき、アクセスを許可または拒否する。ユーザがログインを試みるたびに、ルールのスキャンが順次行われ、最初にマッチしたルールに基づいて承認または拒絶が行われる。同じようなことはpam_succeed_if
でも可能だが、こちらは特定のグループへの所属など、特定の望ましいアカウント特性のチェックに使われる。 -
pam_listfile
:ファイルの内容に基づいてサービスを許可または拒否する、また別の手段。たとえば、承認済みユーザのリストを作成して(「/etc/ssh_users」とする)sshd
アクセスを制限するには、「/etc/pam.d/sshd」ファイルに「auth required pam_listfile.so item=user sense=allow file=/etc/ssh_users onerr=fail
」と記述すればよい。 -
pam_deny
およびpam_permit
:いずれもアクセスに関係したモジュールで、前者は常にアクセスを拒否し、後者はだれに対してもアクセスを許可する(使用には注意が必要)。より徹底しているのはpam_nologin
で、これは「/etc/nologin」ファイルが存在すれば、すべてのログインをブロックする。 -
pam_echo
およびpam_motd
:ユーザに対してメッセージを表示できる。前者は任意のファイルの表示に対応し、後者は「MOTD(Message Of The Day)」ファイルを表示する。同様に、pam_lastlog
はそのユーザによる前回のログインの日時を表示し、pam_mail
は新着メールの有無を通知する。 -
pam_limits
:システムリソースに関する制限を「/etc/security/limits.conf」ファイルによって指定できる。 -
pam_rootok
:それ以上のチェックを行わずに、rootユーザのアクセスを許可する。通常は「/etc/pam.d/su」で使われるため、rootはパスワードなしでほかの任意のユーザとして振る舞うことができる。そのためには「auth sufficient pam_rootok.so
」という記述を含める必要がある。suの利用を制限付きで許可するには、“wheel”グループのメンバーだけにrootアクセス権を与えるpam_wheel
を利用する。このチェックを実施するには「auth required pam_wheel.so
」を含める必要がある。 -
pam_cracklib
およびpam_pwcheck
:パスワードの安全性をチェックすることができる(次ページを参照)。 -
pam_warn
:ログイン情報をシステムログに記録する。
自作のモジュールを利用することもできるが、通常はこれまでに説明したモジュールまたはこちらのリストにあるものだけで間に合うはずだ。
安全なパスワード
PAMのpam_access
を使ってリモート接続をセキュア化する方法(翻訳記事)については、すでにほかの記事で説明した(pam_listfile
を使うという方法も考えられる)。ここでは、別のサンプルとして、ユーザに適切なパスワードを設定させる方法を紹介する。
パスワードの設定をユーザ任せにしてしまうと、パスワードそのものが設定されないことも多い。一方、システム管理者のなかには、ユーザにパスワードの変更を日常的に行うことを奨励している人もいる。PAMを使えば、こうした極端な例に走ることなく、それなりに適切なパスワードの設定が可能になる。そのためには、「/etc/pam.d/passwd」の“password”スタックを編集する必要がある。そうすれば、pam_cracklib
やpam_pwcheck
を使って、ユーザによるパスワード変更をコントロールできるようになる。機能はどちらも同じような内容で、次のようになっている。
- 指定されたminlenパラメータに基づき、短すぎるパスワードを拒絶する。
- 以前使われていたパスワード、またはそれに酷似しているものを禁止する。
- 以前のパスワードの大文字と小文字の割り当てを変えただけのものを禁止する(前に“liNUx”が使われていた場合、“LiNuX”は無効)。
- 以前のパスワードの文字列をローテーションまたは反転させたものを拒絶する(前に“linuxcom”が使われていた場合、“comlinux”は無効)。
- 新しいパスワードに英字の大文字、英文字以外の記号、または数字を含めることをユーザに要求する。
また、cracklib
パラメータを指定することで、cracklibライブラリを利用して辞書にある単語を拒絶することもできる。
# # The user is given three opportunities to enter a strong password. # The password needs be at least 6 characters long, with at least # two digits, one uppercase letter, and one non-alphabetic character, # and any number of lowercase letters. # password required pam_cracklib.so retry=3 minlen=6 dcredit=-2 ucredit=-1 ocredit=-1 lcredit=0 # # Using use_authtok in the pam_unix module ensures it doesn't prompt # for a password on its own, but uses the one provided by pam_cracklib # instead. The pam_cracklib module doesn't store passwords (only # checks them) so we need the standard pam_unix module in order to # accomplish that. # password required pam_unix.so use_authtok
オプションの詳細については、pam_cracklibのドキュメントを参照のこと。
PAMの利用は、GNU/Linuxのセキュリティ管理の基本であり、しかも非常に柔軟性が高い。その設定は、単純明快とはいえないが(しかもGUIが存在しない)、それほど難しくもない。PAMをうまく使えば、セキュリティを大幅に強化できるはずだ。
Federico Kerekiはウルグアイ在住のシステムエンジニア。20年以上にわたり、システムの開発、コンサルティング活動、大学での教育指導を続けている。