実行環境
- CentOS Linux release 7.4.1708 (Core)
- Apache/2.4.6 (CentOS)
ここでは、新しく追加するCGIのディレクトリを /var/www/platform
としています。作成するディレクトリに合わせて適宜読み替えてください
ディレクトリの作成
Apacheの実行ユーザーで読み書きができるディレクトリを作成します
# mkdir /var/www/platform
# chmod 775 /var/www/platform
# chown root.apache /var/www/platform
/var/www/cgi-bin と合わせて root.apache にすれば良いと思います
# ls -ld /var/www/cgi-bin /var/www/platform
drwxrwxr-x. 2 root apache 28 12月 5 19:12 /var/www/cgi-bin
drwxrwxr-x. 5 root apache 64 12月 6 13:45 /var/www/platform
Apacheの設定
基本的には Apacheのドキュメント の通りに設定します
/etc/httpd/conf.d
に新しく追加するディレクトリの設定を追加します。ここでは /etc/httpd/conf.d/test_platform.conf
という名前で新しい設定ファイルを作りましたが、末尾が ".conf" であればどのような名前でも構いません、自分が新たに何の目的で作ったのか分かるような名前にすれば良いと思います
/etc/httpd/conf.d/test_platform.conf
Alias /platform/ /var/www/platform/
<Directory "/var/www/platform">
AllowOverride None
Options ExecCGI
Require method GET POST OPTIONS
<FilesMatch (\.cgi|^[^\.]+)$>
Sethandler cgi-script
</FilesMatch>
</Directory>
この設定で http://%サーバーのアドレス%/platform/
配下が /var/www/platform/
内のコンテンツとして配置されます。ここでは platform ディレクトリ内に CGIスクリプトだけでなく、画像やHTMLコンテンツの配置も考えて ScriptAlias
ではなく Alias
にして Options ExecCGI
を設定するようにしています。また、 .cgi
の拡張子だけでなく、拡張子のない場合は CGI スクリプトとして動作するようにしています
変更後は、設定を適用させます
# systemctl reload httpd.service
SELinuxの設定
※ SELinuxを無効にしている場合は、この手順は必要ありません
Apacheの設定が完了し、いざcgiを実行しようとすると 503 エラー。ログを見るとスクリプト実行のパーミッション拒否でした
AH01215: (13)Permission denied: exec of '/var/www/platform/test' failed
もちろんファイルのオーナーや実行権の確認はしています
# ls -l
合計 1
-rwxr-xr-x. 1 apache apache 71 12月 5 18:42 test
ネットで見ると、SELinuxの動作が疑わしかったのですが、Auditログや ausearch --message AVC
コマンドを確認しても拒否された情報が残っていなかったので、Apacheの設定ミスなのかと思ってかなりハマってしまいました。setenforce 0
を実行するとCGIスクリプトが動作するようになったので、SELinuxの設定は必要だったようです。
SELinuxにはファイルパスに対して、どんな目的で利用されるかといったコンテキストを持っていて、その目的以外のアクセスが行われるとブロックする機能があります。その設定は /etc/selinux/targeted/contexts/files/file_contexts
にあり、これを見てみると cgi-bin とついた名前のディレクトリに対して httpd_sys_script_exec_t というタイプが設定されるようになってます
$ grep 'cgi-bin' /etc/selinux/targeted/contexts/files/file_contexts
/var/www/[^/]*/cgi-bin(/.*)? system_u:object_r:httpd_sys_script_exec_t:s0
/var/www/html/[^/]*/cgi-bin(/.*)? system_u:object_r:httpd_sys_script_exec_t:s0
/usr/lib/cgi-bin(/.*)? system_u:object_r:httpd_sys_script_exec_t:s0
/var/www/cgi-bin(/.*)? system_u:object_r:httpd_sys_script_exec_t:s0
/usr/lib/mailman.*/cgi-bin/.* -- system_u:object_r:mailman_cgi_exec_t:s0
/usr/lib/cgi-bin/(nph-)?cgiwrap(d)? -- system_u:object_r:httpd_suexec_exec_t:s0
/var/www/cgi-bin/munin.* system_u:object_r:munin_script_exec_t:s0
:
新しいCGIのディレクトリにも、このコンテキストを設定すればCGIスクリプトが実行できるようになります。コンテキストの設定には semanage
コマンドを使います。ディレクトリ名の後に (/.*)?
を付けて、正規表現でディレクトリ自身とその配下に含まれるファイルやサブディレクトリを指すようにします
# semanage fcontext -a -t httpd_sys_script_exec_t '/var/www/platform(/.*)?'
# semanage fcontext -C -l
SELinux fcontext タイプ コンテキスト
/var/www/platform(/.*)? all files system_u:object_r:httpd_sys_script_exec_t:s0
/etc/selinux/targeted/contexts/files/file_contexts.local が出来上がるので、中を見てみると、新規登録した /var/www/platform
が記述されています
実行例
# cat /etc/selinux/targeted/contexts/files/file_contexts.local
# This file is auto-generated by libsemanage
# Do not edit directly.
/var/www/platform(/.*)? system_u:object_r:httpd_sys_script_exec_t:s0
restorecon
コマンドを実行して、ディレクトリに変更したタイプを設定します
# restorecon -v /var/www/platform
restorecon reset /var/www/platform context unconfined_u:object_r:httpd_sys_content_t:s0->unconfined_u:object_r:httpd_sys_script_exec_t:s0
※ /var/www 以下ではないディレクトリであれば変更前のタイプは httpd_sys_content_t
になってないかもしれません。
httpd_sys_content_t
から httpd_sys_script_exec_t
に変わったことを確認します。コンテキストの確認には ls
コマンドの -Z
オプションを使います
ディレクトリ自体のコンテキスト
# ls -dZ /var/www/platform
drwxrwxr-x. root apache unconfined_u:object_r:httpd_sys_script_exec_t:s0 /var/www/platform
ディレクトリ内のファイルのコンテキスト
$ ls -l -Z /var/www/platform/test
-rwxr-xr-x. apache apache unconfined_u:object_r:httpd_sys_script_exec_t:s0 /var/www/platform/test
これでCGIスクリプトが実行できるようになっているはずです
参考
redhat CUSTOMER PORTAL - 4.6. SELINUX コンテキスト – ファイルのラベル付け
https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/selinux_users_and_administrators_guide/sect-security-enhanced_linux-working_with_selinux-selinux_contexts_labeling_files