SELinuxを用いて2つのhttpdインスタンスに独立なドメインを割り当てる。 — | サイオスOSS | サイオステクノロジー

SELinuxを用いて2つのhttpdインスタンスに独立なドメインを割り当てる。

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つのインスタンスで立ち上がるようにする。

  1. まずは、/etc/httpd以下をそのまま/etc/httpd_1, /etc/httpd_2としてコピーします。

  2. 同様に/var/www以下をそのまま/var/www1, /var/www2としてコピーします。

  3. /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
    
  4. /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.
    
  5. /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
    
  6. “setenforce 0″を実行して、SELinuxをPermissiveモードにします。

  7. /usr/local/sbin/httpd1.cとして下記のようなプログラムを作り、”gcc -o /usr/local/sbin/httpd1 /usr/local/sbin/httpd1.c”としてhttpd1起動用のラッパーを作成します(httpd2も同様にします)。

  8. #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;
    }
    
  9. /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
    

SELinuxポリシの準備

  1. selinux-policy-devをインストールして、ポリシが追加できるように準備します。

  2. /usr/share/selinux/devel/httpd_1を作成します。

  3. /usr/share/selinux/devel/httpd_1にteファイル,fcファイル,ifファイルを作成します。Makefileは上のディレクトリ(/usr/share/selinux/devel)からコピーします。

  4. 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)
    
  5. fcファイルをこのように作成します。

  6. # 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)
    
  7. ifファイルは現時点では必要ないので空で作ります。

  8. makeを実行します。

  9. httpd1.ppが出来ているはずなので、”semodule -i httpd1.pp”を実行します。

  10. SELinuxがPermissiveになっているのを確認して、/etc/init.d/httpd1 startを実行します。

  11. httpd1がhttpd1_tドメインで動いていることを確認します。

  12. httpd2に対しても同様のステップをとります。

[問題点と解決案]

この後、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がプログラム内容と申し込みの詳細になりますので、是非お申し込み下さい。

セキュリティ系連載案内

—–

タイトルとURLをコピーしました