kakakakakku blog

Weekly Tech Blog: Keep on Learning!

Docker と seccomp を組み合わせてシステムコールを制限する

seccomp (Secure computing mode) はプロセスに対してシステムコールを制限する Linux kernel の機能で,今回は「Docker と seccomp」を組み合わせて試す.ドキュメントは以下にある.

docs.docker.com

seccomp デフォルトプロファイル

まず,Docker はデフォルトで seccomp をサポートしている.Docker (Moby) の GitHub リポジトリにデフォルトプロファイル default.json がある.プロファイルは長く感じるけど,比較的簡単に読める.基本的に SCMP_ACT_ERRNO(拒否) となり,ホワイトリストとして列挙したシステムコールを SCMP_ACT_ALLOW(許可) としている.

基本的には制限しすぎず,ホスト側に影響を及ぼすシステムコールなどは禁止されている.ドキュメントにも「It is moderately protective while providing wide application compatibility(幅広いアプリケーション互換性を提供しながら適度に保護する)」と書いてある.

--security-opt オプション

docker run コマンドには --security-opt オプションがあり,--security-opt="seccomp=profile.json" のように seccomp プロファイルを指定できる.また unconfined を指定するとデフォルトプロファイルを無効化できる.

--security-opt="seccomp=unconfined" Turn off seccomp confinement for the container
--security-opt="seccomp=profile.json" White-listed syscalls seccomp Json file to be used as a seccomp filter

docs.docker.com

検証 : mkdir システムコールを制限する

単純な例として,Ubuntu で mkdir システムコールを制限して,mkdir コマンドの挙動を確認する.デフォルトプロファイルでは mkdir システムコールを許可しているため,デフォルトでは以下のように問題なく使える.

$ docker run --rm -d -it ubuntu:21.10
ad3a814faf29ce6407c44723f8a3330c46a425259507dcd4e7673cbaf0f9b2dd

$ docker exec -it ad3a814faf29 /bin/sh

# mkdir sample-dir

次に seccomp を試す.まず,GitHub から default.json を取得して,mkdir のエントリーを削除した deny-mkdir.json を作る.そして docker run コマンドに --security-opt seccomp=deny-mkdir.json オプションを指定すると,mkdir コマンドを実行できなくなった.実際に Operation not permitted とエラーになった.

$ wget https://raw.githubusercontent.com/moby/moby/master/profiles/seccomp/default.json

$ diff -u default.json deny-mkdir.json
@@ -200,7 +200,6 @@
                "membarrier",
                "memfd_create",
                "mincore",
-               "mkdir",
                "mkdirat",
                "mknod",
                "mknodat",

$ docker run --rm -d -it --security-opt seccomp=deny-mkdir.json ubuntu:21.10
4e24d4448c43169ef15a928080a6d82fc7732ee3b782234dfb9b00b0564689c8

$ docker exec -it 4e24d4448c43 /bin/sh

# mkdir sample-dir
mkdir: cannot create directory 'sample-dir': Operation not permitted

検証 : strace システムコールを制限する

関連する例として,今度は Ubuntu で ptrace システムコールを制限して,strace コマンドの挙動を確認する.デフォルトプロファイルでは,以下のように Linux Kernel 4.8ptrace を許可している.

{
        "names": [
                "process_vm_readv",
                "process_vm_writev",
                "ptrace"
        ],
        "action": "SCMP_ACT_ALLOW",
        "args": null,
        "comment": "",
        "includes": {
                "minKernel": "4.8"
        },
        "excludes": {}
},

よって,デフォルトでは以下のように strace コマンドを問題なく使える.

$ docker run --rm -d -it ubuntu:21.10
14c033b88ab4fc361561c37d271dc9d9a3cb98833d570c7c5e86e8cd94db2281

$ docker exec -it 14c033b88ab4 /bin/sh

# uname -r
5.10.25-linuxkit

# apt-get -y update
# apt-get -y install strace

# strace ls
execve("/usr/bin/ls", ["ls"], 0x7ffc3ae41460 /* 5 vars */) = 0
brk(NULL)                               = 0x561158e2e000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffd05d87490) = -1 EINVAL (Invalid argument)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=5826, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 5826, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fe3dd13d000
close(3)

(中略)

# strace -cw ls
bin  boot  dev  etc  home  lib  lib32  lib64  libx32  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 17.22    0.002433        2432         1           munmap
 16.71    0.002361          90        26           mmap
 12.49    0.001765         176        10           close
  8.47    0.001197         132         9           newfstatat
  6.58    0.000930         116         8           openat
  6.29    0.000889         127         7           read
  4.33    0.000612         101         6           pread64
  4.19    0.000592          84         7           mprotect
  3.72    0.000526         262         2           getdents64
  2.99    0.000423         423         1           execve
  2.10    0.000297         297         1           set_tid_address
  2.08    0.000294         146         2           ioctl
  1.99    0.000281         280         1           set_robust_list
  1.87    0.000264         132         2           rt_sigaction
  1.78    0.000252         126         2         2 statfs
  1.72    0.000243          81         3           brk
  1.36    0.000193         192         1           write
  1.32    0.000186          92         2         1 arch_prctl
  1.22    0.000172          86         2         2 access
  0.81    0.000114         113         1           prlimit64
  0.78    0.000110         109         1           rt_sigprocmask
------ ----------- ----------- --------- --------- ----------------
100.00    0.014131         148        95         5 total

次に ptrace のエントリーを削除した deny-ptrace.json を作る.そして docker run コマンドに --security-opt seccomp=deny-ptrace.json オプションを指定すると,strace コマンドを実行できなくなった.

$ diff -u default.json deny-ptrace.json
@@ -402,8 +402,7 @@
        {
            "names": [
                "process_vm_readv",
-               "process_vm_writev",
-               "ptrace"
+               "process_vm_writev"
            ],
            "action": "SCMP_ACT_ALLOW",
            "args": null,

$ docker run --rm -d -it --security-opt seccomp=deny-ptrace.json ubuntu:21.10
b78b00e8ce7b02b7635a19478fa089caeff1ebc85446ea4013e07696331ca9c6

$ docker exec -it b78b00e8ce7b /bin/sh

# uname -r
5.10.25-linuxkit

# apt-get -y update
# apt-get -y install strace

# strace ls
strace: test_ptrace_get_syscall_info: PTRACE_TRACEME: Operation not permitted
strace: ptrace(PTRACE_TRACEME, ...): Operation not permitted
strace: PTRACE_SETOPTIONS: Operation not permitted
strace: detach: waitpid(262): No child processes
strace: Process 262 detached

# strace -cw ls
strace: test_ptrace_get_syscall_info: PTRACE_TRACEME: Operation not permitted
strace: ptrace(PTRACE_TRACEME, ...): Operation not permitted
strace: PTRACE_SETOPTIONS: Operation not permitted
strace: detach: waitpid(266): No child processes
strace: Process 266 detached

seccomp と DockerSlim (docker-slim)

実際にプロファイルを作るときに必要最低限なシステムコールを洗い出すのは難しく,strace コマンドを使うこともできるけど,「DockerSlim (docker-slim)」を使うとお手軽にプロファイルを作ることができる.

github.com

「Docker/Kubernetes開発・運用のためのセキュリティ実践ガイド」を読んでいたら載っていた.「DockerSlim」は今度試す予定!

参考資料 : Introduction to Seccomp

seccomp を詳しく解説したスライドがあってとてもわかりやすかった💡後半は僕には難しかったけど...!

まとめ

コンテナワークロードのセキュリティ対策として,今回は「Docker と seccomp」を組み合わせて試した.プロファイルを編集してシステムコールを制限することができた.次は「Kubernetes と seccomp」を組み合わせて試すぞー!