SELinuxをRedmine 3.4 + Passenger + CentOS 7の環境で有効にする

2018-01-12 10:00  •  分類: ,  •  @ishikawa84g

Redmine 3.4をCentOS 7.3にインストールする手順」でインストールしたRedmineの環境で、SELinuxを有効にするための手順です。


このサイトで公開しているCentOS用のRedmineインストール手順ではSELinuxを無効にしています。

「SELinuxが有効な状態の手順を掲載してほしい」との要望はこれまで何度も寄せられていました。ただ、Redmine.JP Blogに掲載してたくさんの方にご覧いただくのであれば、「とりあえず動く」手順ではなく、SELinuxの専門家の方にも納得いただけるものでなければならないと考えていました。

そこで、セキュアOSのコミュニティなどでご活躍でSELinuxに造詣が深い石川さん(@ishikawa84g)に相談したところ、記事の執筆を快く引き受けていただきました。石川さん、ありがとうございました。

現時点ではいくつか未確認の内容が残っていますが、今後解決を進めていきます。SELinuxの活用やRedmineサーバ構築の参考にしていただけると幸いです。


はじめに

本来SELinuxを使う上ではディストリビューション用に調整されたパッケージとそのパッケージ用に調整されたSELinux Policyを使用することが望ましいです。 Phusion Passenger(以下、Passenger)を専用のドメインで動作するにあたり、ディストリビューションが提供するパッケージを使用したいところですが、以下の理由から難しくなっています。

  1. CentOS 7ではPassengerのパッケージを提供していない
    • gemでインストールするため、用意されたポリシーではラベル付けが適切に行えない
  2. Phusion Passenger公式から提供されているパッケージに含まれているSELinux Passenger moduleの品質が極めて低い
    • 本来はこのパッケージを利用したいが利用できない。利用する場合手順が複雑化する。

(SELinux Passenger module自体に若干の改良の余地はありますが) ここではRedmine 3.4をCentOS 7.3にインストールする手順の通りにインストールしたRedmineをSELinuxが有効な環境で動作させるための手順を記載します。

SELinuxの用語

用語 説明
Disabled mode SELinuxが無効化されてる状態
Permissive mode SELinuxのポリシー違反を監視するが実際のアクセス拒否を行わずにアクセス拒否ログだけを出力する状態
Enforcing mode SELinuxが有効な状態。ポリシーに反するアクセスは全て拒否されログに記録する
Label SELinux上のユーザ、ロール、タイプ、レベルをひとまとめにした識別子
Domain プロセスに割り当てられたラベル
File Context ファイルに割り当てられたラベル

SELinuxの有効化

「Redmine 3.4をCentOS 7.3にインストールする手順」を使用して構築した環境ではSELinuxの状態がDisabledに設定されています。SELinuxがDisabledの状態で作成されたファイルにはSELinuxのラベルが付与されません。SELinuxを使用するためには全てのファイルにSELinuxのラベルを付与する必要があります。これを ファイルシステムの再ラベル付け と呼びます。

再ラベル付けをすることでSELinuxが利用できるようになります。再ラベル付け後、初めてシステムにアクセスをするとポリシー違反によっていくつかの必要な処理が拒否される場合があります。アクセス拒否が起動中に発生するとシステム自体が起動できなくなる可能性があります。これを回避するため、SELinuxのモードを必ず Permissive モードに設定します。全ての設定が完了した後で、SELinuxのモードを改めて Enforcing モードに変更します。

SELinuxの起動モードを変更する

OS起動時のSELinuxのモードをPermissiveモードに変更します。

$ sudo sed -i "s/\(^SELINUX=\).*/\1permissive/" /etc/selinux/config

再起動時に再ラベル付けを行う

/.autorelabelというファイルを作成すると次回OS起動時に再ラベル付けを行います。

$ sudo fixfiles onboot
$ sudo shutdown -r 0

起動後の状態を確認する

SELinuxの状態確認

再起動後、SELinuxの状態を確認します。

$ sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   permissive  ← 現在のモードがPermissiveモードになっていることを確認
Mode from config file:          permissive  ← 設定ファイル上の設定がPermissiveモードになっていることを確認
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Max kernel policy version:      28

Apache及びPassengerのドメインの確認

ps コマンドに Zオプション を付与するとプロセスのドメインを確認できます。以下の例ではApache、Passengerいずれもhttpd_tドメインで動作していることがわかります。

$ ps axuZ | grep -e [P]ass -e [h]ttpd
system_u:system_r:httpd_t:s0  root     857  0.0  0.1 294516  6476 ?   Ss   23:23   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0  root    1102  0.0  0.1 362928  4776 ?   Ssl  23:23   0:00 Passenger watchdog
system_u:system_r:httpd_t:s0  root    1105  0.0  0.3 666752 11772 ?   SNl  23:23   0:00 Passenger core
system_u:system_r:httpd_t:s0  apache  1117  0.0  0.1 294516  4396 ?   S    23:23   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0  apache  1118  0.0  0.1 294516  4184 ?   S    23:23   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0  apache  1119  0.0  0.1 294516  4396 ?   S    23:23   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0  apache  1120  0.0  0.1 294516  4140 ?   S    23:23   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0  apache  1341  1.5  2.5 388816 99128 ?   Sl   23:39   0:02 Passenger AppPreloader: /var/lib/redmine
system_u:system_r:httpd_t:s0  apache  1360  0.2  3.2 458384 127492 ?  Sl   23:39   0:00 Passenger RubyApp: /var/lib/redmine
system_u:system_r:httpd_t:s0  apache  1372  0.0  0.1 294516  4400 ?   S    23:39   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0  apache  1373  0.0  0.1 294516  4144 ?   S    23:39   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0  apache  1374  0.0  0.1 294516  4404 ?   S    23:39   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0  apache  1375  0.0  0.1 294516  4404 ?   S    23:39   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0  apache  1376  0.0  0.1 294516  4144 ?   S    23:39   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0  apache  1419  0.0  0.1 294516  4144 ?   S    23:40   0:00 /usr/sbin/httpd -DFOREGROUND

アクセス拒否ログの確認

ausearch コマンドを使用するとSELinuxのポリシー違反を起こしたアクセスを確認できます。本手順ではRedmineにアクセスした際、これらのログが出力されないよう設定を行います。

以下の出力例ではhttpd_tドメインに対して許可されていないアクセスが拒否されています。(ログ出力のみ)

$ sudo ausearch -m avc | head -n 5
----
time->Mon Dec  4 22:48:24 2017
type=PROCTITLE msg=audit(1512395304.256:213): proctitle=50617373656E6765724167656E74007761746368646F6700202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020
type=SYSCALL msg=audit(1512395304.256:213): arch=c000003e syscall=1 success=yes exit=6 a0=4 a1=7f1fc9665000 a2=6 a3=22 items=0 ppid=9408 pid=9410 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="PassengerAgent" exe="/usr/local/lib/ruby/gems/2.4.0/gems/passenger-5.1.12/buildout/support-binaries/PassengerAgent" subj=system_u:system_r:httpd_t:s0 key=(null)
type=AVC msg=audit(1512395304.256:213): avc:  denied  { sys_resource } for  pid=9410 comm="PassengerAgent" capability=24  scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:system_r:httpd_t:s0 tclass=capability

SELinux設定の準備

SELinuxの設定を行うにあたり、設定に必要なツールをインストールします。

SELinux操作用各種ツールのインストール

以下のパッケージをインストールします。

$ sudo yum -y install policycoreutils-python setools-console selinux-policy-devel

よく使うコマンドとここでの役割

コマンド 説明
semanage デフォルトのFile Contextを設定する。または表示する
sesearch ドメインに許可されたアクセス情報を表示する
semodule 新しく定義したモジュールを追加する。または表示する
getsebool 定義されたBoolean値を表示する
setsebool 定義されたBoolean値を有効/無効に設定する
restorecon 特定のディレクトリまたはファイルに対して再ラベル付けを行う

SELinux設定の事前確認

設定の方針

  • Passengerをpassenger_tドメインで動作させる。

    • Redmineをhttpd_tのままで動作させる方法は対象外とする。
  • passenger_tが必要とするアクセスは基本的にディストリビューションによって容易されているポリシーを使用し、新規にラベルを作成したりモジュールを作成することは極力避ける。

    • やむを得ない場合はlocal moduleのようなものを作成する。
  • File Contextを設定する場合は、最小特権の観点から適切と思われるものを使用する。

    • 基本的にはPassenger moduleで提供されるラベルを使用するが最小特権の原則に沿わないものは使用しない。
    • そのような状況では、定義済みのPolicyの中から適切なものを使用する。

各ディレクトリの役割

説明がないディレクトリは読み取りのみが行われます。(ファーエンドテクノロジー提供情報)

現在、Redmineは /var/lib/redmine に配置されています。このディレクトリのFile Contextはそのまま var_lib_t を使用し、必要な権限がある場合のみFile Contextを変更します。
※一応、条件に合うFile Contextを設定しますが、Passenger module側で適切なFile Contextを定義した方が良いように見えます。

passenger_tのvar_lib_tに対するアクセス許可情報は以下の通りです。コマンド結果から分かる通り、 passenger_tのディレクトリに対するアクセス許可は定義がありますが、ファイルに対するアクセス許可は定義されていません。

$ sesearch -A -C -s passenger_t -t var_lib_t
Found 4 semantic av rules:
   allow domain base_file_type : dir { getattr search open } ;
   allow domain var_lib_t : dir { getattr search open } ;
   allow passenger_t var_lib_t : dir { getattr search open } ;
   allow nsswitch_domain var_lib_t : dir { ioctl read getattr lock search open } ;

ここで言う「比較的適切と考えられるFile Context」は現在のSELinux Passenger module (Version 1.1.1)の定義にある中で適切と思われるものを指定しています。

ディレクトリ 用途 比較的適切と考えられるFile Context
.bundle/ Ruby gem管理用 httpd_sys_content_t
.svn/ svnコマンドでRedmineを取得した場合に生成される passenger_var_lib_t
app/ Redmine本体 httpd_sys_content_t
bin/ Redmine本体 var_lib_t
config/ 設定ファイル httpd_sys_content_t
db/ データベース関係ファイル (データベースとしてSQLiteを使っているときのみ書き込みあり) passenger_var_lib_t
doc/ ドキュメント (本番運用時は参照されない) var_lib_t
extra/ Redmine本体 var_lib_t
files/ アップロードされた添付ファイルを格納 (書き込みあり) passenger_var_lib_t
lib/ Redmine本体 var_lib_t
log/ アプリケーションのログ (書き込みあり) passenger_log_t
plugins/ プラグインインストール用ディレクトリ httpd_sys_content_t
public/ 画像、CSSなど (plugin_assets/ に対して書き込みあり) httpd_sys_content_t , passenger_var_lib_t
script/ Redmine本体 httpd_sys_content_t
test/ テストコード。(本番運用時は参照されない) var_lib_t
tmp/ テンポラリ (書き込みあり) passenger_tmp_t
vendor/ Redmine本体 lib_t

SELinuxの設定

Passengerをpassenger_tドメインで動作させる

ApacheからPassengerが呼び出された際、passenger_tにドメイン遷移するようにFile Contextを定義します。

$ sudo semanage fcontext -a -s system_u -t passenger_exec_t -r s0 -f f "/usr/local/lib/ruby/gems(/.*)?/gems/passenger-(.*/)buildout/support-binaries/PassengerAgent"

Aapche Module(mod_passenger)のFile Contextを変更する

gemでインストールしているため、Apache module(mod_passenger.so)のFile Contextが意図しないものに設定されています。これをApache module用のFile Contextを設定します。

$ sudo semanage fcontext -a -s system_u -t httpd_modules_t -r s0 -f f "/usr/local/lib/ruby/gems(/.*)?/gems/passenger-(.*/)buildout/apache2/mod_passenger\.so"

passenger_tからRedmineにアクセスする設定を行う。

各ディレクトリとその配下のファイルに必要な権限

passenger_tが動作する際、アクセスが発生するディレクトリとその際必要になるアクセス権限は以下の通りです。必要となる権限には以下に示すディレクトリは配下に配置されたファイルに対するアクセスも含みます。(個別に定義しても良いですが大変だと思いますのでざっくりとです。)

ディレクトリ 必要となる主な権限
app
config read, getattr, ioctl, open
db
files write, create, unlink, など
lib
log append
plugins read
public
public/plugin_assets
tmp
vendor execute
.bundle open, ioctl
.svn lock, write
  • ここでは適切と考えられるFile Contextに以下を使用しています。
    • httpd_sys_content_t: read権限が必要となるディレクトリ
    • passenger_var_lib_t: read権限以外にwrite権限が必要になるディレクトリ
    • lib_t: execute権限が必要となるディレクトリ。再考の余地あり。

各ファイルに必要な権限

passenger_tが動作する際、アクセスが発生するファイルとそのファイルに対して設定する比較的適切と考えられるFile Contextは以下の通りです。

ファイル 比較的適切と考えられるFile Context
config.ru httpd_sys_content_t
Gemfile httpd_sys_content_t
Gemfile.lock httpd_sys_content_t
README httpd_sys_content_t

File Contextの設定

上記を元にFile Contextを定義します。

$ sudo semanage fcontext -a -s system_u -t httpd_sys_content_t -r s0 "/var/lib/redmine/\.bundle(/.*)?"
$ sudo semanage fcontext -a -s system_u -t passenger_var_lib_t -r s0 "/var/lib/redmine/\.svn(/.*)?"
$ sudo semanage fcontext -a -s system_u -t httpd_sys_content_t -r s0 "/var/lib/redmine/app(/.*)?"
$ sudo semanage fcontext -a -s system_u -t httpd_sys_content_t -r s0 "/var/lib/redmine/config(/.*)?"
$ sudo semanage fcontext -a -s system_u -t passenger_var_lib_t -r s0 "/var/lib/redmine/db(/.*)?"
$ sudo semanage fcontext -a -s system_u -t passenger_var_lib_t -r s0 "/var/lib/redmine/files(/.*)?"
$ sudo semanage fcontext -a -s system_u -t passenger_var_lib_t -r s0 "/var/lib/redmine/lib(/.*)?"
$ sudo semanage fcontext -a -s system_u -t passenger_log_t -r s0 "/var/lib/redmine/log(/.*)?"
$ sudo semanage fcontext -a -s system_u -t httpd_sys_content_t -r s0 "/var/lib/redmine/plugins(/.*)?"
$ sudo semanage fcontext -a -s system_u -t httpd_sys_content_t -r s0 "/var/lib/redmine/public(/.*)?"
$ sudo semanage fcontext -a -s system_u -t passenger_var_lib_t -r s0 "/var/lib/redmine/public/plugin_assets(/.*)?"
$ sudo semanage fcontext -a -s system_u -t passenger_tmp_t -r s0 "/var/lib/redmine/tmp(/.*)?"
$ sudo semanage fcontext -a -s system_u -t lib_t -r s0 "/var/lib/redmine/vendor(/.*)?"

$ sudo semanage fcontext -a -s system_u -t httpd_sys_content_t -r s0 -f f "/var/lib/redmine/config\.ru"
$ sudo semanage fcontext -a -s system_u -t httpd_sys_content_t -r s0 -f f "/var/lib/redmine/Gemfile"
$ sudo semanage fcontext -a -s system_u -t httpd_sys_content_t -r s0 -f f "/var/lib/redmine/Gemfile\.lock"

再ラベル付け

semanage コマンドで定義したFile Contextを再ラベル付けをし、適用します。ここではfixfiles コマンドは使用せず、restorecon コマンドを使用し、オンラインで再ラベル付けを行います。

$ sudo restorecon -RF /var/lib/redmine /usr/local/lib/ruby/gems
$ sudo ls -Zl /var/lib/redmine/
total 36
drwxr-xr-x.  6 system_u:object_r:httpd_sys_content_t:s0 apache apache   67 Dec  5 00:37 app
-rw-r--r--.  1 system_u:object_r:var_lib_t:s0   apache apache  860 Dec  5 00:38 appveyor.yml
drwxr-xr-x.  2 system_u:object_r:var_lib_t:s0   apache apache   58 Dec  5 00:38 bin
drwxr-xr-x.  5 system_u:object_r:httpd_sys_content_t:s0 apache apache 4096 Dec  8 02:55 config
-rw-r--r--.  1 system_u:object_r:httpd_sys_content_t:s0 apache apache  160 Dec  5 00:38 config.ru
-rw-r--r--.  1 system_u:object_r:var_lib_t:s0   apache apache  241 Dec  5 00:38 CONTRIBUTING.md
drwxr-xr-x.  3 system_u:object_r:passenger_var_lib_t:s0 apache apache   38 Dec  5 00:45 db
drwxr-xr-x.  2 system_u:object_r:var_lib_t:s0   apache apache  113 Dec  5 00:38 doc
drwxr-xr-x.  5 system_u:object_r:var_lib_t:s0   apache apache   58 Dec  5 00:38 extra
drwxr-xr-x.  3 system_u:object_r:passenger_var_lib_t:s0 apache apache   35 Dec  8 02:57 files
-rw-r--r--.  1 system_u:object_r:httpd_sys_content_t:s0 apache apache 3622 Dec  5 00:38 Gemfile
-rw-r--r--.  1 system_u:object_r:httpd_sys_content_t:s0 apache apache 4864 Dec  5 00:44 Gemfile.lock
drwxr-xr-x.  7 system_u:object_r:passenger_var_lib_t:s0 apache apache  111 Dec  5 00:38 lib
drwxr-xr-x.  2 system_u:object_r:passenger_log_t:s0 apache apache   45 Dec  5 00:45 log
drwxr-xr-x.  2 system_u:object_r:httpd_sys_content_t:s0 apache apache   20 Dec  5 00:38 plugins
drwxr-xr-x.  8 system_u:object_r:httpd_sys_content_t:s0 apache apache  214 Dec  5 00:38 public
-rw-r--r--.  1 system_u:object_r:var_lib_t:s0   apache apache  275 Dec  5 00:38 Rakefile
-rw-r--r--.  1 system_u:object_r:var_lib_t:s0   apache apache  205 Dec  5 00:38 README.rdoc
drwxr-xr-x.  2 system_u:object_r:var_lib_t:s0   apache apache   32 Dec  5 00:38 script
drwxr-xr-x. 10 system_u:object_r:var_lib_t:s0   apache apache  170 Dec  5 00:37 test
drwxr-xr-x.  9 system_u:object_r:passenger_tmp_t:s0 apache apache  106 Dec  5 00:38 tmp
drwxr-xr-x.  3 system_u:object_r:lib_t:s0       apache apache   20 Dec  5 00:42 vendor

sysfsへのアクセスを許可する

Passengerは起動時、/sys/devices/system/cpu にアクセスします。以下はaudit.logを抜粋したものです。
※何かは不明です。どうしてか理由を知っている人は教えてください。

$ sudo grep sysfs /var/log/audit/audit.log
type=AVC msg=audit(1512722470.559:351): avc:  denied  { read } for  pid=3556 comm="ruby" name="cpu" dev="sysfs" ino=37 scontext=system_u:system_r:passenger_t:s0 tcontext=system_u:object_r:sysfs_t:s0 tclass=dir```

これを許可するため、redmine_localモジュールを作成します。

$ mkdir ~/redmine
$ cd ~/redmine
$ cat > ~/redmine/redmine_local.te << _EOF_
module redmine_local 1.0;

require {
        type passenger_t;
        type sysfs_t;
        class dir read;
}

allow passenger_t sysfs_t:dir read;
_EOF_

$ make -f /usr/share/selinux/devel/Makefile
$ sudo semodule -i redmine_local.pp
$ sudo semodule -l | grep redmine_local
redmine_local   1.0

上記に加えメール送信をするためのアクセスを許可する

メール送信機能を使用する場合は上記Policyに加えて、メールが送信できるように以下のPolicyを使用します。
※なぜかpassenger_tからcert9.db, nssdbに対して書き込みが発生します。どうしてか理由を知っている人は教えてください。
※メール送信の際、httpd_can_sendmail相当のBoolean値を有効にする必要がありますが、Passenger moduleには存在しないため、代わりにBoolean値nis_enableを有効にします。

$ mkdir ~/redmine
$ cd ~/redmine
$ cat > ~/redmine/redmine_local.te << _EOF_
module redmine_local 1.0;

require {
        type passenger_t;
        type sysfs_t;
        type cert_t;
        class file write;
        class dir { read write };
}

allow passenger_t cert_t:dir write;
allow passenger_t cert_t:file write;
allow passenger_t sysfs_t:dir read;
_EOF_

$ make -f /usr/share/selinux/devel/Makefile
$ sudo semodule -i redmine_local.pp
$ sudo semodule -l | grep redmine_local
redmine_local   1.0

$ sudo setsebool -P nis_enabled 1

組み込んだmoduleは以下のコマンドで取り除くことができます。不要になった場合は適宜削除ください。

$ sudo semodule -r redmine_local

Apacheを再起動する

Apacheを再起動し、PassengerAgentがpassenger_tドメインで動作していることを確認します。

$ sudo systemctl restart httpd.service
$ ps axuZ | grep -e [P]ass -e [h]ttpd

SELinuxを有効にする

OS起動時のSELinuxのモードをEnforcingモードに変更します。

$ sudo sed -i "s/\(^SELINUX=\).*/\1enforcing/" /etc/selinux/config

SELinuxの状態を確認します。

$ sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   enforcing  ← 現在のモードがEnforcingモードになっていることを確認する
Mode from config file:          enforcing  ← 設定ファイル上の設定がEnforcingモードになっていることを確認する
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Max kernel policy version:      28

おわりに

以上でSELinuxの設定は完了です。ここでは、以下のアクセスについてのみ確認しています。

  • Apache起動時の
  • Redmineへのアクセス
  • Redmineへのログイン
  • プロジェクトの作成
  • チケットの作成(ファイル付き)
  • チケット作成・更新時のメール送付
  • Plugin(Redmine view customize plugin)の簡単な動作確認

これら以外のアクセスについては確認を行っていないため、処理が拒否される場合があります。その場合は ausearch コマンドなどを利用し、適切なFile Contextを設定する必要があります。

Appendix

SELinuxについての情報は以下をご覧ください。

以上

作成: 2018-01-12 10:00  •  分類: ,