CentOS Stream 9でlibpwqualityを使ったパスワードポリシー設定:エンタープライズセキュリティの実践

CentOS tutorial - IT technology blog
CentOS tutorial - IT technology blog

2021年にCentOS 8がEOLを迎えたとき、5台のサーバーをRocky Linuxにわずか1週間で移行しなければならなかった。ひどいストレスだったが、セキュリティ設定全体を見直す貴重な機会でもあった — そこで気づいたのは、ほとんどのサーバーのパスワードポリシーがほぼデフォルトのままだということ。複雑さの強制なし、再利用の制限なし、何もない状態。それがlibpwqualityを本格的に調べ始めたきっかけだ。

この記事は、CentOS Stream 9での実際の導入経験をもとにしている — LDAPとローカルアカウントを組み合わせた約30ユーザーのproduction環境だ。教科書的な理論ではない。

Linuxでパスワードポリシーを強制する3つのアプローチ

決断する前に3つのアプローチを検討した — それぞれ検討する理由があった:

1. pam_cracklib(レガシー)

古いPAMモジュールで、多くのディストリビューションにまだ存在する。かつてはRHEL 6/7の標準だった。今でも動作するが、RHEL 8以降はdeprecatedになっている。CentOS Stream 9では、このパッケージはデフォルトのリポジトリに存在しない。

2. libpwquality + pam_pwquality(現在の推奨)

RHEL 7以降のpam_cracklibの公式後継。同じ開発者(Tomáš Mráz)によるもので、後方互換性のあるAPIを持ちながら、より多くのオプション、pwscore CLIとの優れた統合、そして積極的なメンテナンスが特徴だ。CentOS Stream 9ではこれがデフォルトになっている。

3. カスタムPAMスクリプト + pam_exec

独自のシェルスクリプトを書き、pam_exec経由で呼び出す方法。最も柔軟だが、メンテナンスの悪夢だ。あるクライアントでこういったセットアップを見たことがある:コメントなしの200行近いbashスクリプトで、誰も触ろうとしない。これは絶対に避けたい。

実際の比較:pam_cracklib vs pam_pwquality

比較項目 pam_cracklib pam_pwquality
RHEL 9でのステータス リポジトリに存在しない プリインストール済み、デフォルト
専用設定ファイル なし(PAM引数のみ) あり(/etc/security/pwquality.conf
pwscore CLIツール なし あり
辞書チェック cracklib dict cracklib dict(改善版)
リトライ試行 あり あり(設定可能)

結論は明快:pam_pwquality一択だ。CentOS Stream 9ではpam_cracklibはデフォルトリポジトリにそもそも存在しない — 比較の余地すらない。

現在の環境を確認する

インストール済みと思い込まないこと。何かする前に必ず確認しよう:

# パッケージを確認
rpm -q libpwquality
# Output: libpwquality-1.4.4-8.el9.x86_64

# 現在のPAM設定を確認
grep -n pwquality /etc/pam.d/system-auth
grep -n pwquality /etc/pam.d/password-auth

CentOS Stream 9を新規インストールした場合、次のような出力が表示される:

password    requisite     pam_pwquality.so try_first_pass local_users_only

まだインストールされていない場合やインストールし直す必要がある場合:

dnf install libpwquality -y

/etc/security/pwquality.conf の設定

これが中心的な設定ファイルだ。編集前は必ずバックアップを取る — 昨年、PAM設定のミスでproductionサーバーがロックアウトされた経験から身に付いた習慣だ:

cp /etc/security/pwquality.conf /etc/security/pwquality.conf.bak
vim /etc/security/pwquality.conf

ユーザーが不満を持つほど厳しくない、適度なenterprise環境向けの設定:

# /etc/security/pwquality.conf
# 最小パスワード長
minlen = 12

# 文字種ごとの最小文字数(負の値 = 必須)
minclass = 3        # upper、lower、digit、otherの4種類のうち少なくとも3種類が必要
dcredit = -1        # 数字を最低1文字必須
ucredit = -1        # 大文字を最低1文字必須
lcredit = -1        # 小文字を最低1文字必須
ocredit = 0         # 特殊文字:任意(ユーザーから苦情が多い)

# 辞書とパターンのチェック
dictcheck = 1       # cracklibの辞書でチェック
usercheck = 1       # パスワードにユーザー名を使用禁止
enforcing = 1       # 品質基準を満たさない場合は失敗(警告だけでなく)

# 連続する同一文字の制限
maxrepeat = 3       # 3回以上の連続は禁止:「aaaa」は拒否される
maxsequence = 4     # 連続した文字列は禁止:「1234」、「abcd」

# 旧パスワードと異なる文字数
difok = 5

# 入力ミス時のリトライ回数
retry = 3

# 追加の禁止ワード(状況に応じて追加)
# badwords = company password admin root

creditロジックの説明

dcreditucreditなどは最も混乱しやすい部分だ。ルールはシンプル:

  • 負の値(例:-1):その種類の文字を最低1文字必須にする
  • 正の値(例:1):その種類の文字1文字ごとにminlenにボーナスポイントを加算する(cracklibからの旧来の動作)
  • 0:このルールを適用しない

負の値を使うことをお勧めする — より明確で監査もずっとしやすい。

ポリシーを適用するためのPAM設定

重要な注意authselectを使用するCentOS Stream 9では、/etc/pam.d/system-auth/etc/pam.d/password-authを直接編集してはならない。そのファイルは上書きされる。

# 現在のプロファイルを確認
authselect current

# 通常の出力:
# Profile ID: sssd
# Enabled features: with-faillock

pam_pwqualityにオプションを追加する必要がある場合は、authselectカスタムプロファイルを使用する:

# sssdをベースにカスタムプロファイルを作成
authselect create-profile custom-security --base-on sssd

# 新しいプロファイルのpassword-authファイルを編集
vim /etc/authselect/custom/custom-security/password-auth

pam_pwquality.soの行を見つけて調整する。rootにもポリシーを適用したい場合はenforce_for_rootを追加する:

password    requisite     pam_pwquality.so try_first_pass local_users_only retry=3 enforce_for_root authtok_type=

その後、プロファイルを適用する:

authselect select custom/custom-security with-faillock --force

chageを使ったパスワードエイジングの設定

しかし、libpwqualityだけでは不十分だ。パスワード変更時の品質チェックしかできず、定期的な変更を強制しない。chage/etc/login.defsも必要になる:

# /etc/login.defsで新規ユーザーのデフォルト設定を確認
grep -E 'PASS_MAX_DAYS|PASS_MIN_DAYS|PASS_WARN_AGE' /etc/login.defs
# /etc/login.defsを編集
PASS_MAX_DAYS   90    # 90日後にパスワード変更を強制
PASS_MIN_DAYS   1     # 再変更まで最低1日待つ
PASS_WARN_AGE   14    # 有効期限14日前に警告
# 既存ユーザーに適用(例:ユーザーhieu)
chage -M 90 -m 1 -W 14 hieu

# ユーザーのエイジング設定をすべて確認
chage -l hieu

pwscoreを使った実際のテスト

libpwqualitypam_cracklibより優れている最大の点:pwscoreツールがあることだ。このCLIはユーザーを作成したり実際のパスワードを変更したりすることなく、即座にパスワードをテストできる — ポリシーのデバッグや自動化スクリプトの検証に非常に便利だ:

# パスワードの強度をテスト(stdinで入力)
echo "password123" | pwscore
# Output: 0 (非常に弱い)

echo "P@ssw0rd" | pwscore
# Output: 50 (普通)

echo "Xk9#mNqL2vBp" | pwscore
# Output: 100 (強い)

スコアは0〜100。ポリシーを満たさないパスワードは具体的な理由とともにエラーを表示する:

echo "abc" | pwscore
# The password is shorter than 12 characters.
# Password quality check failed:
#  The password is shorter than 12 characters.

pwscoreをオンボーディングスクリプトに組み込んで、アカウント作成前にパスワードを検証している。直接試して拒否されるよりもずっと効率的だ。

設定全体の検証

最もシンプルな実際のテスト:パスワードを変更してシステムの反応を確認する。テストユーザーを使用し、rootは使わないこと:

# 一般ユーザーのパスワード変更でテスト(テストにrootは使用しないこと)
passwd testuser

# 弱いパスワードを試す:「simple」
# Expected: BAD PASSWORD: The password is shorter than 12 characters.

# クラス不足のパスワードを試す:「alllowercasehere」
# Expected: BAD PASSWORD: The password contains less than 1 uppercase letters

# 有効なパスワードを試す:「Secure#2024Linux」
# Expected: passwd: all authentication tokens updated successfully.
# パスワード変更時のログを確認
tail -f /var/log/secure | grep passwd

Production環境での注意点

rootとenforce_for_root:デフォルトでは、rootは他のユーザーに弱いパスワードを設定できるが、警告が表示されるだけでブロックはされない。rootにも強制したい場合は、PAM設定のpam_pwquality.so行にenforce_for_rootを追加する(上記参照)。注意:rootは古いパスワードを求められないため、新旧パスワードの比較チェックは実行されない — これは正常な動作であり、バグではない。

LDAP/ADユーザーlibpwqualityはPAM経由でのローカルパスワード変更時のみ適用される。ユーザーがLDAPサーバーで直接パスワードを変更した場合、このポリシーは効果がない。LDAPサーバー側で別途設定が必要だ

自動化スクリプト:平文パスワードでchpasswdを使用する場合、PAMは通常通り呼び出される — pam_pwqualityがチェックする。例外:chpasswd -eは事前にハッシュ化されたパスワードを受け取るため、品質チェックが完全にバイパスされる。後でセキュリティ監査をしたとき驚かないように知っておくこと。強制を確実にしたい場合はpasswdを使うこと。

# ランダムな強力なパスワードで複数のユーザーを作成
for user in user1 user2 user3; do
    useradd "$user"
    # 16文字のランダムなパスワードを生成
    pass=$(openssl rand -base64 16 | tr -d '=+/' | head -c 16)
    echo "${user}:${pass}" | chpasswd
    # 初回ログイン時にパスワード変更を強制
    chage -d 0 "$user"
    echo "User: $user | Pass: $pass"
done

このconfigをproductionで6ヶ月間運用した結果、最初の1ヶ月は「パスワードを忘れた」というチケットが約15%増加したが(ユーザーからパスワードが覚えにくいという苦情)、その後は安定した。ブルートフォースやcredential stuffingのリスクを軽減できることを考えれば、受け入れられるトレードオフだ。

Share: