コマンドラインでちょっとSELinux

SELinux、使っていますか?

設定がわかりづらい、難しい等のイメージから敬遠されがちなSELinux。自前で一からポリシーを作成したりしようとすれば確かに難しい部分もあるのですが、ディストリビューションに元々含まれているポリシーをもとにちょっと設定を変更する程度なら簡単にできてしまうこともあります。

ここでは、そんなちょっとの設定変更に用いるコマンドの使用方法の一部を簡単に紹介します。

この内容はCentOS6の環境で確認を行い記述しています。ポリシーセットはデフォルトであるtargetedの使用を前提にしており、またサーバープログラムを動作させるための設定方法の紹介を主な目的としているため、マルチレベルセキュリティ(MLS)やマルチカテゴリーセキュリティ(MCS)、ロールベースのアクセスコントロール(RBAC)等には触れないものとします。

以下、プロンプトを#で表記しているコマンド行の実行には管理者権限が必要です。スーパーユーザーで実行するかsudoコマンド等を用いてください。

SELinuxの概念

SELinuxは、実行プロセスにドメインというものを割り当て、それぞれのドメインがある対象(ファイルやネットワークのポートなど)に対してどのような操作が出来るかを制限します。

明示的に許可されていない操作はSELinuxにより実行が拒否されるので、例えばあるプログラムにroot権限で任意のコマンドを実行できるようなセキュリティホールがあったとしても、被害の拡大をそのドメインに許可されている範囲内に止めることができることになります。

状態の確認

SELinuxが導入された環境では各種基本コマンドが拡張され、SELinux関連の情報を確認できるようになっています。

ドメイン

psコマンドにZオプションをつけて実行することにより、各プロセスがどのようなドメインとして実行されているかを確認することができます。

例としてApache HTTPサーバーが動作する環境でコマンドを実行してみます。

$ ps -eZ | grep httpd
unconfined_u:system_r:httpd_t:s0 42038 ?       00:00:00 httpd
unconfined_u:system_r:httpd_t:s0 46507 ?       00:00:15 httpd
unconfined_u:system_r:httpd_t:s0 46508 ?       00:00:14 httpd
unconfined_u:system_r:httpd_t:s0 46509 ?       00:00:15 httpd
unconfined_u:system_r:httpd_t:s0 46510 ?       00:00:13 httpd

末尾に_tのついたものがドメインで、この場合は各httpdのプロセスがhttpd_tドメインとして実行されていることがわかります。末尾が_u,_rの項目及びs0の表示についてはここでは解説しません。なお、コロンで連結された(この例ではunconfined_uからs0までの)文字列全体で表現されているものをセキュリティコンテキストと呼びます。

ファイル

各ファイルについては、それぞれがどのような種類のファイルであるかを表すタイプというものが割り当てられますが、lsコマンドにZオプションをつけて実行することにより、このタイプを確認できます。

Apache HTTPサーバーのデフォルトのドキュメントルートである/var/www/htmlディレクトリについて確認してみます。

$ ls -dZ /var/www/html/
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html/

httpd_sys_content_tというものが、/var/www/html/に割り当てられているタイプということになります。

デフォルトのポリシーでは、httpd_tドメインとして実行されるプロセスがhttpd_sys_content_tというタイプの対象を読み取ることを許可しているため、このタイプのディレクトリやファイルの内容をApache HTTPサーバーが読み取ってクライアントに返すことができることになります。

ポート

ファイルと同様、ネットワークのポートにもタイプが割り当てられており、どのドメインがどのポートを使用できるかを設定できるようになっています。netstatコマンドにもZオプションが追加され、ポートを使用しているプロセスのセキュリティコンテキストを確認できるようになっています。

管理用コマンドの準備

ここからは実際の設定例と共に各コマンドを紹介していきますが、その前にSELinuxの管理に用いるコマンドの存在を確認しておきます。(ここではsemanageコマンドについて確認)

$ whereis semanage
semanage: /usr/sbin/semanage /usr/share/man/man8/semanage.8.gz

手元のCentOS6の環境では/usr/sbin/にsemanageコマンドがインストールされています。見つからなければパッケージのインストールを行いますが、環境によってパッケージが異なる場合がありますので、yumのprovidesコマンドを使用して対象コマンドが含まれるパッケージを確認してからインストールします。

$ yum provides *bin/semanage
Loaded plugins: downloadonly, fastestmirror, priorities
base                                                               | 3.7 kB     00:00
extras                                                             | 3.0 kB     00:00
updates                                                            | 3.5 kB     00:00
extras/filelists_db                                                |  738 B     00:00
policycoreutils-python-2.0.83-19.1.el6.x86_64 : SELinux policy core python utilities
Repo        : base
Matched from:
Filename    : /usr/sbin/semanage

policycoreutils-python-2.0.83-19.8.el6_0.x86_64 : SELinux policy core python utilities
Repo        : updates
Matched from:
Filename    : /usr/sbin/semanage

CentOS6ではpolicycoreutils-pythonパッケージに含まれるようですので、それをインストールします。

# yum install policycoreutils-python

以降、コマンド群が/sbin/または/use/sbin/のパスに存在するものとして記述しますが、環境により異なる可能性もありますので必要に応じて読み替えてください。

コマンドの使用例と簡単な解説

Apache HTTPサーバーでの設定を例に挙げ、各コマンドの使用方法を簡単に解説していきます。なお、Apache自体の設定については詳しく解説しませんので、他のサイトの情報等を参照してください。

ドキュメントルートの変更

Apache HTTPサーバーでのドキュメントルートはデフォルトで/var/www/html/等に設定されていますが、これを変更したり別の場所にあるコンテンツを公開したい場合もあると思いますので、その設定を行ってみます。

まずは、新しいドキュメントルートとなるディレクトリ(ここでは/var/htdocs/とする)を作成し、Apacheの設定ファイル(CentOS6では/etc/httpd/conf/httpd.conf)のDocumentRoot及びそれに関連するディレクティブを新しいディレクトリを指すように変更し、Apacheを再起動します。

その後、新しいディレクトリに適当なファイル(ここではindex.html)を作成しブラウザでアクセスしようとすると、403エラー等でアクセスできません。この時、SELinuxのログ(CentOS6では/var/log/audit/audit.log)に次のような内容が出力されているはずです。

type=AVC msg=audit(1319475486.021:40867): avc:  denied  { getattr }
 for  pid=3824 comm="httpd" path="/var/htdocs/index.html" dev=dm-0
 ino=1970365 scontext=unconfined_u:system_r:httpd_t:s0
 tcontext=unconfined_u:object_r:var_t:s0 tclass=file

出力内容についての説明は省きますが、これはhttpd_tドメインとして実行されているプロセスがvar_tというタイプのファイルである/var/htdocs/index.htmlにアクセスしようとして拒否されたことを表します。

http_tドメインには、タイプがhttpd_sys_content_tであるファイルやディレクトリについての読み取りは許可されていますが、var_tというタイプに対しては許可されていません。そこで、新しく作成したディレクトリである/var/htdocs/にもhttpd_sys_content_tというタイプを割り当てることにします。

その前に、デフォルトのポリシーではどのようにhttpd_sys_content_tのタイプを割り当てているのかを確認してみましょう。

# /usr/sbin/semanage fcontext -l | grep httpd_sys_content_t
/etc/htdig(/.*)?                                   all files          system_u:object_r:httpd_sys_content_t:s0
/srv/([^/]*/)?www(/.*)?                            all files          system_u:object_r:httpd_sys_content_t:s0
/srv/gallery2(/.*)?                                all files          system_u:object_r:httpd_sys_content_t:s0
/usr/share/drupal(/.*)?                            all files          system_u:object_r:httpd_sys_content_t:s0
/usr/share/htdig(/.*)?                             all files          system_u:object_r:httpd_sys_content_t:s0
/usr/share/icecast(/.*)?                           all files          system_u:object_r:httpd_sys_content_t:s0
/usr/share/mythtv/data(/.*)?                       all files          system_u:object_r:httpd_sys_content_t:s0
/usr/share/mythweb(/.*)?                           all files          system_u:object_r:httpd_sys_content_t:s0
/usr/share/ntop/html(/.*)?                         all files          system_u:object_r:httpd_sys_content_t:s0
/usr/share/openca/htdocs(/.*)?                     all files          system_u:object_r:httpd_sys_content_t:s0
/usr/share/selinux-policy[^/]*/html(/.*)?          all files          system_u:object_r:httpd_sys_content_t:s0
/var/lib/cacti/rra(/.*)?                           all files          system_u:object_r:httpd_sys_content_t:s0
/var/lib/htdig(/.*)?                               all files          system_u:object_r:httpd_sys_content_t:s0
/var/www(/.*)?                                     all files          system_u:object_r:httpd_sys_content_t:s0
/var/www/icons(/.*)?                               all files          system_u:object_r:httpd_sys_content_t:s0
/var/www/svn/conf(/.*)?                            all files          system_u:object_r:httpd_sys_content_t:s0

semanageコマンドにfcontextをつけて実行すると、どのファイルにどのようなタイプ(ファイル・コンテキスト)を割り当てるかの定義情報の操作を行うことができ、-lオプションは全ての定義情報を一覧表示することを表します。

ここで、/var/www(/.*)?で始まる行がありますが、これは/var/www以下の全てのディレクトリとファイルに対して指定したタイプを設定することを意味します。では、これを参考にして/var/htdocs/ディレクトリにも同様の設定をしてみることにしましょう。

# /usr/sbin/semanage fcontext -a -t httpd_sys_content_t "/var/htdocs(/.*)?"

-aオプションは設定の追加、-tオプションは設定するタイプを意味します。設定が正しく追加されたことを確認するために次のコマンドを実行します。

# /usr/sbin/semanage fcontext -lC
SELinux fcontext                                   タイプ                コンテキスト

/var/htdocs(/.*)?                                  all files          system_u:object_r:httpd_sys_content_t:s0

大文字のCをオプションとして追加指定することで、デフォルトのポリシーに存在しない、追加された定義情報のみを表示することができます。

また、次のようにして、設定情報を削除することもできます。

# /usr/sbin/semanage fcontext -d "/var/htdocs(/.*)?"

なお、ここまでの操作はルールを追加しただけで、実際にファイルにタイプが設定されるわけではありません。lsコマンドで確認すると、未だにディレクトリのタイプが変更されていないことがわかります。

$ ls -dZ /var/htdocs/
drwxr-xr-x. root root unconfined_u:object_r:var_t:s0   /var/htdocs/

ルールに従って実際にファイルへのタイプ設定を行うには、restoreconコマンドを実行します。

# /sbin/restorecon -R /var/htdocs/

-Rは指定したディレクトリ以下を再帰的に処理するためのオプションです。再度確認すると、タイプ設定がファイルに反映されていることがわかります。

$ ls -dZ /var/htdocs/
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 /var/htdocs/

この状態で先ほどと同様にindex.htmlへアクセスし、拒否されずに内容が表示されることを確認します。

なお、次のようにしてファイルタイプを直接変更することもできますが、restoreconコマンド等でタイプ付けが行われると変更前のタイプに戻ってしまいますので、一時的に動作を確認したい時等、状況に応じて使い分けると良いかも知れません。

# chcon -R -t httpd_sys_content_t /var/htdocs/

リスニングポートの変更

次は、リスニングポートをデフォルトの80番から変更する場合です。ここでは、30080番を使用するようにApacheの設定を変更し、再起動してみます。

# service httpd restart
httpd を停止中:                                            [  OK  ]
httpd を起動中: (13)Permission denied: make_sock: could not bind to address [::]:30080
(13)Permission denied: make_sock: could not bind to address 0.0.0.0:30080
no listening sockets available, shutting down
Unable to open logs
                                                           [失敗]

起動に失敗してしまいました。また、SELinuxのログには次のような内容が出力されます。

type=AVC msg=audit(1319481469.991:41047): avc:  denied  { name_bind } for  pid=4325 comm="httpd" src=30080 scontext=unconfined_u:sys
tem_r:httpd_t:s0 tcontext=system_u:object_r:port_t:s0 tclass=tcp_socket

port_tというのは、明示的にタイプが設定されていないポートを表すタイプです。ここで、元々の80番ポートにはどのようなタイプが設定されているのかを確認してみます。

# /usr/sbin/semanage port -l | grep 80
amanda_port_t                  tcp      10080-10083
amanda_port_t                  udp      10080-10082
cyphesis_port_t                tcp      6767, 6769, 6780-6799
hplip_port_t                   tcp      1782, 2207, 2208, 8290, 50000, 50002, 8292, 9100, 9101, 9102, 9220, 9221, 9222, 9280, 9281, 9282, 9290, 9291, 9292
http_cache_port_t              tcp      3128, 8080, 8118, 10001-10010
http_port_t                    tcp      80, 443, 488, 8008, 8009, 8443
luci_port_t                    tcp      8084
ocsp_port_t                    tcp      9080
pki_ca_port_t                  tcp      9180, 9701, 9443, 9444, 9445
pki_kra_port_t                 tcp      10180, 10701, 10443, 10444, 10445
pki_ocsp_port_t                tcp      11180, 11701, 11443, 11444, 11445
pki_tks_port_t                 tcp      13180, 13701, 13443, 13444, 13445
soundd_port_t                  tcp      8000, 9433, 16001
speech_port_t                  tcp      8036
transproxy_port_t              tcp      8081
xen_port_t                     tcp      8002
zope_port_t                    tcp      8021

semanageコマンドにportとつけて実行するとネットワークのポートへタイプを設定するための定義情報に対する操作を行うことができ、fcontextと同様-lオプションで定義の一覧表示となります。この結果から、tcpの80番ポートにはhttp_port_tというタイプが設定されていることがわかりましたので、30080番ポートにも同様にhttp_port_tというタイプを設定してみます。

# /usr/sbin/semanage port -a -t http_port_t -p tcp 30080

-aと-tオプションについてはfcontextと同様、-pオプションはプロトコルの指定です。正しく追加されていることを確認するには、fcontextと同様-lCオプションを指定して追加分のみのリストを表示するとよいでしょう。

# /usr/sbin/semanage port -lC
SELinux ポートタイプ                 プロト      ポート番号

http_port_t                    tcp      30080

ファイルと異なりポートについては設定内容が即座に有効となるので、ここでApacheを起動して確認してみます。

# service httpd start
httpd を起動中:                                            [  OK  ]

起動に成功しました。ブラウザで30080ポートを指定してアクセスし、正常にコンテンツが表示できることを確認しておきましょう。(iptables等の設定も忘れずに)

なお、追加したポートの設定についても、fcontextと同様-dオプションで削除することができます。

# /usr/sbin/semanage port -d -p tcp 30080

ブール変数

比較的最近の(と言っても何年も前からですが)SELinuxには、ブール変数というものがあります。

ブール変数とは、ポリシーに含まれる一部の操作を有効にするかどうかをスイッチをオンオフするように切り替えられるもので、ポリシー自体を変更しなくとも必要に応じてある操作を有効にしたり無効にしたりといった調整が行えるようになっています。

例えば次のようにして、Apacheに関連しそうなブール変数の一覧を確認できます。

# /usr/sbin/semanage boolean -l | grep httpd
httpd_can_network_relay        -> オフ    Allow httpd to act as a relay
httpd_can_network_connect_db   -> オフ    Allow HTTPD scripts and modules to connect to databases over the network.
httpd_use_gpg                  -> オフ    Allow httpd to run gpg in gpg-web domain
httpd_enable_cgi               -> オン    Allow httpd cgi support
httpd_use_cifs                 -> オフ    Allow httpd to access cifs file systems
allow_httpd_mod_auth_pam       -> オフ    Allow Apache to use mod_auth_pam
allow_httpd_anon_write         -> オン    Allow Apache to modify public files used for public file transfer services. Directories/Files must be labeled public_rw_content_t.
httpd_enable_homedirs          -> オフ    Allow httpd to read home directories
allow_httpd_sys_script_anon_write -> オン    Allow apache scripts to write to public content.  Directories/Files must be labeled public_rw_content_t.
httpd_dbus_avahi               -> オン    Allow Apache to communicate with avahi service via dbus
httpd_unified                  -> オン    Unify HTTPD handling of all content files.
httpd_can_network_connect      -> オン    Allow HTTPD scripts and modules to connect to the network using TCP.
httpd_tty_comm                 -> オン    Unify HTTPD to communicate with the terminal. Needed for entering the passphrase for certificates at the terminal.
httpd_read_user_content        -> オフ    Allow httpd to read user content
httpd_use_nfs                  -> オフ    Allow httpd to access nfs file systems
httpd_tmp_exec                 -> オフ    Allow Apache to execute tmp content.
httpd_execmem                  -> オフ    Allow httpd scripts and modules execmem/execstack
httpd_can_sendmail             -> オフ    Allow http daemon to send mail
httpd_builtin_scripting        -> オン    Allow httpd to use built in scripting (usually php)
httpd_can_check_spam           -> オフ    Allow http daemon to check spam
allow_httpd_mod_auth_ntlm_winbind -> オフ    Allow Apache to use mod_auth_pam
httpd_can_network_memcache     -> オフ    Allow httpd to connect to memcache server
httpd_can_network_connect_cobbler -> オフ    Allow HTTPD scripts and modules to connect to cobbler over the network.
httpd_ssi_exec                 -> オフ    Allow HTTPD to run SSI executables in the same domain as system CGI scripts.
httpd_enable_ftp_server        -> オフ    Allow httpd to act as a FTP server by listening on the ftp port.
httpd_setrlimit                -> オフ    Allow httpd daemon to change system limits

このように、CGIの実行などはデフォルトでオンに設定されていますが、多くの項目がオフであることがわかります。必要に応じてこれらの項目をオンにすることで、または不要な項目をオフにすることで、ポリシー自体を変更せずに各機能の有効無効の設定ができるようになっているわけです。

私自身(一部項目以外確認していないので)全ての項目について説明することはできませんが、例えばhttpd_can_sendmailの項目をオンにすることでPHP等のプログラムからメールを送信することを許可したり、httpd_enable_cgiの項目をオフにすることでCGIを実行できないようにしたりといったことが可能になります。

これらのブール変数のオンオフを設定するには、setseboolコマンドを使用します。

# /usr/sbin/setsebool -P httpd_can_sendmail on
(メールの送信を可能にする)
# /usr/sbin/setsebool -P httpd_enable_cgi off
(CGIの実行を不可にする)

なお、-Pオプションは永続的に設定を反映することを意味し、これをつけずに実行するとOS再起動の際に設定が戻ってしまいますので注意してください。

また、fcontextやport同様、semanageコマンドにて追加設定のみを確認したり設定の削除が可能です。

# /usr/sbin/semanage boolean -lC
(追加設定のみをリスト表示する)
SELinux boolean                          説明

httpd_enable_cgi               -> オフ    Allow httpd cgi support
httpd_can_sendmail             -> オン    Allow http daemon to send mail
# /usr/sbin/semanage boolean -d httpd_enable_cgi
(httpd_enable_cgiに対する追加設定を削除し、デフォルト値であるオンに戻す)

まとめ

日本語の解説も少なくとっつきにくいイメージのあるSELinuxですが、以上のように内容によってはSELinuxを有効にしたままでも比較的容易に実現できます。もちろん、そんなことを調べている暇がない、テスト環境などを構築するため多少セキュリティを落としてでも容易に扱えるようにしたい等、状況は様々でしょうから、なにがなんでもSELinuxを有効にした方がいいとは言えませんが、興味を持たれた方はSELinuxを無効にする前に他の実現方法を少しだけでも考えてみてはいかがでしょうか。

カテゴリー: システム管理 | タグ: , | 3件のコメント

コマンドラインでちょっとSELinux” への3件のコメント

  1. ossy より:

    いままで、SELinuxは無効にしてました。とてもわかりやすい記事で勉強になります。ありがとうございます!

    • MorphMorph より:

      コメントありがとうございます。
      そう言っていただけると私もとても励みになります。

  2. ピンバック: apacheインストール | 子狐のはじまり

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です