Amazon Linux 2022 にユーザーデータで WordPress を入れる際の SELinux の設定
先日、JAWS-UG 初心者支部#47 千葉支部コラボ AWS入門ハンズオン - AWSを触ってみよう - でハンズオン資料を作りました。
https://github.com/otanikohei/Amazon-VPC---Amazon-EC2---Amazon-RDS-Handson
ハンズオンの元ネタは亀田さんの「AWS体験ハンズオン〜セキュア&スケーラブルウェブサービス構築.pdf」で、 Github でも公開されています。Amazon EC2 を使って、WordPress 環境を構築し、RDS、ALB を使って可用性を高める内容の PDF 資料です。
リメイクは PDF ではなく、初心者支部の武田さんが Zenn で公開されている claatツールを使って簡単にGoogleドキュメントでハンズオン手順を作る を参考に、Google Codelabs で作りました。
今日は、この 手順 16 に記載しているユーザーデータの SELinux について検証した内容をまとめてみたいと思います。
Amazon Linux 2022 は SELinux が有効です
Amazon Linux 2022 はデフォルトで SELinux が有効になっています。
[root@ip-10-0-0-57 ~]# getenforce
Enforcing
[root@ip-10-0-0-57 ~]#
僕はこれまで「SELinux は無効化するもの」ぐらいに捉えていて、Amazon Linux 2 も SELinux が無効化されていたので触れる機会がありませんでした。
そのため、Amazon Linux 2022 で SELinux を無効化したところ
sed -i -e "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config
再起動後にインスタンスが起動しなくなりました。
※ /etc/selinux/config の SELINUX=enforcing を SELINUX=disabled に変更して無効化してみました。
disable にすると再起動後に起動しなくなる
EC2 コンソールで起動しないインスタンスを選択して、アクション > モニタリングとトラブルシューティング > インスタンスのスクリーンショットを取得 を選択して確認したところ、SELinux policy エラーが表示されて止まっていました。
SELinux の無効化方法が間違っていると思われたので、SELinux とはなんぞや?から調べていくことにしました。
SELinux とは?
e-words、Fedra のドキュメントなどを参考に、以下のような機能と捉えました。
SELinux の正式名称は Security-Enhanced Linux
セキュリティ拡張モジュール
ファイルに権限ポリシーを明記したラベルをつけて挙動をコントロールする
Linux の「root ユーザーにスイッチしたら全ファイルを自由に扱える仕様」は攻撃に対して脆弱なので、プロセスごとに扱えるファイルを細かく指定できる機能といったところかと理解しています。
SELinux の正しい無効化
マニュアルに grubby コマンドを使って無効化するようにと記載がありました。
[root@ip-10-0-0-58 ~]# man setenforce
DESCRIPTION
SELinux を disable にしたい場合、または SELinux は有効にしつつ挙動を無効にしたい場合は、 selinux(8) を参照してください。
grubby --update-kernel ALL --args enforcing=0
selinux のマニュアルには以下の通りカーネルレベルで無効化するように記載がありました。なので、grubby コマンドを使う必要があるようです。
[root@ip-10-0-0-58 ~]# man selinux
DESCRIPTION
注意
/etc/selinux/config に SELINUX=disabled と記述して SELinux を無効にすることは非推奨です。
SELinux は完全に無効になるわけではありません。 具体的には、SELinux フックは内部的に実行されますが、SELinux ポリシーが実行されません。
そのため、操作が拒否されることはありませんから、システムは SELinux が無効であるかのように動作しますが、一部の操作については若干挙動が異なります。
SELinux を適切に無効化するには、代わりに selinux=0 カーネルブートオプションを使用することをお勧めします。
この場合、SELinuxは /etc/selinux/config ファイルで設定されている内容に関係なく無効化されます。
※ ↑ 英語のマニュアルを抜粋 & 意訳しています。正しい英語は直接 man して確認ください。
SELinux のステータス
有効化、無効化の話を展開してきましたが、そもそも、SELinux のステータスは 3 つあります。
現在のステータスは getenforce コマンドにて確認でき、一時的な設定は setenforce にて行います。
[root@ip-10-0-0-58 ~]# getenforce
Enforce
[root@ip-10-0-0-58 ~]
Enforce (1)
SELinux が有効な状態です。setenforce コマンドで設定可能です。これは一時的な設定で再起動すると元に戻ります。Permissive (0)
SELinux は無効化されていますが、監査は有効でセキュリティログは記録されます。setenforce コマンドで設定可能です。Disable
無効化された状態です。setenforce コマンドで設定できません。
grubby コマンド
前述の通り、SELinux を無効化するには grubby コマンドを利用します。以下を投入すると、再起動後、恒久的に SELinux が Permissive モードになります。
[root@ip-10-0-0-58 ~]# grubby --update-kernel ALL --args enforcing=0
[root@ip-10-0-0-58 ~]# reboot
SELinux を有効にして運用するには
実際、SELinux は無効化するのがベストプラクティスなのでしょうか。
ここまで 3 つのモードを前提に話を進めてきましたが、有効化には様々なポリシーがあります。
getsebool コマンド
ポリシーの一覧が確認できます。結構な数が出力されます。httpd のポリシーだけでも 44 ありました。
[root@ip-10-0-0-57 ~]# getsebool -a
abrt_anon_write --> off
abrt_handle_event --> off
abrt_upload_watch_anon_write --> on
antivirus_can_scan_system --> off
antivirus_use_jit --> off
(中略)
httpd_can_network_connect --> on
httpd_can_network_connect_cobbler --> off
httpd_can_network_connect_db --> off
(以下省略)
例えば、単に SELinux を有効にしたまま Nginx サーバーにアクセスすると通信がブロックされて、Access Denied になります。
setsebool コマンド
ポリシーを設定します。書き方は以下の通りです。
setsebool -P ポリシー名 オプション
上記の Access Denied エラーを回避するには、httpd_can_network_connect を許可し、WeodPress の場合は更に httpd_can_network_connect_db を許可します。
# Apache や Nginx といった Web サービスの DB アクセスを許可
[root@ip-10-0-0-57 ~]# setsebool -P httpd_can_network_connect_db 1
# Apache や Nginx といった Web サービスのネットワーク接続を許可
[root@ip-10-0-0-57 ~]# setsebool -P httpd_can_network_connect 1
ラベルの理解
SELinux と付き合っていくにはラベルの理解が必要です。chmod で権限を設定しているにも関わらずアクセスできない場合は、このラベルが正しくない可能性があります。ラベルの確認は、ls コマンドの Z オプションを使います。
ls -lZ
semanage と restorecon
ラベルの変更には、semanage コマンドと restorecon コマンドを使います。
semanage コマンドは、SELinux ポリシーのラベルを変更しファイルごとの参照権限や書き込み権限を付与するマネジメントツールです。
書き込みをすべきディレクトリに権限を付与します。
WordPress だと、wordpress のインストールディレクトリの読み込みが必要なので、semanage コマンドで httpd_sys_content_t ラベルをつけます。
semanage fcontext -a -t httpd_sys_content_t "/usr/share/nginx/html/wordpress(/.*)?"
ラベルをつけたら、restorecon コマンドで適用します。
restorecon -R -v /usr/share/nginx/html/wordpress
更に、WordPress は wp-content 配下に Nginx プロセスからの書き込みが必要ですので、httpd_sys_rw_content_t ラベルをつけます。
semanage fcontext -a -t httpd_sys_rw_content_t "/usr/share/nginx/html/wordpress/wp-content(/.*)?"
restorecon -R -v /usr/share/nginx/html/wordpress/wp-content
WordPress のセットアップ
WordPress は、wordpress のディレクトリーに wp-config.php というファイルが存在しないとセットアップ画面が表示されるように作られています。
そして、セットアップ時に WordPress (Nginx プロセス) が wp-config.php を生成します。
ここで一つ問題になるのが、wordpress のルートディレクトリは Nginx に対して読み取り専用にしておきたいのに、その読み取り専用のディレクトリに wp-config.php を作らせないといけないという点です。
実際にやってみないとピンと来ないかも知れませんが、semanage コマンドはファイルが存在しないとラベルを貼れないので、回避が難しいのです。
wp-config.php を作る方法
テーマは SELinux と共存していくなのですが、SELinux が Nginx をブロックしてしまうので回避が難しい WordPress のセットアップ (wp-config.php を作る手順)。
いくつか回避策を検討しました。
1 - SELinux を一時的に無効化する
ハンズオン資料に取り入れた方法です。再起動すると元に戻ります。つまり、WordPress のセットアップを行うときだけ一時的に SELinux を無効化してセットアップが完了したらサーバーを再起動するという方法になります。
setenforce 0
2 - サーバーの中で手動で作成する
Nginx にファイルを生成させず、自ら SSH (ターミナル接続) してファイルを作成するという方法も取れます。
WordPress のセットアップは wp-config.php の存在しなければ起動します。この wp-config.php は手動でも作れます。
wordpress のルートディレクトリに予めテンプレートファイルとして、wp-config-sample.php が用意されているので、コピーして必要な箇所のみ書き換えます。
cp -p wp-config-sample.php wp-config.php
vi wp-config.php
これならラベルの変更は不要です。
3 - SELinux を完全に無効化する
SELinux と共生するのが本記事のテーマなので本筋ではないですが、初心者用のハンズオンということもあり無効化しました。なお、grubby コマンドによる無効化は再起動が必要なので、一時的に無効化する setenforce 0 を併用しています。
setenforce 0
grubby --update-kernel ALL --args enforcing=0
いかがだったでしょうか。マスターすればそれだけで飯が食える。というくらい複雑だけど重要な SELinux。
是非、興味を持たれた方はこの機会に SELinux 沼にドップリ浸かってみてください。そして、この記事の改善点などあれば教えていただけると大変助かります。