LFCS — Linux Foundation認定システム管理者
今の値と永続値は別の場所にある — SELinux・firewalld・sudoers・ACL・sshd
一言でいうと
RHEL系の管理ツールは、ほぼすべてが「今」と「永続」を別々に持っています。setseboolと-P、chconとsemanage fcontext、firewalldのruntimeとpermanent。そして、実効値はファイルではなく、ツールが教えてくれます。getsebool、firewall-cmd --list-all、sudo -l -U、getfacl、sshd -T。このモジュールのラボは、AlmaLinux 9のVMで、その両方を採点します。
なぜ必要なのか
LFCSのOperationsドメインは「SELinuxでアクセスを管理せよ」を明示し、Networkingドメインは、パケットフィルタリングとOpenSSHの構成を要求します。PodにはSELinuxもfirewalldもないので、これらの項目は、模擬試験でかすめた程度でした。前のRHCEのラボは、同じことをAnsibleで行いましたが、試験会場で手元にあるのは、semanageとfirewall-cmdです。
このVMはEnforcingです。そのため、ポートコンテキストを書き漏らすと、httpdが8081をbindできず、本当に起動しませんし、firewalldでpermanentを書き漏らすと、--reloadした瞬間にルールが消えます。採点エージェントが8899/tcpで入ってくるので、そのポートを消したり、デフォルトのゾーンを変えたりすると、採点が届きません。RHCEのラボで実測した落とし穴そのものです。
どう動くのか
SELinuxは、DACの上の一層です。RHEL 9 Using SELinuxが説明するとおり、プロセスとファイルに付いたコンテキスト(タイプ)が、ポリシーの許可ルールと合って初めて、アクセスが通ります。rootでも例外ではありません。ブーリアンは、ポリシーを作り直さずにオン・オフするスイッチで、setsebool(8)の-Pがないと、今は変わっても、再起動すると戻ります。semanage boolean -l -Cが、デフォルトから変更したものだけを表示し、(on , on)は(現在、永続)です。
ファイルコンテキストは、2か所にあります。ファイルのxattr(今の値)と、ポリシーのルール一覧(本来そうあるべき値)です。chconは前者だけを変更し、semanage-fcontext(8)は後者を変更します。後者を変更しないと、restorecon1回で元に戻ります。そのため、順序は、ルールの追加 → restorecon -Rです。ポートにもタイプがあります。semanage-port(8)で8081をhttp_port_tに入れないと、httpd_tはそのポートを開けず、拒否はausearch -m avcに残ります。
firewalldは、ゾーンと2つの状態です。firewall-cmdで、--permanentを付けると設定ファイルにだけ、付けないと今動いているルールにだけ適用されます。--reloadは、permanentをruntimeとして読み直すので、runtimeにだけ入れたものは、そのとき消えます。firewalld.zone(5)のゾーンは、送信元やインターフェースごとに異なる許可リストを持つ単位で、新しいゾーンはpermanentでしか作れないので、reloadしたあとで初めてruntimeに現れます。サービス・ポートだけでは書けない条件(送信元 + ポート + 動作)は、リッチルール1行で書きます。
sudoersは、断片で、検査から。sudoers(5)の%ops ALL=(ALL) NOPASSWD: /usr/bin/systemctlは、「opsグループが、どこからでも、誰としてでも、パスワードなしでsystemctlだけ」です。/etc/sudoers.d/に置けば、パッケージの更新で上書きされず、断片1つが間違っていても、その断片だけが弾かれます。文法が間違ったまま放置すると、sudo全体が拒否するので、visudo -cfで先に検査します。結果は、sudo -l -U deployが教えてくれます。
ログイン環境とリソース制限は、ログインの瞬間にかかります。/etc/profile.d/*.shは、ログインシェルが/etc/profileを経由して読み込む断片で、exportがないと、そのシェルの中でしか見えず、シェルが起動したプログラムには渡りません。limits.conf(5)の4つのフィールド(対象・soft/hard・項目・値)は、pam_limitsがセッションを開くときに適用されるので、すでに開いているシェルでulimitを見ても、変わりません。グループは@opsで書きます。
ACLは、9ビットの外にある権限です。所有者・グループ・その他では、「このユーザー1人だけを追加」を表現できません。setfacl(1)の-m u:deploy:rwxがそれで、-dのデフォルトACLは、ディレクトリの中に今後できるものが引き継ぎます。ACLが付くと、ls -lのグループの位置は、実際のグループ権限ではなくmaskを表示します。750にACLを与えると770のように見えるのが、正常です。maskが実効権限を削るので、getfaclの#effectiveを見ます。
sshdは、先に読んだ値を使います。sshd_config(5)によると、同じキーワードが複数回現れると、最初の値が勝ちます。RHEL 9のsshd_configは、最初の行がInclude /etc/ssh/sshd_config.d/*.confなので、ドロップインが本体に勝ちます。sshd -tが文法を、sshd -Tが、すべてのIncludeとMatchを解決した実効値を教えてくれます。
dnfはトランザクションです。dnfコマンドリファレンスのhistoryがトランザクション単位で履歴を残し、undoで元に戻します。アップグレードから外す方法は2つあります。versionlockプラグインは、今のバージョンに固定し、dnf.confのexclude=は、候補から最初から外します。Ubuntuのapt-mark holdと同じ位置づけです。
現場での姿
「httpdが起動しない、設定は合っている」のRHEL版は、10のうち9がSELinuxです。journalctl -u httpdにPermission deniedが見えたら、ausearch -m avc -ts recentを見ます。ポートならsemanage port、ファイルならsemanage fcontext + restoreconが答えで、setenforce 0は答えではありません。
「ファイアウォールを開けたのに、再起動したら閉じていた」は、--permanentを書き漏らしたもので、「開けたのに、今は通らない」は、--permanentだけを指定して--reloadをしていないものです。同じツールの2つの顔なので、症状が正反対に出ます。
「ACLを与えたのに、書き込めない」は、maskを見ます。chmod g-wのようなグループ権限の変更が、maskも一緒に削るので、user:deploy:rwxの実効値がr-xに落ちます。getfaclが#effective:r-xで教えてくれます。
次のラボですること
sestatusの保存 + setsebool -P → /srv/webのfcontextルール + restorecon + 8081をhttp_port_tに + httpdの応答 → publicゾーンにhttp・8081をruntimeとpermanentの両方に(8899は維持) → ゾーンlab + 送信元 + リッチルール → ops/deploy + sudoers.d/ops(0440、visudo -cf) → profile.dのexport + limits.d → /srv/web/uploadのACLとデフォルトACL → sshdのドロップイン + sshd -T → treeのインストール・ロック・dnf history。採点ツールは、getsebool、semanage … -C、firewall-cmd --permanent、su - deploy、sshd -Tで実効値を見ます。ファイルに書いたものと、ツールが言うものが同じときだけ、合格します。