RHEL8に限らずLinux一般で使えると思うが、RHEL8で出来るかを試したのでそのメモ。
Linuxにpam_scriptモジュールを導入して、OSユーザーのパスワード変更をHookしてみる。
パスワード変更がHook出来ると、独自のパスワードルールを作りこんだり、変更したパスワードを他システムと連携してパスワード管理を一元化できる。パスワード管理の一元化は、オンプレなら普通はLDAPでやると思うが、まあ、少し活用しそうな用途があったため。
pam_scriptを導入する
RHELのバージョンは8.3。VMWare Workstationにminimalでインストールしたものを使用。RHELの導入手順は割愛。
EPELの以下のURLからpam_scriptを入手する。依存関係があまり複雑じゃないのでrpm単体をダウンロードして導入も苦ではない。
rpmファイルをRHELに転送し、rpmコマンドでインストール。
# rpm -i pam_script-1.1.9-7.el8.x86_64.rpm
PAMを設定する
pam_scriptの利用方法はGitHubの以下を参照。
https://github.com/jeroennijhof/pam_script
passwdコマンドのパスワード変更にpam_scriptが噛むよう、pamの設定ファイルを修正する。
# %PAM-1.0
# This tool only uses the password stack.
(↓↓↓ここに行を追加)
password required pam_script.so onerr=fail dir=/root/pam_script
(↑↑↑ここに行を追加)
password substack system-auth
-password optional pam_gnome_keyring.so use_authtok
password substack postlogin
フック用のスクリプトを作る
まあ、用途の良し悪しは置いておいて、パスワード変更時に渡されたパスワードをファイルに記録するスクリプトで動作検証。
スクリプトのファイル名はpam_scriptで決められており、pam_script_passwd。
# ! /bin/bash
date >> /root/pam_script/passwd-hook.log
env >> /root/pam_script/passwd-hook.log
ファイルの実行権を付ける。
# chmod a+x /root/pam_script/pam_script_passwd
まあ、selinuxが有効な場合は動作しないので、Permissiveに。
# setenforce 0
動作確認
テスト用のユーザーを作る。
# adduser test
テスト用ユーザーのパスワードを変更する。
# passwd test
パスワードを変更すると/root/pam_script/passwd-hook.logに変更したパスワードが記録される。envコマンドの出力結果をすべて出力しているが、必要な部分を抜粋すると以下のような感じ。
PAM_AUTHOKに変更したパスワードが、PAM_USERに変更したユーザー名が値として設定されている。
Wed Feb 16 15:08:07 JST 2022
...
PAM_TYPE=password
PAM_AUTHTOK=PasswordForTest
...
USER=root
PAM_USER=test
...
ついでに
テスト用のユーザーtestに、設定したパスワード(PasswordForTest)でログインできるようになっているが、testユーザーは自分自身のパスワー変更時にエラーが出力されるようになる。
[test@r8 ~]$ passwd
Changing password for user test.
Current password:
New password:
New password (again):
/bin/bash: /root/pam_script/pam_script_passwd: Permission denied
Retype new password:
passwd: Authentication token manipulation error
[test@r8 ~]$
これは、testユーザーにpam_script_passwordのファイルアクセス権を追加するとか、今回の例でいえばpasswd-hook.logファイルにtestユーザーからの書き込み権を設定して、とかを調整すればパスワード変更できるようになるのだが、ちょっと今回はそこまで踏み込まない。
あとはまあ、パスワード変更のhookにpam_scriptを使うのは若干悪い点があり、今回は例としてパスワードをプレーンテキストでログファイルに記録しているというのはまあ置いておいて、pam_scriptではスクリプトおよびスクリプト内でコマンド実行する際にメモリに記録されたパスワード文字列をクリアする手段がない。OSのメモリダンプを取られたり、Meltdownのようなサイドチャネル攻撃に対して脆弱である。通常は心配しすぎの領域だと思うが、その場合はcでpamモジュールをメモリのクリアとかちゃんと意識して書くしか。pam_script自体の実装がそれなりに参考になると思うが。