Skip to content

食わず嫌いのSELinux

2016/9/19

SELinuxはdisableにするもの、そう考えている人が一般的に多いらしい。

SELinuxについて調べる機会が有り、調べてみたところ、実は食わず嫌いなだけで、使うだけであればそこまで難しく無いものだと感じた。

せっかくなのでそのまとめ。

SELinuxとは?

DACの仕組みだけに頼らない、セキュリティをより強固にしたもの。
(DACはユーザごとにファイルとかに対してrwxを与える仕組みのこと)

DAC→SELinuxという順番でチェックされるため、DACで弾かれるとSELinuxのチェックは働かない。

動きを簡単にまとめると、

  • プロセスやファイルごとにSELinuxコンテキストというラベルみたいなのが設定されている
  • そのプロセスに設定されているラベルがファイルやディレクトリに設定されているラベルに対して、読み取りだけとか書き込みもOKとか許可するルールを設定していく

SELinuxの設定値を見るコマンド

ファイルのSELinuxコンテキストを表示する

カレントディレクトリにあるファイル一覧に対して、表示する例。

# ls -Z
-rw-------. root root          system_u:object_r:admin_home_t:s0 anaconda-ks.cfg
-rw-r--r--. apache apache system_u:object_r:httpd_sys_rw_content_t:s0 avatar.png

※ファイルではなくディレクトリに対して確認したい場合は-dオプションも必要

プロセスのSELinuxコンテキストを表示する

# ps -eZ
system_u:system_r:httpd_t:s0     1223 ?        00:01:34 httpd

ユーザのSELinuxコンテキストを表示する

# id -Z
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

コンテキストの見方は以下の通り。

SELinuxユーザ:ロール  :タイプ      :レベル
system_u     :object_r:admin_home_t:s0

コンテキストに設定されているアクセス制御を確認する

sesearchを用いる。
setools-consoleパッケージに含まれているツールとなる。

httpd_t が httpd_sys_content_tに対しての権限設定を表示する例。
※httpd_tはプロセスのコンテキスト、httpd_sys_content_tはファイル等コンテンツに対するのコンテキスト

# sesearch -A -C -s httpd_t -t httpd_sys_content_t
Found 15 semantic av rules:
   allow httpd_t file_type : filesystem getattr ; 
   allow httpd_t file_type : dir { getattr search open } ; 
   allow httpd_t httpd_sys_content_t : file { ioctl read getattr lock open } ; 
   allow httpd_t httpd_sys_content_t : dir { ioctl read getattr lock search open } ; 
   allow httpd_t httpd_sys_content_t : lnk_file { read getattr } ; 
   allow httpd_t httpd_content_type : file { ioctl read getattr lock open } ; 
   allow httpd_t httpd_content_type : dir { getattr search open } ; 
   allow daemon httpd_sys_content_t : dir { getattr search open } ; 
ET allow httpd_t httpd_sys_content_t : dir { ioctl read write getattr lock add_name remove_name search open } ; [ httpd_enable_cgi httpd_unified && httpd_builtin_scripting && ]
ET allow httpd_t httpd_content_type : file { ioctl read getattr lock open } ; [ httpd_builtin_scripting ]
ET allow httpd_t httpd_content_type : dir { ioctl read getattr lock search open } ; [ httpd_builtin_scripting ]
ET allow httpd_t httpd_content_type : lnk_file { read getattr } ; [ httpd_builtin_scripting ]
ET allow httpd_t httpdcontent : file { ioctl read write create getattr setattr lock append unlink link rename execute open } ; [ httpd_enable_cgi httpd_unified && httpd_builtin_scripting && ]
ET allow httpd_t httpdcontent : dir { ioctl read write create getattr setattr lock unlink link rename add_name remove_name reparent search rmdir open } ; [ httpd_enable_cgi httpd_unified && httpd_builtin_scripting && ]
ET allow httpd_t httpdcontent : lnk_file { ioctl read write create getattr setattr lock append unlink link rename } ; [ httpd_enable_cgi httpd_unified && httpd_builtin_scripting && ]

コマンドのオプション

-A, --allow Search for allow rules.
-C          Print the conditional expression and state for all conditional rules found. 
                 This option has no effect on unconditional rules.
                 (ブール値による設定値の表示を行う。[ ]で囲まれた部分がブール値の設定を表している。)
-s , --source   :Find rules with type/attribute NAME as their source.
-t , --target   :Find rules with type/attribute NAME as their 
target.

よく使われるhttpdについての例(apacheもnginxもプロセスはともにhttpd_t)

httpd_sys_content_t : httpdプロセスが"読み取り"のみ可。書き込みは不可。  
httpd_sys_rw_content_t : 読み書き可
httpd_sys_script_exec_t : スクリプト実行可

httpdプロセスがReadするだけのファイルであれば、httpd_sys_content_tを設定してあげれば良い。


コンテキストの変更

一時的な設定変更

一時的にコンテキストを変更する。
[filename]にhttpd_sys_content_tを設定する例。

# chcon -t httpd_sys_content_t [filename]

コンテキストに設定されているアクセス制御を確認する で確認した通り、allow httpd_t httpd_sys_content_tという設定が以下の通り存在する。

allow httpd_t httpd_sys_content_t : file { ioctl read getattr lock open } ; 
allow httpd_t httpd_sys_content_t : dir { ioctl read getattr lock search open } ; 
allow httpd_t httpd_sys_content_t : lnk_file { read getattr } ; 

つまり、今回設定した[filename]のファイルに対して、httpd_tのプロセス(のコンテキスト)がReadする権限をつけたということになる。

オプション

-t  :ターゲットを指定
-R :ディレクトリを指定する場合

一時的な設定のため、設定した内容を元に戻すことができる。
(永続的に設定されている管理情報を元に、設定に戻す)

# restorecon -v [filename]

オプション

-v : 詳細表示

永続的な設定変更

永続的にコンテキスト変更する。
semanage コマンドを用いる。
semanageはpolicycoreutils-pythonパッケージに含まれている。

# semanage fcontext -a -t httpd_sys_content_t [filename]

オプション

-a : コンテキスト追加
-t : ターゲット

実行例

# semanage fcontext -a -t httpd_sys_content_t /home/hoge/test.txt

★[filename]部分は絶対パスじゃないとダメなので注意。
理由としては、今回のコマンドはファイルそのものに設定されるのではなく、下記に登場する"コンテキスト管理ファイル"に設定画記録されるため、絶対パスで記録する必要があるため。

実行すると、以下の場所に設定が書き込まれる
/etc/selinux/targeted/contexts/files/

上記ディレクトリにてgrepで何処に設定が書かれたか調べてみる。

# grep test.txt *
file_contexts.local:/home/hoge/test.txt    system_u:object_r:httpd_sys_content_t:s0

test.txtに対して、設定されている事がわかる。

1つのファイルだけではなく、特定のディレクトリとその配下のファイルをまるごと設定したい場合は正規表現を用いる。

# semanage fcontext -a -t httpd_sys_content_t "/home/hoge/testdir(/.*)?"

コンテキスト管理ファイルも正規表現で記録されていることがわかる。

# grep testdir *
file_contexts.local:/home/hoge/testdir(/.*)?    system_u:object_r:httpd_sys_content_t:s0

コンテキストを適用する

永続的な設定変更 を実施後、以下のコマンドで適用する。

# restorecon -v [filename]

オプション

-v : 詳細表示
-R : 再帰的に実行(ディレクトリを指定して、その配下まるごと適用する場合等)

永続的な設定から、適用までの実行例

## 永続設定
# semanage fcontext -a -t httpd_sys_content_t /home/hoge/test.txt

## 確認。この時点だと適用されていない。
# ls -Z test.txt 
-rw-r--r--. root root unconfined_u:object_r:user_home_t:s0 test.txt

## 適用
# restorecon -v test.txt
restorecon reset /home/hoge/test.txt context unconfined_u:object_r:user_home_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0

## 再確認。適用されていることがわかる。
# ls -Z test.txt 
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 test.txt
## 複数ファイルを永続設定
# semanage fcontext -a -t httpd_sys_content_t "/home/hoge/testdir(/.*)?"

## 複数ファイルにまとめて適用
# restorecon -R -v /home/hoge/testdir
restorecon reset /home/hoge/testdir context unconfined_u:object_r:user_home_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
restorecon reset /home/hoge/testdir/aaa.txt context unconfined_u:object_r:user_home_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
restorecon reset /home/hoge/testdir/bbb.txt context unconfined_u:object_r:user_home_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0

コンテキストを削除する

消す場合は -d オプションを用いる。

# semanage fcontext -d "/home/hoge/testdir(/.*)?"

# restorecon -R -v /home/hoge/testdir
restorecon reset /home/hoge/testdir context unconfined_u:object_r:httpd_sys_content_t:s0->unconfined_u:object_r:user_home_t:s0
restorecon reset /home/hoge/testdir/aaa.txt context unconfined_u:object_r:httpd_sys_content_t:s0->unconfined_u:object_r:user_home_t:s0
restorecon reset /home/hoge/testdir/bbb.txt context unconfined_u:object_r:httpd_sys_content_t:s0->unconfined_u:object_r:user_home_t:s0

# ls -lZR
drwxr-xr-x. root root unconfined_u:object_r:user_home_t:s0 testdir
./testdir:
-rw-r--r--. root root unconfined_u:object_r:user_home_t:s0 aaa.txt
-rw-r--r--. root root unconfined_u:object_r:user_home_t:s0 bbb.txt

通信ポートの設定

SELinuxではネットワークの使用するポートも管理されている。
一般的なwell knownポートの場合は許可が設定済みとなっているが、ポート番号を独自のものに変えた場合、設定変更が必要となる。

設定一覧表示

設定されてるポート表示

# semanage port -l
http_port_t    tcp      80, 81, 443, 488, 8008, 8009, 8443, 9000

ポート設定追加(tcp/12345を追加)

# semanage port -a -t http_port_t -p tcp 12345

ポート設定削除

# semanage port -d -t http_port_t -p tcp 12345

ファイルシステム

ファイルシステムをマウントするときもSELinuxのコンテキストを指定することができる。
SambaとかでNFS使う場合に便利だと思う。

mountコマンド実行時に指定

# mount sever:/export /local/mountpoint -o context="system_u:object_r:httpd_sys_content_t:s0"

-o オプションと、context= でコンテキストを設定する。

/etc/fstab に記述することで永続化される。

sever:/export /local/mountpoint nfs context="system_u:object_r:httpd_sys_content_t:s0" 0 0

パッケージに対してまとめて設定

特定のパッケージに対して、一つ一つ細かくSELinuxの設定を入れなくても、まるごと必要な権限をまるごと設定してくれる仕組みが用意されている。
httpdやftpd等、有名なパッケージだと、大体用意されている。
semanage というコマンドを用いる。

一覧表示

# semanage boolean -l
SELinux boolean                状態       初期値  説明
httpd_can_network_connect_db   (オン   ,   オン)  Allow httpd to can network connect db
ftpd_use_cifs                  (オフ   ,   オフ)  Allow ftpd to use cifs

httpdパッケージに対して設定する。
httpdが(ネットワーク越しに)DBサーバに接続する権限を与える。

# setsebool -P httpd_can_network_connect_db on

オプション

-P : 永続設定(これをつけないと再起動時に設定が変更前に戻る)

設定後、onかoffか確認する

# getsebool httpd_can_network_connect_db
httpd_can_network_connect_db --> on

auditログを用いた設定

SELinuxは/var/log/audit/audit.log に色々とログが残る。
ログの中身としては、権限不足で拒否された内容などが残っている。
audit.logを元に許可ルール(ポリシーパッケージ)を作成することができる。
基本的にはこちらの機能を使ったほうが楽で確実なのでおすすめ。

auditログの確認

audit2allowコマンドを用いて、audit.logについて、人が読みやすいようにログを変換する。

# audit2allow -a
#============= httpd_t ==============
#!!!! This avc can be allowed using one of the these booleans:

#     nis_enabled, httpd_can_network_relay, httpd_can_connect_ftp, httpd_can_network_connect
allow httpd_t ftp_port_t:tcp_socket name_connect;

#!!!! This avc can be allowed using one of the these booleans:
#     httpd_can_network_relay, httpd_can_network_connect
allow httpd_t http_cache_port_t:tcp_socket name_connect;

#!!!! This avc can be allowed using the boolean 'httpd_unified'
allow httpd_t httpd_sys_content_t:dir { write remove_name create add_name setattr };

#!!!! This avc can be allowed using the boolean 'httpd_unified'
allow httpd_t httpd_sys_content_t:file { write create unlink setattr };
allow httpd_t postfix_etc_t:file read;

ポリシーパッケージの生成

-M オプションを用いて、ログ情報から拒否されたものに対して、許可ルールを作成する。
今回の場合、生成するファイルには"test"と名前をつける。

# audit2allow -a -M test
******************** IMPORTANT ***********************
To make this policy package active, execute:

semodule -i test.pp

コマンド結果から、test.ppと test.teが作成される

.pp: ポリシーパッケージ
.te: タイプエンフォースメントファイル

なお、タイプエンフォースメントファイル(.te)のルールをコンパイルすることでポリシーパッケージ(.pp)が作成されている。

.teの中身は以下の通り

# cat test.te 
module test 1.0;
require {
    type postfix_etc_t;
    type httpd_t;
    type ftp_port_t;
    type httpd_sys_content_t;
    type http_cache_port_t;
    class tcp_socket name_connect;
    class dir { write remove_name create add_name setattr };
    class file { read write create unlink setattr };
}

#============= httpd_t ==============
#!!!! This avc can be allowed using one of the these booleans:

#     nis_enabled, httpd_can_network_relay, httpd_can_connect_ftp, httpd_can_network_connect
allow httpd_t ftp_port_t:tcp_socket name_connect;

#!!!! This avc can be allowed using one of the these booleans:
#     httpd_can_network_relay, httpd_can_network_connect
allow httpd_t http_cache_port_t:tcp_socket name_connect;

#!!!! This avc can be allowed using the boolean 'httpd_unified'
allow httpd_t httpd_sys_content_t:dir { write remove_name create add_name setattr };

#!!!! This avc can be allowed using the boolean 'httpd_unified'
allow httpd_t httpd_sys_content_t:file { write create unlink setattr };
allow httpd_t postfix_etc_t:file read;

ポリシーパッケージの適用

上記で生成したポリシーパッケージについて、以下のコマンドで適用できる。
.teではなく.ppを指定すること。

# semodule -i test.pp

特定のルールのみを適用したい場合

ログでは権限不足で拒否されたものが複数記録されることがある。
上記のコマンド例では、全ての拒否記録に対して、許可を与えることになってしまう。
test.te の内容から、httpd,postfix,ftp の設定が含まれていることがわかる。
特定のルールのみを作りたい場合はgrepを使う。

httpdのみを指定したい場合。

# grep httpd /var/log/audit/audit.log | audit2allow -a
→httpdのみのログが表示される(省略)

# grep httpd /var/log/audit/audit.log | audit2allow -a -M httpd_pol
→httpdのみの許可ルールが生成される

これでまた、.pp, .teのファイルが生成される。

.teの中身を確認するとhttpdに関する内容となっていることがわかる。

# cat httpd_pol.te 
module httpd_pol 1.0;
require {
    type httpd_t;
    type httpd_sys_content_t;
    class dir { write remove_name add_name };
    class file { write create unlink setattr };
}

#============= httpd_t ==============
#!!!! This avc can be allowed using the boolean 'httpd_unified'
allow httpd_t httpd_sys_content_t:dir { write remove_name add_name };

#!!!! This avc can be allowed using the boolean 'httpd_unified'
allow httpd_t httpd_sys_content_t:file { write create unlink setattr };

あとはsemoduleのコマンドを実行し、適用してあげれば良い。

# semodule -i httpd_pol.pp

【参考】
SELinux ユーザーおよび管理者のガイド
アクセスの許可: audit2allow