はじめに
現場で働いていた際に別のプロジェクトでSELinuxという言葉が飛び交っていました。自分自身も前PJのTeamsで「SELinuxがどうちゃらこうちゃら」と誰かがやりとりしていたのを思い出しました。今回気になったので、自分なりに調べてまとめてみました。
1. SELinuxとは?
SELinux(Security-Enhanced Linux) とは、Linuxに組み込まれた 強制アクセス制御(MAC: Mandatory Access Control) の仕組みです。
通常のLinux(任意アクセス制御: DAC)では、root権限を持つユーザーはほぼすべての操作を実行できます。そのため、万が一root権限が漏洩すると、被害がシステム全体に及ぶ可能性があります。
SELinuxはこの問題に対処するため、たとえroot権限であってもアクセスに制限をかけることができます。これにより、侵害が発生した場合でも 被害の拡大を最小限に抑えることが可能になります。
Red Hat系のディストリビューション(RHEL, CentOS, AlmaLinuxなど)では、SELinuxは デフォルトで有効(ON) になっています。
2. 仕組み:主要な概念と動作モード
SELinuxがどのようにアクセスを制御しているのか、その仕組みを解説します。
ラベル(コンテキスト)
SELinuxでは、すべてのプロセス、ファイル、ネットワークポートなどに 「ラベル(コンテキスト)」 が付与されています。
ls -Z や ps -Z で詳細を見ると、以下のような形式で表示されます。
user:role:type:level
| 要素 | 名前 | 説明 |
|---|---|---|
| user | ユーザー | SELinux独自のユーザー識別子。標準のLinuxユーザーとは別に管理されます。 |
| role | ロール | プロセスが持つ「役割」を定義します(RBAC)。ファイルの場合は通常 object_r です。 |
| type | タイプ | 最重要。 プロセスやファイルの「タイプ」を定義します(TE)。アクセス制御の主役です。 |
| level | レベル | マルチレベルセキュリティ(MLS)で使われます。通常は s0 などが表示されます。 |
実務上でトラブル解決や設定変更を行う際、ほとんどのケースで意識するのは type(タイプ) だけです。
-
プロセス側: 「このプログラムは
httpd_tというタイプだ」 -
ファイル側: 「このファイルは
httpd_sys_content_tというタイプだ」 -
ルール: 「
httpd_tタイプのプロセスは、httpd_sys_content_tタイプのファイルにアクセスして良い」
このように、タイプ同士の組み合わせでアクセスを許可する仕組みを TE (Type Enforcement) と呼びます。
アクセスチェックの流れ
Linuxカーネル内では、以下の順番でチェックが行われます。
- DAC (任意アクセス制御): 従来の「ユーザー/グループ/権限(rwx)」のチェック。
- MAC (強制アクセス制御/SELinux): DACをパスしても、SELinuxのポリシーに反していれば拒否される。
「rootだからOK」というDACの常識を、SELinuxのMACが上書きして制限をかけるのが大きな特徴です。
SELinux内部の判定プロセス
SELinuxがどのようにアクセスを判定しているかを図解すると以下のようになります。
(出典:Red Hat Enterprise Linux 5 導入ガイド Section 45.2. SELinux のメリット)
- Subject(主体): アクセスを要求する主体。主にプロセスです(例:Apacheなど)。
- Action Request: SubjectがObjectに対して行いたいアクション(read, write, openなど)。
- SELinux Security Server: Linuxカーネル内にあり、アクセスを許可するかどうかを判断する中心的なエンジンです。
- SELinux Policy Database: 管理者が定義したセキュリティルール(ポリシー)の集合体です。Security Serverはここを参照して判定を行います。
-
Permission Granted?:
- Yes: アクセスが許可され、Object(ファイルやディレクトリなど)にアクセスできます。
- No: アクセスが拒否され、AVC(Access Vector Cache) を通じて拒否ログ(Denied Message)を出力します。
3つの動作モード
| モード | 説明 |
|---|---|
| Enforcing | ポリシーを強制。不正なアクセスを実際に遮断します。 |
| Permissive | アクセス拒否はしませんが、警告(ログ出力)のみ行います。デバッグ用です。 |
| Disabled | SELinux自体を無効にします。適用にはOS再起動が必要です。 |
3. ハンズオン1:SELinuxの現状確認とモード切替
ここでは、SELinuxが動いているかどうかの確認と、システムを停止せずにモード(有効/無効のようなもの)を切り替える方法をハンズオンします。
手順 1-1:現在のステータスを詳しく確認する
まず、現在のSELinuxの状態全体を表示します。
以下のコマンドを実行します。
sestatus
実行結果の確認: 以下のような出力が表示されます。特に Current mode に注目してください。
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
手順 1-2:簡易コマンドでモードを確認する
getenforce
実行結果の確認: Enforcing(または Permissive)と表示されます。
手順 1-3:モードを「Permissive」に変更する
sudo setenforce 0
変更されたか確認します。
getenforce
# Permissive と表示されればOK
手順 1-4:モードを「Enforcing」に戻す
セキュリティを有効な状態に戻します。
sudo setenforce 1
確認します。
getenforce
# Enforcing と表示されればOK
[重要事項]
setenforceコマンドによる変更は一時的です。再起動すると元に戻ります(設定ファイル/etc/selinux/configの内容が優先されます)。
4. ハンズオン2:ファイルコンテキスト(ラベル)の確認と変更実験
SELinuxは、ファイルにつけられた「ラベル(名札)」を見てアクセス制御を行います。このラベルを見て、触って、直す体験をします。
手順 2-1:実験用のファイルを作成する
まず、実験用のファイルを /root ディレクトリに作成します。
cd /root
touch selinux_test.txt
手順 2-2:ファイルについた「ラベル」を確認する
通常の ls コマンドではラベルは見えません。 -Z オプションを使います。
ls -Z selinux_test.txt
実行結果の確認: 以下のような文字列が表示されます。
system_u:object_r:admin_home_t:s0 selinux_test.txt
この system_u:object_r:admin_home_t:s0 がSELinuxのコンテキスト(ラベル)です。 特に重要なのが、3番目の admin_home_t(タイプ) です。SELinuxは主にここを見て判断します。
手順 2-3:ラベルを一時的に書き換える(chcon)
このファイルのラベルを、Webサーバー用のラベル(httpd_sys_content_t)に無理やり書き換えてみます。
chcon -t httpd_sys_content_t selinux_test.txt
変わったかどうか確認します。
ls -Z selinux_test.txt
実行結果の確認:
system_u:object_r:httpd_sys_content_t:s0 selinux_test.txt
admin_home_t だった部分が httpd_sys_content_t に変わりました。
手順 2-4:本来あるべきラベルに戻す(restorecon)
「設定をいじってラベルがおかしくなった!」という状況を想定し、システムが定義している「あるべき正しいラベル」に自動修復します。
restorecon -v selinux_test.txt
実行結果の確認: 修復された旨が表示されます。
Relabeled /root/selinux_test.txt from system_u:object_r:httpd_sys_content_t:s0 to system_u:object_r:admin_home_t:s0
念のため確認します。
ls -Z selinux_test.txt
# 元の admin_home_t に戻っているはずです。
手順 2-5:後片付け
作成したファイルを削除します。
rm selinux_test.txt
5. ハンズオン3:Webサーバーの実践(ドキュメントルートとポートの変更)
Webサーバー(Apache)を例に、「ディレクトリの場所を変える」「ポート番号を変える」といった実務でよくあるシナリオを通じ、SELinuxの制御と修正方法を学びます。
ドキュメントルート変更による「403 Forbidden」の体験
通常、Webサーバーのファイルは /var/www/html に置きますが、運用上の都合で /web という独自ディレクトリに変更したと仮定します。
手順 3-1:独自ディレクトリとファイルの作成
ルート直下に /web ディレクトリを作成し、テスト用のHTMLファイルを用意します。
mkdir /web
echo "<h1>SELinux Test Page</h1>" > /web/index.html
作成したファイルのラベルを確認しておきます。
ls -Zd /web
実行結果:
unconfined_u:object_r:default_t:s0 /web
タイプが default_t(役割未定義)になっており、このままではWebサーバーからアクセスできません。
手順 3-2:Webサーバーの設定を変更する
Apacheの設定を書き換えて、参照先を /web に変更します。
# 設定ファイルをバックアップ
sudo cp /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.bak
# DocumentRootを /web に書き換え
sudo sed -i 's|DocumentRoot "/var/www/html"|DocumentRoot "/web"|' /etc/httpd/conf/httpd.conf
# ディレクトリ権限設定も /web に書き換え
sudo sed -i 's|<Directory "/var/www">|<Directory "/web">|' /etc/httpd/conf/httpd.conf
# Apacheを再起動
sudo systemctl restart httpd
手順 3-3:アクセス拒否(エラー)を体験する
ブラウザの代わりに curl でアクセスを確認します。
curl localhost
実行結果の確認: 以下のような「403 Forbidden」が返ってくるはずです。これがSELinuxによるブロックです。
<h1>Forbidden</h1>
<p>You don't have permission to access this resource.</p>
手順 3-4:ログで拒否の証拠を確認する
「403エラーの原因が本当にSELinuxなのか?」をログで確認します。SELinuxの拒否ログ(AVC拒否)は通常 /var/log/audit/audit.log に出力されます。
以下のコマンドを実行します。
sudo ausearch -m avc -ts recent
実行結果の確認: denied { read }(読み取り拒否)と記されており、comm="httpd" が default_t のファイルを読もうとして止められた証拠が確認できます。
手順 3-5:正しい修正(semanage fcontext / restorecon)
「/web 以下のすべてはWeb用コンテンツである」というルールをSELinuxに登録し、適用します。
# ルールを登録
sudo semanage fcontext -a -t httpd_sys_content_t "/web(/.*)?"
# ルールをファイルに適用
sudo restorecon -R -v /web
手順 3-6:アクセス成功の確認
もう一度アクセスします。
curl localhost
# <h1>SELinux Test Page</h1> と表示されれば成功です!
非標準ポート(8081)での起動失敗と修正
次に、Webサーバーのポートを 80 から 8081 に変更してみます。
手順 3-5:ポートを変更して再起動
# ポートを 8081 に変更
sudo sed -i 's/Listen 80/Listen 8081/' /etc/httpd/conf/httpd.conf
# Apacheを再起動
sudo systemctl restart httpd
実行結果: 起動に失敗します(Job for httpd.service failed...)。 systemctl status httpd で確認すると Permission denied が記録されています。
手順 3-7:ログからエラー原因を特定する
起動失敗の理由をログから紐解きます。以下のコマンドで詳細なSELinuxログを確認します。
sudo ausearch -m avc -ts recent
実行結果の確認: denied { name_bind } とあり、ポート 8081 (src=8081) へのバインドがSELinuxによって拒否されたことが記録されています。
手順 3-8:ポートのラベルを確認して許可する
SELinuxの許可リストに 8081 を追加します。
# 許可されているポートの一覧を確認
semanage port -l | grep http_port_t
# 8081 を追加
sudo semanage port -a -t http_port_t -p tcp 8081
手順 3-9:Webサーバーの起動確認
sudo systemctl restart httpd
curl localhost:8081
# <h1>SELinux Test Page</h1> が表示されれば成功です。
まとめ
現場でSELinuxは難しいという理由で"SELinuxを無効"にしているPJがあるように感じます。SELinuxを有効に保つことは、サーバーのセキュリティを一段上のレベルに引き上げます。昨今のランサムウェアを踏まえて、セキュリティ意識が高まっているように思えますが、意外にもエンジニアでセキュリティのことまで考慮してシステム開発できる人材は少ないと思っています。自分もまだまだ未熟者ですが、多くのことを学び、お客様にとって安全で便利なシステムを作れるようになりたいと思っています。この記事でご紹介した内容を踏まえて少しでもSELinuxについて理解していただければ幸いです。
