ローカルに仮想環境を構築し、共有フォルダへドキュメントルートを設定しようとして上手くいかない時の対処法について。
Vagrant + VirtualBoxでCentOS7の仮想環境を構築した時にドットインストールを参考にしてドキュメントルートを共有フォルダへのシンボリックに設定したときにハマりました。
長い時間をかけて原因がSELinuxがわかったものの、意地になってSELinuxを無効にはしたくないと思ってしまった人に向けてメモを残しておきます。
* 大人しくSELinuxオフっとくと楽になるよ...(仮想環境なんだからさ...)
ちなみに、ドキュメントルートを共有フォルダのシンボリックリンクに設定するところまでの手順は以下にメモしてあります。
エラーの原因であるSELinuxコンテキストを確認する
今あなたは、ドキュメントルートを変更したら Forbidden(403エラー)となっているのではないでしょうか。もしくはTesting画面にしかならない状態でしょうか。
これは、単純なパーミッションの問題ではなく、「SELinux コンテキスト」の設定がうまくいっていないために、SELinuxによってアクセスが拒否されている状態です。
SELinuxコンテキストとは
SELinuxコンテキストとは、SELinuxによってファイルやディレクトリにラベル付けされた情報のことです。
「ユーザー :ロール:タイプ :レベル 」という4種類の情報を持ちます。
共有フォルダのSELinux コンテキストを確認する
まずは共有フォルダのSELinux コンテキストがどうなっているのかを確認してみましょう。
* 私は、共有フォルダを「/vagrant/data」というパスに設定しています。
環境が異なる方は適宜読み替えてください。
ls -Z コマンドで SELinux コンテキストを確認
[vagrant@localhost ~]$ ls -Z /vagrant
-rw-r--r--. vagrant vagrant unconfined_u:object_r:default_t:s0 Vagrantfile
drwxrwxr-x. vagrant vagrant system_u:object_r:vmblock_t:s0 data
共有フォルダに指定しているdataディレクトリの方に注目してください。
「system_u:object_r:vmblock_t:s0」が dataディレクトリのSELinux コンテキストになります。
- ユーザー:system_u
- ロール :object_r
- タイプ :vmblock_t
- レベル :s0
という内容でラベル付けされています。
今回のエラーの原因は、共有フォルダ(dataディレクトリ)のタイプ、「vmblock_t」です。
*共有フォルダ内に作成したファイルのSELinux コンテキストも全て「vmblock_t」タイプとなっているはずです。
httpdがアクセスできるファイルについて
SELinux有効時、httpdはタイプが「httpd_sys_content_t」のディレクトリやファイルにしかアクセスすることができません。
そのため、タイプが「vmblock_t」となっている共有フォルダの中身へはアクセスできず、403エラーとなってしまうのです。
「vmblock_t」タイプは変更できない。
じゃあ「vmblock_t」を「httpd_sys_content_t」にすればいいんじゃないか!
と思いつき、がんばって調べ、semanage fcontext
コマンドとrestorecon
コマンドでラベルの変更をできることを知り、解決したぜ!と歓喜してしまったあなた。
結局解決できずに再び絶望の淵へと付き落とされたことでしょう。私もです。笑
なぜ上手くいかないのか。「Apache に関する SELinux の設定 (CentOS)」という記事に答えが書いてありました、
VirtualBoxやVMwareなどの仮想機械で開発環境を構築している場合、共有ディレクトリのラベルは変更することができません。
とのこと...。
ああ、落ち込まないで。そのsemanage fcontext
コマンドとrestorecon
コマンドに関する知識は、将来きっと 、本番サーバーを立ち上げる時に役に立ちます。
「vmblock_t」タイプにアクセスできるように新ルールを追加する
さて、最終的な解決方法です。「vmblock_t」を変更することはできない。じゃあどうするか?
「httpd_sys_content_t」の他に「vmblock_t」にもアクセスしていいんだよと、httpdくんに教えてあげるしかないのです。
ここからの手順は以下の2サイトを参考にさせてもらいました。
多大なる感謝の意をここに示します。
ではいきましょう。
必須:SELinuxをPermissiveにしておく
SELinuxが有効になったままの再ラベル付けなどは絶対にNGです。Permissiveにしておきましょう。
Permissiveとは、実際にアクセス拒否はしないが、SELinux的にアウトなことがあればエラーログの記録はしてくれる状態です。
一時的にPermissiveに変更
$ sudo setenforce 0
ちゃんと設定できたか確認
$ sudo getenforce
「Permissive」と表示されればOK
無駄に定義してしまったラベルがある人は、削除しておく
semanage fcontext
とrestorecon
での修正を試みてしまった人は、semanage fcontext
で定義したラベルを削除しておきます。
現在定義済みのラベルの確認
$ sudo vi /etc/selinux/targeted/contexts/files/file_contexts.local
定義済みのラベルがあればこんな感じ
# This file is auto-generated by libsemanage
# Do not edit directly.
/vagrant/data(/.*)? system_u:object_r:httpd_sys_content_t:s0
「/vagrant/data(/.*)」の部分は共有フォルダのパスによって、各々違うと思いますので、読み替えてください。
無駄な定義済みラベルを発見したら、:q でそっと閉じましょう。
定義済みラベルの削除
$ sudo semanage fcontext -d -t httpd_sys_content_t "/vagrant/data(/.*)?"
SELinuxによるエラーログの場所を確認
ログの場所によって次の手順が異なりますので、先に確認しておきましょう。
Linux Audit によるログを確認
Auditが有効な状態の場合、SELinuxによるエラーログがAudtiによって記録されていますので、確認してみましょう。
Auditのログを表示してみる
$ sudo ausearch -m avc
こんなログが表示されるはず
---
time->Sun May 27 01:44:54 2018
type=PROCTITLE msg=audit(1527385494.880:812): proctitle=2F7573722F7362696E2F6874747064002D44464F524547524F554E44
type=SYSCALL msg=audit(1527385494.880:812): arch=c000003e syscall=2 success=yes exit=10 a0=555595622360 a1=80000 a2=0 a3=7ffc092d85e0 items=0 ppid=912 pid=937 auid=4294967295 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=4294967295 comm="httpd" exe="/usr/sbin/httpd" subj=system_u:system_r:httpd_t:s0 key=(null)
type=AVC msg=audit(1527385494.880:812): avc: denied { open } for pid=937 comm="httpd" path="/vagrant/data/index.html" dev="vboxsf" ino=113 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:vmblock_t:s0 tclass=file
type=AVC msg=audit(1527385494.880:812): avc: denied { read } for pid=937 comm="httpd" name="index.html" dev="vboxsf" ino=113 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:vmblock_t:s0 tclass=file
---
このようなログが表示されれば、Auditによるログを使ってSELinuxの新ルールを作成することができます。
実際のAuditによるログは「/var/log/audit/audit.log」に保存されているので、このファイルを直接確認してもOKです。
Auditのログがなかった場合
「/var/log/messages」のログ情報を使用することになります。
* Auditを起動させ、一度ブラウザを更新してAuditによるエラーログを残しても構いません。
ログから新ルールを作成
SELinux に対してアクセス許可ルールを新たに生成することができる便利なコマンド、audit2allow
コマンドというのがあるので、先にこのコマンドを使えるようにしておきましょう。
audit2allow
コマンドは policycoreutils-python というパッケージをインストールすることで使えるようになります。
policycoreutils-pythonパッケージをインストール
$ sudo yum install policycoreutils-python
インストールが完了すれば、新ルールを追加していきましょう。
どのようなルールが追加されるか確認する
Auditログがあった場合
$ sudo audit2allow --module=httpd --all
Auditログがなかった場合
$ sudo audit2allow --module=httpd —dmesg
私の場合は、次のように表示されました。(Auditログを使用しています)
$ sudo audit2allow --module=httpd --all
module httpd 1.0;
require {
type httpd_t;
type vmblock_t;
class file { getattr open read };
}
#============= httpd_t ==============
#!!!! The file '/vagrant/data/index.html' is mislabeled on your system.
#!!!! Fix with $ restorecon -R -v /vagrant/data/index.html
allow httpd_t vmblock_t:file { getattr open read };
先に作成していたindex.htmlに関するメッセージが表示されていますが、これは気にしなくても大丈夫です。
変な記述がなさそうだったら、新ルール追加に必要なファイルを作成します。
*何か変なルールが追加されそうな場合、Auditログを一旦クリアしてから再チャレンジしてみてください。
httpd.ppファイルを作成
$ sudo audit2allow --module-package=httpd --all
表示メッセージ
$ sudo audit2allow --module-package=httpd --all
******************** IMPORTANT ***********************
To make this policy package active, execute:
semodule -i httpd.pp
このコマンドによって、中間ファイル?となる httpd.te ファイルと一緒に、httpd.pp ファイルが作成されます。(コマンドを実行した時のカレントディレクトリに)
この httpd.pp ファイルを元に、最後の仕上げです。
作成されたモジュールをインストール
$ sudo semodule -i httpd.pp
SELinuxを有効にして確認
新ルールのインストールが終われば、SELinuxを Enforcing に戻して確認してみましょう。
SELinuxを Enforcing に
$ sudo setenforce 1
ブラウザを更新しドキュメントルートの中身が表示されていれば解決です!
httpd.teファイルとhttpd.ppファイルは、作業完了後、削除しても大丈夫です。
インストールまで完了しても上手くいかない場合、一度仮想マシンを再起動してみてください。
おわりに
無事に解決したでしょうか?
誰かの参考になれば幸いです。