SELinuxを用いて2つのhttpdインスタンスに独立なドメインを割り当てる。
こんにちは。SIOS OSSエバンジェリスト/セキュリティ担当の面 和毅です。
ここでは、SELinuxの使い方の例をいくつかサンプルにして見てみます。
SELinuxによるコンパートメント
SELinuxを用いてコンパートメント化を行いたいという要望はよく聞きます。今回は、下図のような構成を作成してみます。
Apacheを2つのインスタンスで立ち上げます。/etc/httpd_1/conf, /var/www1/等を利用してPort8081/4431でListenするインスタンスAはhttpd1_tドメイン、同様に/etc/httpd_2/conf, /var/www2/等を利用しPort8082/4432でListenするインスタンスBはhttpd2_tドメインとします。
2つのインスタンスで立ち上がるようにする。
まずは、/etc/httpd以下をそのまま/etc/httpd_1, /etc/httpd_2としてコピーします。
同様に/var/www以下をそのまま/var/www1, /var/www2としてコピーします。
/etc/httpd_1/conf/httpd.confを以下のように書き換えます。httpd2も同様に変えます。
[root@localhost etc]# diff -Nru /etc/httpd/conf/httpd.conf /etc/httpd_1/conf/httpd.conf|more --- /etc/httpd/conf/httpd.conf 2017-10-20 01:44:27.000000000 +0900 +++ /etc/httpd_1/conf/httpd.conf 2017-12-06 12:30:11.318780270 +0900 @@ -28,7 +28,7 @@ # same ServerRoot for multiple httpd daemons, you will need to change at # least PidFile. # -ServerRoot "/etc/httpd" +ServerRoot "/etc/httpd_1" # # Listen: Allows you to bind Apache to specific IP addresses and/or @@ -39,7 +39,7 @@ # prevent Apache from glomming onto all bound IP addresses. # #Listen 12.34.56.78:80 -Listen 80 +Listen 8001 # # Dynamic Shared Object (DSO) Support @@ -116,19 +116,19 @@ # documents. By default, all requests are taken from this directory, but # symbolic links and aliases may be used to point to other locations. # -DocumentRoot "/var/www/html" +DocumentRoot "/var/www1/html" # # Relax access to content within /var/www. # - + AllowOverride None # Allow open access: Require all granted # Further relax access to the default document root: - + # # Possible values for the Options directive are "None", "All", # or any combination of: @@ -244,15 +244,15 @@ # client. The same rules about trailing "/" apply to ScriptAlias # directives as to Alias. # - ScriptAlias /cgi-bin/ "/var/www/cgi-bin/" + ScriptAlias /cgi-bin/ "/var/www1/cgi-bin/" # -# "/var/www/cgi-bin" should be changed to whatever your ScriptAliased +# "/var/www1/cgi-bin" should be changed to whatever your ScriptAliased # CGI directory exists, if you have that configured. # - + AllowOverride None Options None Require all granted @@ -351,3 +351,7 @@ # # Load config files in the "/etc/httpd/conf.d" directory, if any. IncludeOptional conf.d/*.conf + +# PIDFile + +PidFile /var/run/httpd1.pid
/etc/httpd1/conf.d/ssl.confも変更します。
[root@localhost etc]# diff -Nru /etc/httpd/conf.d/ssl.conf /etc/httpd_1/conf.d/ssl.conf --- /etc/httpd/conf.d/ssl.conf 2017-10-20 01:44:27.000000000 +0900 +++ /etc/httpd_1/conf.d/ssl.conf 2017-12-06 12:34:41.877615417 +0900 @@ -2,7 +2,7 @@ # When we also provide SSL we have to listen to the # the HTTPS port in addition. # -Listen 443 https +Listen 4431 https ## ## SSL Global Context @@ -53,11 +53,11 @@ ## SSL Virtual Host Context ## - + # General setup for the virtual host, inherited from global configuration #DocumentRoot "/var/www/html" -#ServerName www.example.com:443 +#ServerName www.example.com:4431 # Use separate log files for the SSL virtual host; note that LogLevel # is not inherited from httpd.conf.
/etc/httpd1/conf.d/nss.confも書き換えます。
[root@localhost etc]# diff -Nru /etc/httpd/conf.d/nss.conf /etc/httpd_1/conf.d/nss.conf --- /etc/httpd/conf.d/nss.conf 2015-11-21 00:16:41.000000000 +0900 +++ /etc/httpd_1/conf.d/nss.conf 2017-12-06 12:39:24.425501258 +0900 @@ -16,7 +16,7 @@ # Note: Configurations that use IPv6 but not IPv4-mapped addresses need two # Listen directives: "Listen [::]:8443" and "Listen 0.0.0.0:443" # -Listen 8443 +Listen 4411 ## ## SSL Global Context @@ -80,17 +80,17 @@ ## SSL Virtual Host Context ## - + # General setup for the virtual host -#DocumentRoot "/etc/httpd/htdocs" -#ServerName www.example.com:8443 +#DocumentRoot "/etc/httpd_1/htdocs" +#ServerName www.example.com:4441 #ServerAdmin you@example.com # mod_nss can log to separate log files, you can choose to do that if you'd like # LogLevel is not inherited from httpd.conf. -ErrorLog /etc/httpd/logs/error_log -TransferLog /etc/httpd/logs/access_log +ErrorLog /etc/httpd_1/logs/error_log +TransferLog /etc/httpd_1/logs/access_log LogLevel warn # SSL Engine Switch: @@ -134,7 +134,7 @@ # The NSS security database directory that holds the certificates and # keys. The database consists of 3 files: cert8.db, key3.db and secmod.db. # Provide the directory that these files exist. -NSSCertificateDatabase /etc/httpd/alias +NSSCertificateDatabase /etc/httpd_1/alias # Database Prefix: # In order to be able to store multiple NSS databases in one directory
“setenforce 0″を実行して、SELinuxをPermissiveモードにします。
/usr/local/sbin/httpd1.cとして下記のようなプログラムを作り、”gcc -o /usr/local/sbin/httpd1 /usr/local/sbin/httpd1.c”としてhttpd1起動用のラッパーを作成します(httpd2も同様にします)。
/etc/init.d/httpd1, /etc/init.d/httpd2を作っておきます(本当は、systemdで作るべきですが、あくまでもSELinuxのテストということで、簡便に作っています。
#!/bin/sh case "$1" in start) /usr/local/sbin/httpd1 ;; stop) kill `ps axZ|grep http|grep Ss |awk '{print $2}'` exit 2 esac
#include #include int main(void) { char program[] = "/usr/sbin/httpd -f /etc/httpd_1/conf/httpd.conf"; int result; result = system(program); if ( result == EXIT_SUCCESS ) { puts("Success to exec."); } else { puts("Failed to exec."); } return EXIT_SUCCESS; }
SELinuxポリシの準備
selinux-policy-devをインストールして、ポリシが追加できるように準備します。
/usr/share/selinux/devel/httpd_1を作成します。
/usr/share/selinux/devel/httpd_1にteファイル,fcファイル,ifファイルを作成します。Makefileは上のディレクトリ(/usr/share/selinux/devel)からコピーします。
teファイルはこのように作成します。
[root@localhost httpd_1]# more httpd1.te policy_module(httpd1,1.0.1) ######################################## # # Declarations # type httpd1_t; type httpd1_exec_t; domain_type(httpd1_t) domain_entry_file(httpd1_t, httpd1_exec_t) type httpd1_log_t; logging_log_file(httpd1_log_t) init_daemon_domain(httpd1_t, httpd1_exec_t)
fcファイルをこのように作成します。
ifファイルは現時点では必要ないので空で作ります。
makeを実行します。
httpd1.ppが出来ているはずなので、”semodule -i httpd1.pp”を実行します。
SELinuxがPermissiveになっているのを確認して、/etc/init.d/httpd1 startを実行します。
httpd1がhttpd1_tドメインで動いていることを確認します。
httpd2に対しても同様のステップをとります。
# myapp executable will have: # label: system_u:object_r:myapp_exec_t # MLS sensitivity: s0 # MCS categories: /usr/local/sbin/httpd1 -- gen_context(system_u:object_r:httpd1_exec_t,s0)
[問題点と解決案]
この後、httpd1_t, httpd2_tに対して必要なパーミッションをログからallow文等で追加していけば、httpd1_t, httpd2_tドメインでそれぞれ動くことになります。
しかし、この方法では先の図のようにライブラリやその他のファイル等をドメインA, ドメインBで使っていることになるため、httpd1_tが突破されると共用している部分に被害が及び、結果としてドメインBまで被害が及ぶ可能性が有ります。
このような構成を取る場合には、最近ではDockerが充分に使えるものになっているため、Dockerを用いてドメインA, ドメインBを分けたほうが(リソースの共用もないため)ベターだと思われます。
DockerとSELinuxを併用することで、ドメインA(DockerA)とドメインB(DockerB)が違うカテゴリに入るためアクセスできないようになるため、こちらを使った構成のほうがシンプルでかつセキュリティ的にもベターだと言えます。
セミナー情報
12/13/(水)に「OSSセキュリティナイターvol.7」と題して、セキュリティのセミナーを行います。この回では、『IoTセキュリティの今/世界のLinux Securityの今 』と題してIoTセキュリティの著名な方、またLinux Securityの著名な方を講師としてお招きし、IoTセキュリティの話と、世界のLinux Securityの最新動向を御講演頂きます。
https://connpass.com/event/72983がプログラム内容と申し込みの詳細になりますので、是非お申し込み下さい。
セキュリティ系連載案内
OSSセキュリティ技術の会による日経Linuxでの連載「IoT時代の最新SELinux入門」がITPro上で読めるようになりました。技術の会代表で第一人者である中村さん等による、最新のSELinuxの情報やコマンド類等も更新されているのでお薦めです。
OSSセキュリティ技術の会によるThinkITでの連載「開発者のためのセキュリティ実践講座」がThinkIT上で開始しました。技術の会の中の人間で、最新の代表的なOSSセキュリティ技術を紹介していきます。
OSSセキュリティ技術の会により、ThinkITでLinuxSecuritySummit 2017のレポートが紹介されています。