前回は bcc を使ってコンテナ内の execve を取得する方法について書きました。
最近 falco などを使い、Kubernetes の Pod の安全性を高めているのですが、そのルールを定義するのが難しいと感じていました。
例えば NIST の Application Container Security Guide の 4.4.4 節では次のイベントが発生することを検知できるようにしたほうが良いと書かれています。
- Invalid or unexpected process execution,
- Invalid or unexpected system calls,
- Changes to protected configuration files and binaries,
- Writes to unexpected locations and file types,
- Creation of unexpected network listeners,
- Traffic sent to unexpected network destinations, and
- Malware storage or execution.
ref : https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-190.pdf
「期待していないプロセス」「期待していない通信先」などと言われても列挙するのは難しいと思います。
そこで、BPF を使って特定のシステムコールを取得すれば、ある程度ホワイトリスト化できるのではないかと思い、 cxray というツールを作りはじめました。
README にあるように、バイナリを実行するだけで、そのホスト上のコンテナで発生した execve と open からプロセスやファイル名を取得し、JSON と出力するようにしています。
$ sudo ./cxray > log.json
$ docker run --rm -it alpine:latest sh
/ # id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
/ # uname -a
Linux 5af89d05295b 5.0.0-37-generic #40~18.04.1-Ubuntu SMP Thu Nov 14 12:06:39 UTC 2019 x86_64 Linux
/ # cat /etc/passwd
root:x:0:0:root:/root:/bin/ash
...
$ cat log.json
{"data":{"container_id":"5af89d052","event":{"syscall":"execve","data":{"argv":"","comm":"","pid":"12555","ret":"0","uid":"0","user":"root"}}},"level":"info","msg":"execve","time":"2019-12-24T12:45:36Z"}
{"data":{"container_id":"5af89d052","event":{"syscall":"execve","data":{"argv":"","comm":"/usr/bin/id","pid":"12605","ret":"0","uid":"0","user":"root"}}},"level":"info","msg":"execve","time":"2019-12-24T12:45:37Z"}
{"data":{"container_id":"5af89d052","event":{"syscall":"execve","data":{"argv":"-a","comm":"/bin/uname","pid":"12608","ret":"0","uid":"0","user":"root"}}},"level":"info","msg":"execve","time":"2019-12-24T12:45:39Z"}
{"data":{"container_id":"5af89d052","event":{"syscall":"execve","data":{"argv":"/etc/passwd","comm":"/bin/cat","pid":"12609","ret":"0","uid":"0","user":"root"}}},"level":"info","msg":"execve","time":"2019-12-24T12:45:41Z"}
{"data":{"container_id":"5af89d052","event":{"syscall":"open","data":{"comm":"cat","fname":"/etc/passwd","pid":"14134","ret":"3","uid":"0"}}},"level":"info","msg":"open","time":"2019-12-25T02:02:27Z"}
開発環境やテスト環境である程度のイベントログを作成し、そこから falco のルールにしたりすることを想定しています。
これ自体を監視として入れる、というのもあるかな、と思います。
今はまだ execve
と open
しか取得できていませんが、今後 tcp_v4_connect
などの追加で HTTP リクエストを検出したりする予定です。