PAM による認証は、クライアントを手動で実行すると成功し、systemd が同じプロファイルを起動すると AUTH_FAILED で失敗することがあります。この二つの実行の間でパスワードは変わっていません。変わるのは、PAM に問い合わせるプロセスを取り巻く制約の集合です。PAM はヘルパーを介して応答し、そのヘルパーが自分の資格情報を変更できる能力こそ、堅牢化された unit が削り取るものです。ケイパビリティ一覧に触れる前に、そのヘルパーと必要な境界を見つけてください。

unix_chkpwd は PAM の問いに答えるバイナリです

ローカルパスワード認証では、pam_unix がハッシュファイル自体を読むことはほとんどありません。それは unix_chkpwd を実行します。ディストリビューションはこれを setuid root または setgid shadow として導入し、/etc/shadow を読む必要のないプロセスの代わりに一つのパスワードを検証できるようにします。その同一性を得る能力を外すと、ヘルパーは検証を完了できず、モジュールは単なる認証失敗を返します。

すると失敗は、クライアントが見られるすべてのログで資格情報の問題のように見えます。それが罠です。クライアントは PAM が伝えた内容を報告し、PAM はスタックが拒否したとだけ報告します。ヘルパーを root で手動実行しても何も証明になりません。サービスが決して使わない特権経路を試すだけだからです。systemd が実際に読み込んだ unit を読み、続いて行われた試行についてシステムログを読んでください。この二つの視点が、サンドボックスの問題と誤ったパスワードの問題を切り分けます。

パスワードのログを読む前に unit を読む

パッケージされた unit には、自分が書いていない drop-in が含まれていることがあり、実効設定は統合された結果です。systemd が見ているとおりに unit を表示し、ヘルパーが自分を昇格できるかを決めるサンドボックス設定も一緒に確認してください。この段階では読み取り専用の調査で十分です。

systemctl cat [email protected]
systemctl show [email protected] -p User -p Group -p CapabilityBoundingSet -p AmbientCapabilities -p NoNewPrivileges
journalctl -u [email protected] -b

最初のコマンドは unit とその drop-in がどこから来るかを示します。何か月も前に追加された上書きが、なぜ存在するかの記憶より長く生き残るので、これは重要です。二つ目は、次の二つの節が依存するサンドボックスの値を表示します。

目にした内容を、同じディストリビューションと同じバージョンの動作中のホストと比較してください。User、CapabilityBoundingSet、NoNewPrivileges の違いは具体的な手がかりです。文章のコメントの違いは手がかりになりません。何かを変える前に値を書き留めてください。動く標的との後日の比較は何も証明しないからです。サービスが特権のないアカウントと空の bounding セットで動いているなら、ヘルパーにはほとんど何も残っていません。

資格情報の変換、ファイルアクセス、ポリシーは三つの境界です

exec の間に何が起きるかから始めます。setuid バイナリやファイルケイパビリティを持つファイルは資格情報の変換を引き起こすため、結果の同一性は呼び出し元の継続ではありません。bounding セットはそうしたファイルが獲得できるものを制限し、NoNewPrivileges は setuid、setgid、ファイルケイパビリティの獲得を完全に遮断します。この三つのどれか一つでもヘルパーを止められますが、他のサービス機能はすべて無傷のままです。

次に、広い裁量バイパスと狭い読み取りアクセスを分けます。CAP_DAC_OVERRIDE はほぼどこでも裁量チェックを飛ばしますが、CAP_DAC_READ_SEARCH は独自の追加権限で読み取りとディレクトリ走査をカバーします。両者は影響範囲の異なる別の道具であり、どちらも PAM に shadow ファイルを読ませるという言い方の綴りではありません。

最後に、必須ポリシーがその行為をそもそも許可しているかを問います。Linux ケイパビリティは SELinux を上書きせず、一つ持っていることが type enforcement ルールについて何かを証明することもありません。ファイルアクセスの拒否とケイパビリティの拒否は別の証拠として扱ってください。示す修正も、しばしば担当者も異なるからです。denied という一語ではなく、レコードの各フィールドを読んでください。どの実行ファイルが行為をしたか、どのドメインで動いたか、どの種類の対象に触れたか、どのオブジェクトクラスが関与したか、ポリシーがどの許可を拒否したか。それぞれが違う形で答えを絞り込みます。

監査ログから拒否を引き出す

強制モードのホストでは、拒否を記録するのは監査トレイルだけです。最近のイベントを問い合わせ、失敗したログインのタイムスタンプに対して読みます。調査を始めた時刻ではありません。

ausearch -m AVC,USER_AVC -ts recent

空の結果は無実の証拠ではありません。監査が収集していないか、あなたの時間枠が試行を取りこぼしたかのどちらかであり、ポリシーを除外する前に両方の可能性を除外する必要があります。

Red Hat の SELinux トラブルシューティングガイド はラベルと設定の確認を allow ルールの生成より前に置いています。これはこの問題でも正しい順序です。ラベルを誤ったヘルパーバイナリとポリシーの穴は似た拒否を生みますが、必要な修理は異なります。ラベルの誤りに対して allow ルールを生成すると、欠陥を隠し、次のパッケージ更新で再発させます。ポリシーを書く前に、導入済みヘルパーのラベルを確認してください。

受け入れられるログインと拒否されるログインで変更を証明する

実証した境界だけを変え、そのうえで両方の結果を試します。認証されるべきアカウントは成功し、誤ったパスワードのアカウントは依然として失敗する必要があります。すべての試行を成功させる変更は、認証を修復したのではなく取り除いたのです。

実際の接続を試み、その直後にジャーナルを読みます。修正を証明する行は、その試行の pam_unix(openvpn:auth) エントリです。認証成功と表示され、同じ秒に AVC レコードが一つもあってはなりません。

journalctl -u [email protected] -n 30 --no-pager
ss -tnp | grep openvpn

動作するトンネルには再接続も必要です。サンドボックスの変更は、最初の接続より二回目の接続を壊すことが多いからです。再接続後に確立されたソケットを確認し、同じ unit がまだそれを提供していることを確かめてください。

関連記事