コンテナと SELinux


Linux についてそこそこ詳しくなったので、そろそろ SELinux と本気で向き合おうとしている今日この頃です。SELinux 自体は下記のサイトさんが分かりやすくてなんとなく理解できた気がします。

理由がわかれば怖くない!SELinux とのつきあい方

今回はどうやってそれをコンテナに適用するか、調べてみました。

やりたいこととしては、複数のコンテナを立ち上げてコンテナごとにホスト側のファイルのアクセスを制限することです。

以下のようなディレクトリ構成の場合、

/srv/wwwpod/
 ├ mariadb/  mariadb のみ許可
 ├ nginx/    nginx のみ許可
 ├ php/      php のみ許可
 └ public/   nginx, php のみ許可

といった設定にしたいのです。元ネタはこの記事です

コンテナのプロセスのコンテキスト

まずはコンテナのプロセスがどんなコンテキストになるか確認しました。ps コマンドって人によって好みのオプションがあると思いますが、それに Z を追加するとコンテキストが出てきます。

[root@localhost ~]# ps axZ
LABEL                             PID TTY      STAT   TIME COMMAND
system_u:system_r:container_t:s0 4000 ? Ss   0:00 php-fpm: master process (/usr/local/etc/php-fpm.conf)
system_u:system_r:container_t:s0 4001 ? Ss   0:00 nginx: master process nginx -g daemon off;
system_u:system_r:container_t:s0 4002 ? S   0:00 php-fpm: pool www
system_u:system_r:container_t:s0 4003 ? S   0:00 php-fpm: pool www
system_u:system_r:container_t:s0 4004 ? S   0:00 nginx: worker process
system_u:system_r:container_t:s0 4005 ? Ssl   0:00 mysqld

コンテナのプロセスのみ抽出しました。デフォルトだと全部 system_u:system_r:container_t:s0 になるみたいですね。

podman / docker のオプションを調べる

ひとまずコンテナ立ち上げ時に SELinux 関連のオプションがないか調べます。どうやら run する時にオプション –security-opt を使用することで設定できるようです。

Docker のドキュメント
Podman のドキュメント

system_u:system_r:container_t:s0 の場合
--security-opt label=user:system_u
--security-opt label=role:system_r
--security-opt label=type:container_t
--security-opt label=level:s0

動作確認は podman で行っています。 docker で動かなかったら申し訳ありません。

どういうコンテキスト構成にするか

ユーザーとロールはまだ理解していないのでなしとして、タイプかレベルを使うことになるのですが、レベルは用途的にタイプの中での切り分けで使うもののようなので、タイプを変更する方向でまずは考えます。

ただ、タイプを変えると以下のような許可設定を作らないといけないので少し手間がかかります。自作したい場合はこちらが参考になります。

module xxxx 1.0;

require {
	type container_t;
}

allow container_t admin_home_t:file { read };

コンテナのデフォルトの許可設定はここみたいですが、正直見てもわかりません。どこかに container_t タイプのプロセスは container_file_t タイプのファイルの読み書きができるっていう設定があるはずなのですが・・・。タイプを変える場合はこの設定を維持しないと何かが動かなくなる気がするので、私がまだ立ち入ってはならない領域のようです。

簡単な方法を探す

ところで、 SELinux には MCS という概念があります。Multi Category Security の略です。

先ほどのコンテキストは system_u:system_r:container_t:s0 でしたが、レベルの s0 の後ろに s0:c20,c85 といった形で , 区切りで複数のカテゴリを指定できる機能です。カテゴリというか感覚的にはタグに近い気がします。

例として、ユーザーのコンテキストを確認すると以下のように出てきます。root で確認したのでほぼ許可するコンテキストになっています。

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

分解すると以下のような形です。右に意訳を書いてみました。カテゴリの . は範囲指定です。

user:                  unconfined_u    制限のないユーザー
role:                  unconfined_r    制限のないロール
type:                  unconfined_t    制限のないタイプ
level(sensitivity):    s0-s0           機密度 0~0 まで見れる
level(category):       c0.c1023        カテゴリ 0~1023 まで見れる

機密度は大きくなるほど制限が強いんですが、ファイルの機密度を s1 とかにすると root ユーザーでも見えないってことですよね。相当な機密情報です。最大で s15 まで指定できるみたいですが、そこまで使い切る案件には出会いそうにないです。

カテゴリの動き

試しにディレクトリにカテゴリを設定してみます。

# chcon -Rt container_file_t /srv/wwwpod

# chcon -Rl s0:c1 /srv/wwwpod/mariadb
# chcon -Rl s0:c2,c4 /srv/wwwpod/php
# chcon -Rl s0:c3,c4 /srv/wwwpod/nginx
# chcon -Rl s0:c4 /srv/wwwpod/public

# ls -lZ
drwxr-xr-x. 2 root     root     system_u:object_r:container_file_t:s0:c1     4096 Aug 12 00:00 mariadb
drwxr-xr-x. 2 root     root     system_u:object_r:container_file_t:s0:c2,c4  4096 Aug 12 00:00 nginx
drwxr-xr-x. 2 root     root     system_u:object_r:container_file_t:s0:c3,c4  4096 Aug 12 00:00 php
drwxr-xr-x. 3 root     root     system_u:object_r:container_file_t:s0:c4     4096 Aug 12 00:00 public

ファイルのコンテキストの変更は chcon コマンドを使用します。

chcon – change file SELinux security context

man chcon より。注:強調は編集者によるもの

名前は chmod, chown と同じように覚えやすそうです。

R オプションは再帰的に反映ですので注意してください。

t オプションでタイプを変更できます。環境によるかもしれませんが、 container_file_t タイプではないファイルには、コンテナ側からアクセスできないです。

l オプションを指定するとコンテキストのレベルを変更できます。

s0 は s0-s0 の略です。機密度は変更しないんですが、機密度とカテゴリは2つ合わせてレベルという概念なのでセットで指定します。

ファイル側のカテゴリが c1 の場合は、c1 を許可されたユーザー・プロセスがアクセス可能です。ファイル側が c3,c4 の場合は、ユーザー・プロセスは c3,c4 両方を許可されていないとアクセスできません。

コンテナ側の設定

上記を踏まえて、コンテナ側のオプションを指定します。それぞれのコンテナの podman run / docker run に以下のような –security-opt オプションを追加します。

mariadb コンテナ:     --security-opt label=level:s0:c1
php コンテナ:         --security-opt label=level:s0:c2,c4
nginx コンテナ:       --security-opt label=level:s0:c3,c4

このように指定すれば、最初に想定した通りの制限がかかります。許可されていない場所にアクセスすると、 Permission denied になります。

ls: can't open '.': Permission denied

参考にさせて頂いたサイト


コメントを残す

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

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください