Kubernetes でコンテナワークロードの脅威検出として使える「Falco」に入門する.CNCF (Cloud Native Computing Foundation) で Incubating に位置しているプロジェクトで,今回は実際に Falco を使って Pod に対する操作(振る舞い)を検出したり,独自ルールを作る.Falco はコンテナに限らず,ホスト側のプロセスも監視できる.
インストールをする 🦅
以下の検証環境を使う.ドキュメントに書いてある Ubuntu の手順をそのまま使って,ワーカーノードに簡単に Falco v0.31.1 をインストールできた.また Helm を使って Kubernetes 上に Falco を DaemonSet としてインストールをする選択肢もある.Falco は日本語ドキュメントがとても充実しててイイ✨
- Kubernetes v1.23.0
- ワーカーノード : Ubuntu 20.04.3 LTS
node01 $ curl -s https://falco.org/repo/falcosecurity-3672BA8F.asc | apt-key add - node01 $ echo "deb https://download.falco.org/packages/deb stable main" | tee -a /etc/apt/sources.list.d/falcosecurity.list node01 $ apt-get update -y node01 $ apt-get -y install linux-headers-$(uname -r) node01 $ apt-get install -y falco node01 $ systemctl start falco node01 $ systemctl status falco
/etc/falco
を確認すると falco.yaml
(設定ファイル)や falco_rules.yaml
(ルール)や falco_rules.local.yaml
(独自ルール)など Falco 関連のファイルがあった.
node01 $ ls -l /etc/falco total 200 -rw-r--r-- 1 root root 12400 Mar 9 17:20 aws_cloudtrail_rules.yaml -rw-r--r-- 1 root root 11384 Mar 9 17:20 falco.yaml -rw-r--r-- 1 root root 1136 Mar 9 17:20 falco_rules.local.yaml -rw-r--r-- 1 root root 133017 Mar 9 17:20 falco_rules.yaml -rw-r--r-- 1 root root 27287 Mar 9 17:20 k8s_audit_rules.yaml drwxr-xr-x 2 root root 4096 Apr 16 12:14 rules.available drwxr-xr-x 2 root root 4096 Mar 9 17:42 rules.d
動作確認をする 🦅
まず,動作確認をする.今回は Pod(コンテナ)に対してシェル接続が発生したことを検出する.運用上必要になる場面以外では不正な操作の可能性があり,検出できるのは便利だと思う.さっそく kubectl run
コマンドを使って nginx Pod を起動して,kubectl exec
コマンドを使って Pod にシェル接続をする.
controlplane $ kubectl run nginx --image nginx:1.21 pod/nginx created controlplane $ kubectl exec -it nginx -- sh #
syslog を確認すると A shell was spawned in a container with an attached terminal
という振る舞いが検出されている.container_id
や image
など,詳細情報も確認できる.
container_id=aaee21e42016
image=docker.io/library/nginx
node01 $ grep falco /var/log/syslog (中略) Apr 16 14:00:00 node01 falco: 14:00:00.000000000: Notice A shell was spawned in a container with an attached terminal (user=kc-internal user_loginuid=-1 nginx (id=aaee21e42016) shell=sh parent=runc cmdline=sh terminal=34817 container_id=aaee21e42016 image=docker.io/library/nginx)
設定ファイルを確認する 🦅
まず /etc/falco/falco.yaml
を確認すると Falco で検出した結果を syslog に出力する設定になっている.
# Send information logs to stderr and/or syslog Note these are *not* security # notification logs! These are just Falco lifecycle (and possibly error) logs. log_stderr: true log_syslog: true
次に /etc/falco/falco_rules.yaml
を確認すると,A shell was spawned in a container
からはじまる今回検出された振る舞いがルールとして設定されている.
- rule: Terminal shell in container desc: A shell was used as the entrypoint/exec point into a container with an attached terminal. condition: > spawned_process and container and shell_procs and proc.tty != 0 and container_entrypoint and not user_expected_terminal_shell_in_container_conditions output: > A shell was spawned in a container with an attached terminal (user=%user.name user_loginuid=%user.loginuid %container.info shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline terminal=%proc.tty container_id=%container.id image=%container.image.repository) priority: NOTICE tags: [container, shell, mitre_execution]
ルールを一部変更する 🦅
検証のため /etc/falco/falco_rules.yaml
を直接変更して,output
として tag=%container.image.tag
(コンテナイメージタグ)と pod_name=%k8s.pod.name
(Pod 名)を追加する.以下のドキュメントを読むと,Falco は他にも多くのフィールドをサポートしている.
- rule: Terminal shell in container desc: A shell was used as the entrypoint/exec point into a container with an attached terminal. condition: > spawned_process and container and shell_procs and proc.tty != 0 and container_entrypoint and not user_expected_terminal_shell_in_container_conditions output: > A shell was spawned in a container with an attached terminal (user=%user.name user_loginuid=%user.loginuid %container.info shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline terminal=%proc.tty container_id=%container.id image=%container.image.repository tag=%container.image.tag pod_name=%k8s.pod.name) priority: NOTICE tags: [container, shell, mitre_execution]
Falco を再起動して,もう一度 kubectl exec
コマンドを使って Pod にシェル接続をする.
node01 $ systemctl restart falco controlplane $ kubectl exec -it nginx -- sh #
すると期待した通りに tag
と pod_name
も確認できるようになった.
tag=1.21
pod_name=nginx
node01 $ grep falco /var/log/syslog (中略) Apr 16 14:00:00 node01 falco: 14:00:00.000000000: Notice A shell was spawned in a container with an attached terminal (user=kc-internal user_loginuid=-1 nginx (id=aaee21e42016) shell=sh parent=runc cmdline=sh terminal=34817 container_id=aaee21e42016 image=docker.io/library/nginx tag=1.21 pod_name=nginx)
デフォルトマクロ 🦅
Falco ルールの condition
には条件が書いてある.今回だと spawned_process
や container
など,簡易的な表現になっていて,これは Falco の「デフォルトマクロ」と言う.実際に /etc/falco/falco_rules.yaml
を確認すると spawned_process
(新規プロセスが生成された)や container
(コンテナオブジェクトである)というよく使う条件がプリセットされている.
- macro: spawned_process condition: evt.type in (execve, execveat) and evt.dir=< - macro: container condition: (container.id != host)
独自ルールを作る 🦅
検証のため,簡単な独自ルールを作る.今回は Pod 上で mkdir
コマンドを使って「新規ディレクトリを作ったこと」を検出する.以下のルールを /etc/falco/falco_rules.local.yaml
に追加した.
- rule: mkdir_in_container desc: mkdir_in_container condition: container and mkdir output: mkdir_in_container priority: NOTICE tags: [container, shell]
Falco を再起動して,もう一度 kubectl exec
コマンドを使って Pod にシェル接続をしてから mkdir
コマンドを実行した.
node01 $ systemctl restart falco controlplane $ kubectl exec -it nginx -- sh # mkdir falco #
すると,簡単ではあるけど,期待した通りに mkdir
コマンドの実行を検出できた.
node01 $ grep falco /var/log/syslog (中略) Apr 16 14:00:00 node01 falco: 14:00:00.000000000: Notice mkdir_in_container
まとめ
Kubernetes でコンテナワークロードの脅威検出として使える「Falco」を試した.今回はお手軽に Pod への「シェル接続」と「mkdir
コマンドの実行」を検出した.他にも「yum
などのパッケージマネージャの実行」や「ホスト側に危険性のあるディレクトリのマウント」などを検出できたりもする.「Docker/Kubernetes 開発・運用のためのセキュリティ実践ガイド」 にも Falco の紹介が載っていて参考になった.