kakakakakku blog

Weekly Tech Blog: Keep on Learning!

Kubernetes と Falco を組み合わせて脅威検出に入門する

Kubernetes でコンテナワークロードの脅威検出として使える「Falco」に入門する.CNCF (Cloud Native Computing Foundation) で Incubating に位置しているプロジェクトで,今回は実際に Falco を使って Pod に対する操作(振る舞い)を検出したり,独自ルールを作る.Falco はコンテナに限らず,ホスト側のプロセスも監視できる.

falco.org

インストールをする 🦅

以下の検証環境を使う.ドキュメントに書いてある 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

falco.org

/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_idimage など,詳細情報も確認できる.

  • 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 は他にも多くのフィールドをサポートしている.

falco.org

- 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
# 

すると期待した通りに tagpod_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_processcontainer など,簡易的な表現になっていて,これは 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 の紹介が載っていて参考になった.