Edited at

Apache に関する SELinux の設定 (CentOS)

More than 3 years have passed since last update.


導入

SELinuxは、どのプロセスが、どのファイルやディレクトリに、どのような操作(読み取りや書き込み)ができるかを設定するLinuxの拡張機能です。

ネットワーク関連のデーモン(サービス)のみを管理するtargetedポリシーと、SELinuxの機能をフルに利用するstrictポリシーがあります。この項目の解説は、targetedで動作している場合を対象としています。sestatusコマンド実行結果のPolicy from config file:項目を見れば、現在どのポリシーが設定されているかわかります。1


SELinuxが無効になっていた場合

sestatusコマンド実行結果でSELinux status: disabledと表示されていた場合、SELinuxが無効になっています。

設定ファイルを編集し、ひとまずpermissiveモードに変更します。permissiveは、ポリシー違反の場合でもアクセスを遮断せず、ログに記録するだけの動作モードです。1


/etc/selinux/config

# This file controls the state of SELinux on the system.

# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - SELinux is fully disabled.
SELINUX=permissive
# ↑この項目を、disabledからpermissiveに変更する

# SELINUXTYPE= type of policy in use. Possible values are:
# targeted - Only targeted network daemons are protected.
# strict - Full SELinux protection.
SELINUXTYPE=targeted

SELinuxでは、プロセスやファイルにSELinuxセキュリティコンテキストというラベルを付けて、どのラベルが付いているかによってアクセス権の有無を判断します。しかし、SELinuxが無効の状態ではラベルが削除されているので、ラベルの再構築が必要です。以下のように、ルートディレクトリに空の.autorelabelファイルを作成しておけば、次回起動時にラベルの再構築が行われます。2

# 再起動時にラベルの再構築を行う

sudo touch /.autorelabel
# 再起動
sudo reboot

ラベルの再構築をともなうOSの起動は時間がかかるので、実運用環境ではご注意ください。


Webサーバープロセスからのアクセス許可

/etc/selinux/targeted/contexts/files/file_contextsには、どこにどのラベルを張り付けると良いか記述されています。このファイルには、Webサーバーに関するラベル付けの設定が初めから含まれているので、Apacheのドキュメントルート等を対象にrestoreconコマンドを実行するだけでOKです。1

# /var/wwwのラベルの貼り直し

sudo restorecon -R /var/www

以前からWebサーバーを動かしていて、/tmpディレクトリ直下以外の場所にセッションファイルを保存するようにしていたなら、それらのファイルを掃除しておきます。


違反ログから新しいルールを定義

基本的にはこれで、Apacheに関するポリシー違反は起きないと思います。私の環境ではポリシー違反が起きたので、新しいルールを定義しました。

ポリシー違反のログは、sudo grep avc: /var/log/messagesを実行、又はAuditが起動していた状態ならsudo ausearch --message AVCを実行することで確認できます。1

まず、ログをルールに変換するaudit2allowコマンドが使えるようにします。

# audit2allowコマンドが含まれるパッケージを調べる

yum --quiet provides */audit2allow
# policycoreutils-python-2.0.83-19.30.el6.x86_64 : SELinux policy core python utilities
# Repo : base
# Matched from:
# Filename : /usr/bin/audit2allow

# 上で返った情報先頭のパッケージ名を指定してインストール
sudo yum install policycoreutils-python

sudo audit2allow --module=httpd --dmesgを実行、Auditが起動していた状態ならsudo audit2allow --module=httpd --allを実行すれば、ログに記録されているポリシー違反に対応するアクセス許可ルールが出力されます。3 4

私の環境では以下のような出力になりました。


httpd.te

module httpd 1.0;

require {
type httpd_sys_script_t;
type httpd_t;
class process signull;
}

#============= httpd_t ==============
allow httpd_t httpd_sys_script_t:process signull;


これはラベルhttpd_tが付いたプロセスから、ラベルhttpd_sys_script_tが付いたprocessへの、signullを許可するというルールになります。

表示されたルールを確認して問題が無ければ、以下のようにしてルールをインストールします。

# ルールが定義されたモジュールを作成

# ※Auditが起動していた状態なら、--dmesg → --all
sudo audit2allow --module-package=httpd --dmesg
# 作成されたモジュールをインストール
sudo semodule --install=httpd.pp


手動で新しいルールを定義

VirtualBoxVMwareなどの仮想機械で開発環境を構築している場合、共有ディレクトリのラベルは変更することができません。仮想機械上の開発環境において、それらのディレクトリを/var/www以下に配置しているなら、Apacheからのアクセスを許可するルールを定義する必要があります。

まず以下のようなType Enforcementポリシーファイルを作成します。このファイルのルール定義は、私の開発環境のポリシー違反ログをaudit2allowコマンドで変換したものです。httpd_tからvmblock_tへのアクセスを許可しています。


httpd.te

module httpd 1.0;

require {
type httpd_t;
type vmblock_t;
class dir { getattr search read open };
class file { getattr read open };
}

#============= httpd_t ==============
allow httpd_t vmblock_t:dir { getattr search read open };
allow httpd_t vmblock_t:file { getattr read open };


ファイル操作を行うCGIスクリプトを利用しているなら、以下のように書き込みや実行も許可する必要があります。


httpd.te

module httpd 1.0;

require {
type httpd_t;
type vmblock_t;
class dir { getattr search read open write remove_name add_name };
class file { getattr read open write lock execute execute_no_trans ioctl append setattr create unlink };
}

#============= httpd_t ==============
allow httpd_t vmblock_t:dir { getattr search read open write remove_name add_name };
allow httpd_t vmblock_t:file { getattr read open write lock execute execute_no_trans ioctl append setattr create unlink };


このルールを以下のように2段階でコンパイルし、インストールします。5 6

# 中間ファイルの作成

checkmodule -m -M -o httpd.mod httpd.te
# 中間ファイルをコンパイル
semodule_package --outfile httpd.pp --module httpd.mod
# インストール
sudo semodule --install=httpd.pp


SELinuxがpermissiveモードで動いている場合

前述の通り、permissiveモードはログを残すだけでアクセスを遮断しないので、実際にアクセスを遮断するenforcingモードに切り替えます。

sestatusコマンド実行結果でMode from config file: permissiveと表示されていた場合、OS起動時にpermissiveモードになります。設定ファイルを編集してenforcingモードで起動するようにしておきます。


/etc/selinux/config

# This file controls the state of SELinux on the system.

# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - SELinux is fully disabled.
SELINUX=enforcing
# ↑この項目を、permissiveからenforcingに変更する

# SELINUXTYPE= type of policy in use. Possible values are:
# targeted - Only targeted network daemons are protected.
# strict - Full SELinux protection.
SELINUXTYPE=targeted

getenforceコマンドを実行してPermissiveと表示された場合、以下のコマンドを実行して動作モードを変更します。1

# SELinuxをenforcingモードに(OS終了時まで)

sudo setenforce 1

1ではなく0を指定すれば、再びpermissiveモードに変更できます。


【追記】mod_sslを利用している場合

SSLCertificateFileディレクティブで設定する公開鍵ファイルSSLCertificateKeyFileディレクティブで設定する秘密鍵ファイル、およびSSLPassPhraseDialogディレクティブで設定するパスフレーズを出力するプログラムファイルへのラベル付けが適切に行われている必要があります。


SSLPassPhraseDialog builtinの場合

公開鍵ファイル、および秘密鍵ファイルの両方にhttpd_config_tが貼り付けられている必要があります。

両方のファイルが/etc/httpd以下のディレクトリに配置されていれば、sudo restorecon -R /etc/httpdを実行すればOKです。


SSLPassPhraseDialog exec:{プログラムファイルのパス}の場合

公開鍵ファイルhttpd_config_tが、秘密鍵ファイルパスフレーズを出力するプログラムファイルhttpd_sys_script_exec_tが貼り付けられている必要があります。さらに以下のルールをインストールしなければならないようです。


httpd.te

module httpd 1.0;

require {
type user_devpts_t;
type httpd_sys_script_t;
class capability { dac_override };
class chr_file { read write };
}

#============= httpd_sys_script_t ==============
allow httpd_sys_script_t self:capability { dac_override };
allow httpd_sys_script_t user_devpts_t:chr_file { read write };


semanageコマンドを使うと、ラベルを永続的に変更できます。1


設定例

sudo semanage fcontext --add --type httpd_sys_script_exec_t /usr/local/apache/sbin/pp-filter

sudo restorecon /usr/local/apache/sbin/pp-filter


【追記】ソケット通信を利用している場合

PHPなどのプログラムからWhois検索をしたりするために、ソケット通信が必要になりますが、SELinuxは既定でこれを許可しません。

sudo setsebool -P httpd_can_network_connect on を実行し、永続的に許可しておきます。7


【追記】データベースを利用している場合

PHPなどのプログラムからデータベースに接続するには、以下のルールが必要になります。

module httpd 1.0;

require {
type init_t;
class unix_stream_socket connectto;
}

#============= httpd_t ==============
allow httpd_t init_t:unix_stream_socket connectto;


参考ページ