Linuxエンジニア養成講座 第28回|全36回・フェーズ4「サーバー構築と運用」の第1回目(1/9回目)です。
前回まで: フェーズ3「ネットワークとインフラ基盤」(第16回〜第27回)で、TCP/IPの基礎からSSH応用までを学びました。
今回学ぶこと: SELinux の設計思想を理解し、コンテキストの確認・修正・監査ログの読み方を実践します。
前回の予告で「SELinux の仕組みと基本操作(getenforce、semanage、restorecon)を学びます。Enforcing のまま運用することの意味と、SELinux が原因でサービスが動かない場合の切り分け方を身につけます」とお伝えしました。今回からフェーズ4「サーバー構築と運用」が始まります。フェーズ4の最初のテーマとして、サーバー構築の土台となる SELinux を取り上げます。
この記事を読み終えると、以下のことができるようになります。
- SELinux の設計思想(DAC と MAC の違い)を説明できる
- getenforce / sestatus で SELinux の動作モードとポリシーを確認できる
- ls -Z / ps -eZ / id -Z でファイル・プロセス・ユーザーのコンテキストを確認できる
- restorecon でファイルのコンテキストを正しい値に修正できる
- semanage でポートやブーリアンのルールを確認できる
- audit.log から SELinux の拒否ログ(AVC deny)を検索できる
なぜ SELinux が必要か
第11回で学んだパーミッション(rwx)を思い出してください。Linux の標準的なパーミッションは DAC(Discretionary Access Control: 任意アクセス制御)と呼ばれます。ファイルの所有者がアクセス権を自由に決められる仕組みです。
DAC には構造的な弱点があります。あるプロセスがセキュリティ上の脆弱性を突かれて侵害された場合、そのプロセスを実行しているユーザーの権限で何でもできてしまいます。たとえば Web サーバー(httpd)が root 権限で動いていれば、侵害された瞬間にサーバー全体が危険にさらされます。
SELinux(Security-Enhanced Linux)は、この問題に対する答えです。SELinux は MAC(Mandatory Access Control: 強制アクセス制御)を実装しています。MAC では、OS が「このプロセスはこのファイルにしかアクセスできない」というルールを強制します。ファイルの所有者やプロセスの実行ユーザーが何であっても、OS が定めたルールを超えることはできません。
具体的な例を挙げます。httpd プロセスは httpd_sys_content_t という type(後述)のファイルしか読めません。仮に httpd が侵害されても、/etc/shadow(パスワードハッシュ)や /var/log/audit/(監査ログ)にはアクセスできません。被害がそのプロセスの許可範囲内に限定されるのです。
これは「最小権限の原則」をOSレベルで実装したものです。第3回で「必要最小限の権限だけを与える」というセキュリティの基本を学びました。SELinux はその考え方をカーネルレベルで強制する仕組みです。

だからこそ、SELinux を disable(無効化)にしてはいけません。これはこの講座全体を通じた鉄則です。「SELinux のせいで動かない」と感じたら、disable にするのではなく「なぜ拒否されたのか」を調べて正しく設定することが、インフラエンジニアの仕事です。
SELinux の基本概念
コンテキスト(ラベル)
SELinux では、ファイル・プロセス・ユーザーのすべてに「コンテキスト」と呼ばれるラベルが付きます。コンテキストは次の4つのフィールドで構成されます。
user:role:type:level
たとえば system_u:object_r:httpd_sys_content_t:s0 のような文字列です。4つのフィールドのうち、今の段階で覚えるべきは type(3番目のフィールド)だけです。type が SELinux のアクセス制御の中心です。残りの user、role、level は、まず type を理解してから必要に応じて学べば十分です。
targeted ポリシー
AlmaLinux 9 では targeted ポリシーが使われています。targeted とは「主要なネットワークサービス(httpd、sshd、named など)だけを SELinux で制限し、一般ユーザーのプロセスは制限しない」という方針です。一般ユーザーには unconfined_t(制限なし)という type が付きます。すべてを制限する strict ポリシーもありますが、サーバー用途では targeted が標準です。
3つのモード
SELinux には3つの動作モードがあります。
- Enforcing — ポリシーに違反するアクセスを拒否し、ログに記録する。本番環境での正しい状態
- Permissive — ポリシー違反をログに記録するが、アクセスは拒否しない。デバッグ用
- Disabled — SELinux を完全に無効化する。使わない
この講座では Enforcing を維持します。Permissive は「原因調査のために一時的に切り替える」場面でのみ使い、調査が終わったら必ず Enforcing に戻します。Disabled は選択肢に入れません。
getenforce / sestatus で確認する
現在のモードを確認します。alma-main で実行してください。
実行コマンド:
$ getenforce
実行結果:
Enforcing
getenforce は現在のモードを1行で返します。Enforcing と表示されれば正常です。
より詳細な情報を見るには sestatus を使います。
実行コマンド:
$ sestatus
実行結果:
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Memory protection checking: actual (secure)
Max kernel policy version: 33
注目すべきは3つです。Loaded policy name: targeted(targeted ポリシーを使用)、Current mode: enforcing(現在 Enforcing で動作中)、Mode from config file: enforcing(設定ファイルでも Enforcing が指定されている = 再起動しても Enforcing になる)。
ファイルとプロセスのコンテキストを確認する
コンテキストの概念を理解したら、実際に確認してみます。ファイル、プロセス、ユーザーのそれぞれにコンテキストが付いていることを自分の目で確かめてください。
ファイルのコンテキスト(ls -Z)
ls に -Z オプションを付けると、ファイルの SELinux コンテキストが表示されます。alma-main で実行してください。
実行コマンド:
$ ls -Z /var/log/ | head -7
実行結果:
system_u:object_r:var_log_t:s0 README
system_u:object_r:var_log_t:s0 anaconda
system_u:object_r:auditd_log_t:s0 audit
system_u:object_r:faillog_t:s0 btmp
system_u:object_r:faillog_t:s0 btmp-20260402
system_u:object_r:chronyd_var_log_t:s0 chrony
system_u:object_r:cron_log_t:s0 cron
3番目のフィールド(type)に注目してください。var_log_t、auditd_log_t、chronyd_var_log_t、cron_log_t など、ファイルの用途に応じた type が付いています。audit ディレクトリには auditd_log_t が付いているため、auditd 以外のプロセスからはアクセスが制限されます。
SSH 関連のファイルも確認してみます。
実行コマンド:
$ ls -Z /etc/ssh/ | head -5
実行結果:
system_u:object_r:etc_t:s0 moduli
system_u:object_r:etc_t:s0 ssh_config
system_u:object_r:etc_t:s0 ssh_config.d
system_u:object_r:sshd_key_t:s0 ssh_host_ecdsa_key
system_u:object_r:sshd_key_t:s0 ssh_host_ecdsa_key.pub
設定ファイルには etc_t、ホスト鍵には sshd_key_t が付いています。ホスト鍵は sshd が読み取る必要があるため、専用の type で管理されています。
プロセスのコンテキスト(ps -eZ)
ps に -eZ オプションを付けると、プロセスの SELinux コンテキストが表示されます。
実行コマンド:
$ ps -eZ | grep sshd
実行結果:
system_u:system_r:sshd_t:s0-s0:c0.c1023 807 ? 00:00:00 sshd
sshd プロセスの type は sshd_t です。SELinux は「sshd_t の type を持つプロセスは sshd_key_t の type を持つファイルを読める」というルールを定義しています。これがコンテキストによるアクセス制御の仕組みです。
ユーザーのコンテキスト(id -Z)
自分自身の SELinux コンテキストも確認できます。
実行コマンド:
$ id -Z
実行結果:
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
type が unconfined_t です。targeted ポリシーでは、SSH でログインした一般ユーザーは unconfined_t(制限なし)になります。SELinux が制限するのは httpd や sshd などのネットワークサービスであり、ログインユーザーの通常操作は制限されません。
policycoreutils-python-utils を導入する
SELinux のルールを確認・変更するための semanage コマンドは、Minimal Install には含まれていません。policycoreutils-python-utils パッケージを導入します。alma-main で実行してください。
実行コマンド:
$ sudo dnf install -y policycoreutils-python-utils
インストールが完了したら semanage コマンドが使えるようになります。man semanage でマニュアルを確認できるので、どのようなサブコマンドがあるか眺めてみてください。
restorecon でコンテキストを修正する
ここまでで「ファイルやプロセスに type が付いている」ことを確認しました。では、その type が間違っていたらどうなるでしょうか。httpd が読むべきファイルに httpd_sys_content_t ではなく別の type が付いていたら、httpd はそのファイルを読めません。サービスが正常に動かない原因になります。
cp と mv でコンテキストが変わる
ファイルのコンテキストが意図せず変わる、よくある場面を見てみます。
- cp(コピー) — コピー先の親ディレクトリのデフォルトコンテキストを継承する。元のコンテキストは保持されない
- mv(移動) — 元のコンテキストをそのまま保持する
この違いが問題を起こします。/tmp でファイルを作成し、/var/www/html/ に cp した場合を実際に見てみます。alma-main で実行してください。
実行コマンド:
$ touch /tmp/selinux-test.txt
作成したファイルのコンテキストを確認します。
実行コマンド:
$ ls -Z /tmp/selinux-test.txt
実行結果:
unconfined_u:object_r:user_tmp_t:s0 /tmp/selinux-test.txt
type は user_tmp_t です。/tmp に作ったファイルなので、一時ファイル用の type が付いています。
このファイルを /var/www/html/ にコピーします。このディレクトリは Apache(httpd)がインストールされると自動的に作成されますが、現時点ではまだ存在しないため、先に作成します。
実行コマンド:
$ sudo mkdir -p /var/www/html
実行コマンド:
$ sudo cp /tmp/selinux-test.txt /var/www/html/
コピー先のコンテキストを確認します。
実行コマンド:
$ ls -Z /var/www/html/selinux-test.txt
実行結果:
unconfined_u:object_r:var_t:s0 /var/www/html/selinux-test.txt
type が var_t になっています。/var/www/html/ のデフォルトコンテキストは httpd_sys_content_t ですが、cp で /var 配下にコピーされたため、途中のディレクトリのコンテキスト(var_t)を継承してしまいました。この状態では httpd はこのファイルを読めません。
restorecon で正しいコンテキストに戻す
コンテキストを修正するコマンドは2つあります。
- chcon — コンテキストを手動で指定して変更する。一時的な変更であり、
restoreconを実行すると元に戻る - restorecon — そのパスに対してポリシーで定義された正しいコンテキストに復元する。こちらが正解
chcon は「とりあえず動かしたい」ときに使うことがありますが、再起動やファイルシステムの再ラベリングで消えてしまいます。恒久的な修正には restorecon を使ってください。
先ほどの var_t になってしまったファイルを restorecon で修正します。
実行コマンド:
$ sudo restorecon -v /var/www/html/selinux-test.txt
実行結果:
Relabeled /var/www/html/selinux-test.txt from unconfined_u:object_r:var_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0
-v オプションを付けると、変更内容が表示されます。var_t から httpd_sys_content_t に修正されたことが分かります。
修正後のコンテキストを確認します。
実行コマンド:
$ ls -Z /var/www/html/selinux-test.txt
実行結果:
unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/selinux-test.txt
type が httpd_sys_content_t に修正されました。これで httpd がこのファイルを読めるようになります。第29回で Apache を構築する際、この知識が必要になります。
ディレクトリ配下を再帰的に修正したい場合は -R オプションを使います。sudo restorecon -Rv /var/www/html/ のように実行すると、ディレクトリ内の全ファイルを一括で修正できます。
semanage でルールを確認する
semanage は SELinux のポリシールールを確認・変更するコマンドです。まずは「確認」の使い方を見ていきます。
ポートのルール確認
SELinux は「どのサービスがどのポートを使えるか」もルールで管理しています。SSH が使えるポートを確認してみます。
実行コマンド:
$ sudo semanage port -l | grep ssh
実行結果:
ssh_port_t tcp 22
ssh_port_t に TCP 22 番が割り当てられています。もし SSH を別のポート番号で動かしたい場合は、semanage port -a でそのポートを ssh_port_t に追加する必要があります(firewalld のルール変更に加えて、SELinux のルール変更も必要ということです)。
HTTP 関連のポートも確認します。
実行コマンド:
$ sudo semanage port -l | grep http
実行結果:
http_cache_port_t tcp 8080, 8118, 8123, 10001-10010
http_cache_port_t udp 3130
http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000
pegasus_http_port_t tcp 5988
pegasus_https_port_t tcp 5989
http_port_t に TCP 80、443 などが含まれています。httpd がこれら以外のポートで待ち受けようとすると、SELinux に拒否されます。
ブーリアン(ON/OFF スイッチ)
SELinux にはブーリアン(Boolean)という ON/OFF のスイッチがあります。特定の機能を個別に許可・禁止できる仕組みです。getsebool で現在の値を確認できます。
実行コマンド:
$ getsebool -a | grep httpd | head -5
実行結果:
httpd_anon_write --> off
httpd_builtin_scripting --> on
httpd_can_check_spam --> off
httpd_can_connect_ftp --> off
httpd_can_connect_ldap --> off
たとえば httpd_can_connect_ftp が off になっています。httpd から FTP サーバーへの接続は禁止されているということです。必要に応じて setsebool -P httpd_can_connect_ftp on のように変更できます(-P は再起動後も永続化するオプション)。
semanage fcontext -a(ファイルコンテキストのルール追加)や semanage port -a(ポートルールの追加)といった書き込み操作は、第29回で Apache を構築するときに実践します。今回は「確認方法を知っている」ことが目標です。
audit.log の読み方
SELinux がアクセスを拒否すると、/var/log/audit/audit.log に記録されます。このファイルは root のみ読めます。
「SELinux のせいでサービスが動かない」と疑ったとき、最初に確認するのがこのログです。ausearch コマンドで AVC(Access Vector Cache)メッセージを検索します。
実行コマンド:
$ sudo ausearch -m avc --start recent
実行結果:
<no matches>
<no matches> は deny エントリがないことを意味します。SELinux が何も拒否していない = 正常に動作しているということです。
もし deny が記録されていた場合、出力にはどのプロセス(scontext)がどのファイル(tcontext)に対してどの操作(read、write、connectなど)を拒否されたかが記載されます。deny が出ても disable にしないでください。ログの内容を読み、正しいコンテキストを設定するか、ブーリアンを変更するか、ポートを追加するかで対処します。
--start recent は直近10分以内のログを表示するオプションです。時間範囲を指定したい場合は --start 04/04/2026 09:00:00 --end 04/04/2026 10:00:00 のように書くこともできます。詳しくは man ausearch を確認してください。
ヒヤリハット: SELinux を disable にして「解決した」と思った話
ヒヤリハット: 本番環境で SELinux を disable にした
ある現場で、Apache がコンテンツを配信できないトラブルが発生しました。原因は SELinux のコンテキスト不一致だったのですが、担当者は「SELinux のせいで動かない」と判断し、/etc/selinux/config を SELINUX=disabled に変更してサーバーを再起動しました。Apache は動くようになり、「解決した」と報告されました。
しかし数か月後のセキュリティ監査で SELinux が無効化されていることが発覚し、重大な指摘事項になりました。本来は restorecon 1発で直る問題でした。「動けば良い」ではなく「なぜ動かないのか」を調べる姿勢が、エンジニアとして問われた事例です。
ヒヤリハット: Permissive のまま本番リリース
開発環境でトラブルシューティングのために Permissive に切り替え、そのまま本番環境にリリースしてしまったケースもあります。Permissive はポリシー違反をログに記録するだけで、アクセスを拒否しません。つまり、SELinux が存在しないのと同じ状態です。
Permissive に切り替えた場合は getenforce で必ずモードを確認し、調査が終わったら sudo setenforce 1 で Enforcing に戻してください。設定ファイル(/etc/selinux/config)側も SELINUX=enforcing のままであることを確認するのが鉄則です。
やってみよう
今回学んだコマンドを使って、以下の課題に取り組んでください。alma-main で実行します。
課題1: ログファイルの type を比較する
ls -Z で /var/log/messages と /var/log/secure の type を確認してください。2つのファイルの type は同じですか、違いますか。違う場合はなぜ異なる type が付いているか考えてみてください。
ヒント: ls -Z /var/log/messages /var/log/secure で2つ同時に確認できます。
課題2: cp によるコンテキスト変化と restorecon による修正
以下の手順を順番に実行してください。
/tmpに適当な名前のテキストファイルを作成する(touch /tmp/mytest.txt)ls -Zでそのファイルの type を確認するsudo cpでそのファイルを/var/www/html/にコピーするls -Zでコピー先のファイルの type を確認する(httpd_sys_content_tではないはず)sudo restorecon -vでコンテキストを修正するls -Zで修正後の type を確認する(httpd_sys_content_tになっているはず)
演習が終わったら、作成したテストファイルを削除しておきます。
実行コマンド:
$ rm /tmp/mytest.txt
$ sudo rm /var/www/html/mytest.txt
$ sudo rm /var/www/html/selinux-test.txt
まとめと次回予告
今回は SELinux の設計思想と基本操作を学びました。ポイントは3つです。
- 設計思想 — SELinux は最小権限の原則を OS レベルで強制する仕組み(MAC)。プロセスが侵害されても被害を限定できる
- disable にしない — 動かないときは disable ではなく、
audit.logを読んで原因を特定し、コンテキストやポート、ブーリアンを正しく設定する - restorecon で修正 — ファイルをコピーしてコンテキストがおかしくなったら
restoreconで正しい値に戻す。chconは一時的な変更なので恒久対応には使わない
次回は第29回「Webサーバー構築(Apache/Nginx)」です。Apache のインストールから設定、自己署名証明書による HTTPS 体験までを行います。今回学んだ SELinux のコンテキスト設定(httpd_sys_content_t)や firewalld のポート許可(80/443)が必要になるので、今回の内容を復習しておいてください。
理解度チェック
今回の内容を振り返り、○×で答えてください。
Q1. SELinux の targeted ポリシーでは、SSH でログインした一般ユーザーのプロセスにも SELinux の制限がかかる。
Q2. SELinux のコンテキストは user:role:type:level の4フィールドで構成され、targeted ポリシーでは type フィールドが最も重要である。
Q3. ファイルを cp でコピーすると、コピー先のファイルは元のファイルの SELinux コンテキストをそのまま引き継ぐ。
Q4. chcon で変更したコンテキストは、restorecon を実行すると元に戻ってしまう。
Q5. SELinux がアクセスを拒否したログは /var/log/audit/audit.log に記録され、ausearch -m avc で検索できる。
Q6. SELinux が原因でサービスが動かない場合、/etc/selinux/config で SELINUX=disabled に変更するのが正しい対処法である。
以下、解答です。
Q1. × — targeted ポリシーでは、一般ユーザーのプロセスは unconfined_t(制限なし)になります。SELinux が制限するのは httpd や sshd などのネットワークサービスです。
Q2. ○ — コンテキストの4フィールドのうち、targeted ポリシーでアクセス制御の中心となるのは type です。「このプロセスの type はこのファイルの type にアクセスできる」というルールで制御されます。
Q3. × — cp はコピー先の親ディレクトリのデフォルトコンテキストを継承します。元のコンテキストを保持するのは mv(移動)です。この違いがコンテキスト不一致の原因になることがあります。
Q4. ○ — chcon による変更は一時的です。restorecon を実行すると、ポリシーで定義された正しいコンテキストに戻されます。恒久的な修正には restorecon を使ってください。
Q5. ○ — SELinux の拒否ログ(AVC deny)は audit.log に記録されます。ausearch -m avc で検索でき、どのプロセスがどのファイルへのどの操作を拒否されたかを確認できます。
Q6. × — disable は絶対に選択肢に入れません。audit.log を読んで原因を特定し、restorecon でコンテキストを修正する、semanage port でポートを追加する、setsebool でブーリアンを変更するなど、正しい方法で対処します。
シリーズ一覧
フェーズ1: エンジニアのいろは(第1回〜第3回)
フェーズ2: Linux基礎(第4回〜第15回)
- 第4回 Linuxとは何か+環境確認
- 第5回 SSH接続とターミナル操作
- 第6回 ファイルシステムとディレクトリ構造
- 第7回 基本コマンド(ファイル操作)
- 第8回 基本コマンド(テキスト処理・パイプとリダイレクト)
- 第9回 viエディタ
- 第10回 ユーザーとグループ管理
- 第11回 パーミッションと所有権
- 第12回 プロセス管理
- 第13回 systemd
- 第14回 シェルスクリプト入門
- 第15回 フェーズ2まとめ演習
フェーズ3: ネットワークとインフラ基盤(第16回〜第27回)
- 第16回 ネットワーク基礎
- 第17回 ネットワーク設定と疎通確認
- 第18回 企業ネットワークの仕組み
- 第19回 パッケージ管理
- 第20回 ファイアウォール(firewalld)
- 第21回 ボンディング/チーミング
- 第22回 VLAN
- 第23回 ログ管理
- 第24回 cron / systemd timer
- 第25回 ストレージ管理(LVM)
- 第26回 シェルスクリプト実践
- 第27回 SSH応用
フェーズ4: サーバー構築と運用(第28回〜第36回)
