こんにちは。SIOS OSSエバンジェリスト/セキュリティ担当の面 和毅です。
2019年初の話題として、次期Linux Kernelのバージョンが4.xから5.0になるという話が話題になっています。
メジャーバージョンも上がるということで、一種まとめの機会ではあると思われますので、これから数回に分けてLinux Kernel 5.0での現状のセキュリティ機構(Kernelに含まれているセキュリティ機構)を整理して見ていこうと思います。
今回は、前回の続きでSELinuxのコンテナ(Docker, runc, Kubernetes等)周りについて見ていきたいと思います。
連載の構成
本連載では、Linux Kernelのセキュリティについて、下記のような順番で紹介します。
- LSM(Linux Security Module)の2019での情報まとめ
- SELinux
- AppArmor
- Yama
- IMA
- TOMOYO
- SMACK
- その他(loadpin, Hardened-UserCopy, その他)
- ケーパビリティ(Capability)について
- ケーパビリティについて、及び使い方(2019年版)
- seccompについて
- seccompについて、及び使い方
- BPFについて、及び使い方
- Kernel Self-Protectionについて
第ニ回(SELinux編 後編)
SELinuxに関しては、ほぼ知らない方はいらっしゃらないかと思いますので詳しい説明は>省略します(概要及び2017年時点での情報に関しては、こちらの日経Linuxの記事を参照してください。以降、この記事では「既に基本的な(CentOS7.x時代の)SELinuxを理解している」という前提で進めていきます。
サンプルで使用するには、やはりFedoraの最新バージョンを使うのが一番簡単です。今回は(執筆時点の01/09/2019では)Fedora29を使用します。
以降、Fedora29をインストールし、パッケージは(01/09/2019時点での)最新バージョンにしている状態を想定して説明していきます。ここでは、日経Linuxの記事の話を踏まえて
- 2019年時点での差分(Fedora29で)
- CILに関してもう少し
- 2019年時点での差分
について説明していきます。
2019年時点でのSELinuxの差分(Fedora29で)と簡単な振り返り
- バイナリーポリシーファイル
- ブーリアン(Boolean)
- SELinux CIL
- Container対応
- Container対応
システムでコンテナを動かした際にSELinuxがどのように動くかをまとめます。
Dockerのようなコンテナは、システム上から見るとひと括りになっているプロセスになっています。
例として、Fedora29上にDockerをインストールして、dockerのnginxをコンテナで動かしてみましょう。
- まず、システム上でDockerが動作するようにします。Dockerの公式リポジトリをdnfに登録します。
[root@localhost ~]# dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo repo の追加: https://download.docker.com/linux/fedora/docker-ce.repo [root@localhost ~]# dnf info docker-ce Docker CE Stable - x86_64 1.3 kB/s | 3.6 kB 00:02 利用可能なパッケージ 名前 : docker-ce エポック : 3 バージョン : 18.09.1 リリース : 3.fc29 アーキテクチ : x86_64 --省略--
- 次にdocker-ceをインストールします。
[root@localhost ~]# dnf install docker-ce Fedora Modular 29 - x86_64 4.6 kB/s | 8.0 kB 00:01 Fedora Modular 29 - x86_64 - Updates 4.5 kB/s | 7.9 kB 00:01 Fedora 29 - x86_64 - Updates 4.2 kB/s | 7.2 kB 00:01 Fedora 29 - x86_64 4.8 kB/s | 8.1 kB 00:01 依存関係が解決しました。 ======================================================================================== パッケージ アーキテクチャー バージョン リポジトリ サイズ ======================================================================================== インストール: docker-ce x86_64 3:18.09.1-3.fc29 docker-ce-stable 19 M --省略-- 完了しました!
- dockerがサービスとして自動起動するようにしておきます。
[root@localhost ~]# systemctl enable docker Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service. [root@localhost ~]# systemctl start docker [root@localhost ~]# ps axZ|grep -i docker system_u:system_r:container_runtime_t:s0 3444 ? Ssl 0:00 /usr/bin/dockerd -H fd:// system_u:system_r:container_runtime_t:s0 3463 ? Ssl 0:00 containerd --config /var/run/docker/containerd/containerd.toml --log-level info
このように、docker(dockerd)はcontainer_runtime_tドメインで動作しています。親子関係を把握したい為、”pstree -Z”の結果も確認します。
├─dockerd(`system_u:system_r:container_runtime_t:s0') │ ├─containerd(`system_u:system_r:container_runtime_t:s0')
- nginxをDockerコンテナからダウンロードして、Port80で動作するようにします(nginx01)。
[root@localhost ~]# docker run --name nginx01 -d -p 80:80 nginx Unable to find image 'nginx:latest' locally latest: Pulling from library/nginx 177e7ef0df69: Pull complete ea57c53235df: Pull complete bbdb1fbd4a86: Pull complete Digest: sha256:b543f6d0983fbc25b9874e22f4fe257a567111da96fd1d8f1b44315f1236398c Status: Downloaded newer image for nginx:latest 87dfe1def9d586a49523a85b995fdca1d62bed130d933a5ff45a17e9523428e6 [root@localhost ~]# ps axZ|grep nginx system_u:system_r:spc_t:s0 4400 ? Ss 0:00 nginx: master process nginx -g daemon off; system_u:system_r:spc_t:s0 4436 ? S 0:00 nginx: worker process
親子関係を把握したい為、”pstree -Z”の結果も確認します。
|-dockerd(`system_u:system_r:container_runtime_t:s0') | |-containerd(`system_u:system_r:container_runtime_t:s0') | | |-containerd-shim(`system_u:system_r:container_runtime_t:s0') | | | |-nginx(`system_u:system_r:spc_t:s0') | | | | `-nginx(`system_u:system_r:spc_t:s0') | | | `-9*[{containerd-shim}(`system_u:system_r:container_runtime_t:s0')] | | `-11*[{containerd}(`system_u:system_r:container_runtime_t:s0')] | |-docker-proxy(`system_u:system_r:container_runtime_t:s0') | | `-7*[{docker-proxy}(`system_u:system_r:container_runtime_t:s0')] | `-13*[{dockerd}(`system_u:system_r:container_runtime_t:s0')]
ここで、コンテナで動作しているプロセス(nginx)が”spc_t”ドメインで動作していることがわかります。
- spc_tドメインについて
“spc_t”ドメインに関しては、こちらのDan Walsh氏のブログに詳しくまとまっていますが、”Super Privileged Container(スーパー特権コンテナ)”のドメインになります。
スーパー特権コンテナ:詳しくはRed Hatのサイトで詳しく説明されています。通常のコンテナでは他のコンテナやホストシステムへのアクセスを制限されていますが、スーパー特権コンテナはホストシステムに直接アクセスし、監視や機能変更を行えるようにされています。例えば
- RHEL Atomic Tools コンテナーイメージ: 診断の為のデバッグツール (strace、traceroute、 sosreport など) を実行
- RHEL Atomic rsyslog コンテナーイメージ: rsyslogdを実行してログファイルを管理
- RHEL Atomic System Activity Data Collector (sadc) コンテナーイメージ: sadcサービスを実行し、sarコマンドによる定期的なデータ収集
などが有ります。
SELinuxではスーパー特権コンテナ用にspc_tドメインを用意しています。これらのコンテナはシステム上で何でも出来るので、SELinuxがアクセスを阻害しないようにするため、spc_tドメインはunconfined_tドメインと同じようになっています。sesearchコマンドで遷移するドメインを確認すると、dockerに与えられたcontainer_runtime_tドメインから、spc_tドメインに遷移します。
[root@localhost ~]# sesearch -T -s container_runtime_t|grep spc_t type_transition container_runtime_t container_file_t:process spc_t; type_transition container_runtime_t container_share_t:process spc_t; type_transition container_runtime_t container_var_lib_t:process spc_t; type_transition container_runtime_t unlabeled_t:process spc_t;
- この状態で、docker上でnginxとPostgreSQLを動かしてみましょう。post-dbという名前でPort:5432で動かします。
[root@localhost ~]# docker run --name post-db -p 5432:5432 -e POSTGRES_USER=dockertest -e POSTGRES_PASSWORD=dockertest -d postgres:9.6 d0869da901cd0635da07664aed7d029acfa14f4ee978c84db52217c38de80e50 [root@localhost ~]# ps axZ|grep docker|grep 5432 system_u:system_r:container_runtime_t:s0 2866 ? Sl 0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 5432 -container-ip 172.17.0.2 -container-port 5432
- ここで改めて、nginxとPostgreSQLのコンテキストを比べてみましょう。下記のようになっているため、nginxとPostgreSQLは同じコンテキスト(system_u:system_r:unconfined_service_t:s0)で動作しているため、SELinuxを用いてのアクセス制御では同じもの(しかもunconfinedドメイン!!)として扱われていることがわかります。
[root@localhost ~]# ps axZ|grep -i postgres system_u:system_r:unconfined_service_t:s0 2579 ? Ss 0:00 postgres system_u:system_r:unconfined_service_t:s0 2677 ? Ss 0:00 postgres: checkpointer process system_u:system_r:unconfined_service_t:s0 2678 ? Ss 0:00 postgres: writer process system_u:system_r:unconfined_service_t:s0 2679 ? Ss 0:00 postgres: wal writer process system_u:system_r:unconfined_service_t:s0 2680 ? Ss 0:00 postgres: autovacuum launcher process system_u:system_r:unconfined_service_t:s0 2681 ? Ss 0:00 postgres: stats collector process [root@localhost ~]# ps axZ|grep -i nginx system_u:system_r:unconfined_service_t:s0 2759 ? Ss 0:00 nginx: master process nginx -g daemon off; system_u:system_r:unconfined_service_t:s0 2793 ? S 0:00 nginx: worker process
- このままですと、図のようにnginxが何か侵害された際にPostgreSQLにも影響があることになります(図1)。そのため、Dockerを「SELinuxによるアクセス制御を有効にする」形で起動して、コンテキストをそれぞれで分けるようにします。
- まずは、”docker info”でセキュリティのオプションを見てみると
[root@localhost ~]# docker info --省略-- Security Options: seccomp Profile: default --省略--
と、”seccomp”のみをサポートする形になっていることがわかります。
- そこで、/usr/lib/systemd/system/docker.serviceファイルを下記のように修正します(修正後は”systemctl daemon-reload”を忘れずに!)。
修正前
[Service] Type=notify # the default is not to use systemd for cgroups because the delegate issues still # exists and systemd currently does not support the cgroup feature set required # for containers run by docker ExecStart=/usr/bin/dockerd -H fd:// <----ここを ExecReload=/bin/kill -s HUP $MAINPID
修正後
[Service] Type=notify # the default is not to use systemd for cgroups because the delegate issues still # exists and systemd currently does not support the cgroup feature set required # for containers run by docker ExecStart=/usr/bin/dockerd -H fd:// --selinux-enabled <-----こう変更します。 ExecReload=/bin/kill -s HUP $MAINPID
- 一度dockerで"post-db"と"nginx01"をstopし、"docker rm"でイメージを削除します(これをやらないと、コンテキストが分かれませんでした)。
[root@localhost ~]# docker stop nginx01 post-db nginx01 post-db [root@localhost ~]# docker rm nginx01 post-db nginx01 post-db
- dockerを再起動し、再び"docker run"でnginx01とpost-dbを動かします。
[root@localhost ~]# systemctl stop docker [root@localhost ~]# systemctl start docker [root@localhost ~]# docker run --name post-db -p 5432:5432 -e POSTGRES_USER=dockertest -e POSTGRES_PASSWORD=dockertest -d postgres:9.6 c70d8c051635c6ab6caee94fd07ba6b60642abcb295613a1754a5495b44824f7 [root@localhost ~]# docker run --name nginx01 -d -p 80:80 nginx 3bafcbb71308ca259a365e0a54a403f913592dd1e6a2dbcfdc61541b3eeb1d56
- 再び、PostgreSQLとnginxのコンテキストを確認します。
[root@localhost ~]# ps axZ|grep postgres system_u:system_r:container_t:s0:c351,c670 3930 ? Ss 0:00 postgres system_u:system_r:container_t:s0:c351,c670 4024 ? Ss 0:00 postgres: checkpointer process system_u:system_r:container_t:s0:c351,c670 4025 ? Ss 0:00 postgres: writer process system_u:system_r:container_t:s0:c351,c670 4026 ? Ss 0:00 postgres: wal writer process system_u:system_r:container_t:s0:c351,c670 4027 ? Ss 0:00 postgres: autovacuum launcher process system_u:system_r:container_t:s0:c351,c670 4028 ? Ss 0:00 postgres: stats collector process [root@localhost ~]# ps axZ|grep nginx system_u:system_r:container_t:s0:c11,c612 4075 ? Ss 0:00 nginx: master process nginx -g daemon off; system_u:system_r:container_t:s0:c11,c612 4107 ? S 0:00 nginx: worker process
このように、PostgreSQLに関してはcontainer_tドメインのカテゴリ(c351,c670)で、nginxに関してはcontainer_tドメインのカテゴリ(c11,c612)で動作していることがわかります。カテゴリが異なるコンテキストは互いに影響を及ぼすことが出来ないため(MCS: Multi Category Securityと呼ばれています(参照:第6回 新しく追加されたMulti Category Security(@IT)))、このMCSを用いてdockerでコンテナで動かすサービス同士のセキュリティを向上させることが可能です。
- まず、システム上でDockerが動作するようにします。Dockerの公式リポジトリをdnfに登録します。
- Kubernetes対応
前節で説明した「DockerをSELinux有効で立ち上げた時」ですが、Kubernetesを用いて、SELinuxのコンテキストを指定してサービスを起動することが可能なようです。(参照: Configure a Security Context for a Pod or Container。こちらは、また別の機会で紹介したいと思います。
[次回は]
今回でSELinuxに関しては終わりにします。次回はAppArmorに関しての説明を行います。
[参考]
次期Linux Kernel(4.21)を5.0にするというLinusのメール
SELinuxのCIL (Part3) — | サイオスOSS | サイオステクノロジー
SELinuxのCILリファレンスガイド(OSSセキュリティ技術の会(Secure OSS Sig))
セキュリティ系連載案内
- OSSセキュリティ技術の会による日経Linuxでの連載「IoT時代の最新SELinux入門」がITPro上で読めるようになりました。技術の会代表で第一人者である中村さん等による、最新のSELinuxの情報やコマンド類等も更新されているのでお薦めです。
- OSSセキュリティ技術の会によるThinkITでの連載「開発者のためのセキュリティ実践講座」がThinkIT上で開始しました。技術の会の中の人間で、最新の代表的なOSSセキュリティ技術を紹介していきます。
- OSSセキュリティ技術の会により、ThinkITでLinuxSecuritySummit 2018のレポートが紹介されています。
- OSSセキュリティ技術の会の面により、@ITで「OSS脆弱性ウォッチ」が連載されています。
- OSSセキュリティ技術の会の面により、@ITで「OpenSCAPで脆弱性対策はどう変わる?」が連載されています。
- OSSセキュリティ技術の会のメンバーにより、@ITで「Berkeley Packet Filter(BPF)入門」が連載されています。
セミナー情報1
2019/02/08 19:00-21:00に「DRBD開発の最新動向を聞く夜 (つまりDRBDメイン開発者Philippが来日するので迎撃したい。)」が開催されます。SIOSは会場の提供をさせて頂きます。
DRBD(Distributed Replicated Block Device)は、TCP/IPネットワークを通じて複数のサーバ間のHDD(パーティション)をミラーリング(複製)するソフトウェアです。簡単に言うと、ネットワーク越しにRAID1の環境を構築することができます。詳しくは、こちらやこちらの記事がわかりやすく参考になると思います。
DRBDメイン開発者の Philipp Reisner が来日するというので,日本のコミュニティに向けてもDRBDの最新情報を話してもらう場となります。お話は英語で行われます。当日は懇親会も予定しております(ビール、ピザなど)。
https://connpass.com/event/116940/がプログラム内容と申し込みの詳細になります。奮ってご参加下さい。
セミナー情報2
2019/02/12 17:00-19:30で、「NGINX MeetUp Tokyo #2」を行います。
日本のNGINXユーザー、また関心をお持ちの方に向けてNGINX, Inc. CTO / Igor Sysoevを 招きNGINX最新情報をお届けします。セッション終了後には懇親会を用意しておりますので、NGINXを利用する方同士で交流もいただけます。
https://nginx-mj.connpass.com/event/116837/がプログラム内容と申し込みの詳細になります。奮ってご参加下さい。
セミナー情報3
2019/02/21 18:30-22:00で、「OSSライセンスMeetup Vol.2 「実録:GPL違反とその対応を振り返る」」を行います。
いまだに国内の事例として紹介されるGPL違反に関して、状況や経緯、解決策、対応後の反響などについて振り返ります。 これまでは、客観的に違反とその対応に関して事例を説明することは多くありましたが、実際に起こった現場の声を反映した 事例の説明は数少なく、今だから言えることなど、知見を共有いたします。
https://sios.connpass.com/event/112157/がプログラム内容と申し込みの詳細になります。奮ってご参加下さい。