【Linux Kernel 5.0特集】Kernelに含まれているセキュリティ機構 - Part2(SELinux編: 後編)

こんにちは。SIOS OSSエバンジェリスト/セキュリティ担当の面 和毅です。

2019年初の話題として、次期Linux Kernelのバージョンが4.xから5.0になるという話が話題になっています。

メジャーバージョンも上がるということで、一種まとめの機会ではあると思われますので、これから数回に分けてLinux Kernel 5.0での現状のセキュリティ機構(Kernelに含まれているセキュリティ機構)を整理して見ていこうと思います。

今回は、前回の続きでSELinuxのコンテナ(Docker, runc, Kubernetes等)周りについて見ていきたいと思います。




連載の構成

本連載では、Linux Kernelのセキュリティについて、下記のような順番で紹介します。

  1. LSM(Linux Security Module)の2019での情報まとめ
    1. SELinux
    2. AppArmor
    3. Yama
    4. IMA
    5. TOMOYO
    6. SMACK
    7. その他(loadpin, Hardened-UserCopy, その他)
  2. ケーパビリティ(Capability)について
    1. ケーパビリティについて、及び使い方(2019年版)
  3. seccompについて
    1. seccompについて、及び使い方
    2. BPFについて、及び使い方
  4. Kernel Self-Protectionについて

第ニ回(SELinux編 後編)

SELinuxに関しては、ほぼ知らない方はいらっしゃらないかと思いますので詳しい説明は>省略します(概要及び2017年時点での情報に関しては、こちらの日経Linuxの記事を参照してください。以降、この記事では「既に基本的な(CentOS7.x時代の)SELinuxを理解している」という前提で進めていきます。

サンプルで使用するには、やはりFedoraの最新バージョンを使うのが一番簡単です。今回は(執筆時点の01/09/2019では)Fedora29を使用します。

以降、Fedora29をインストールし、パッケージは(01/09/2019時点での)最新バージョンにしている状態を想定して説明していきます。ここでは、日経Linuxの記事の話を踏まえて

  1. 2019年時点での差分(Fedora29で)
  2. CILに関してもう少し
  3. 2019年時点での差分

について説明していきます。

2019年時点でのSELinuxの差分(Fedora29で)と簡単な振り返り

  1. バイナリーポリシーファイル
  2. ブーリアン(Boolean)
  3. SELinux CIL
  4. Container対応

  1. Container対応
  2. システムでコンテナを動かした際にSELinuxがどのように動くかをまとめます。

    Dockerのようなコンテナは、システム上から見るとひと括りになっているプロセスになっています。

    例として、Fedora29上にDockerをインストールして、dockerのnginxをコンテナで動かしてみましょう。

    1. まず、システム上で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
      --省略--
      
    2. 次に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
      --省略--
      完了しました!
      
    3. 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')
      
    4. 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"ドメインで動作していることがわかります。

    5. 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;
      
    6. この状態で、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
      
    7. ここで改めて、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
      
    8. このままですと、図のようにnginxが何か侵害された際にPostgreSQLにも影響があることになります(図1)。そのため、Dockerを「SELinuxによるアクセス制御を有効にする」形で起動して、コンテキストをそれぞれで分けるようにします。
    9. まずは、"docker info"でセキュリティのオプションを見てみると
      
      [root@localhost ~]# docker info 
      --省略--
      Security Options:
       seccomp
        Profile: default
      --省略--
      
      と、"seccomp"のみをサポートする形になっていることがわかります。
    10. そこで、/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
      
    11. 一度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
      
    12. 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
      
    13. 再び、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でコンテナで動かすサービス同士のセキュリティを向上させることが可能です。

  3. Kubernetes対応
  4. 前節で説明した「DockerをSELinux有効で立ち上げた時」ですが、Kubernetesを用いて、SELinuxのコンテキストを指定してサービスを起動することが可能なようです。(参照: Configure a Security Context for a Pod or Container。こちらは、また別の機会で紹介したいと思います。


[次回は]

今回でSELinuxに関しては終わりにします。次回はAppArmorに関しての説明を行います。



セキュリティ系連載案内


セミナー情報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/がプログラム内容と申し込みの詳細になります。奮ってご参加下さい。


OSSに関するお困りごとは サイオス OSSよろず相談室まで

サイオスOSSよろず相談室 では、OSSを利用する中で発生する問題に対し、長年培ってきた技術力・サポート力をもって企業のOSS活用を強力に支援します。Red Hat Enterprise Linux のほか、CentOS をご利用されている環境でのサポートも提供いたします。

前へ

"syzbot"と"syzkaller"について (Part 2) 「Azure上でsyzkallerは動くのか」

次へ

Mcafee Endpoint Security for Linuxインストール時のTips(CentOS 7上でのfileaccess_modモジュールによるKernel Crash等の問題と解決方法)