午前2時、アラートで目が覚めた
Kubernetesクラスターは正常に稼働していた。Prometheus + GrafanaはCPU、メモリに異常なし。クラッシュしているPodもない。しかし決済システムの処理が不思議なほど遅かった——通常のメトリクスでは説明できない遅さだった。
40分かけてログを掘り起こした結果、原因が判明した。あるコンテナが30秒ごとに外部インターネットへcurlプロセスを実行していたのだ。アプリケーションのコードではない。設定されたcronジョブでもない。イメージがいつの間にか侵害されていたのだった。
当時、Prometheus + Grafanaは15台のサーバーを監視していた。メトリクスは充実していて、ダッシュボードも綺麗だった。インフラのメトリクス監視としては申し分なかった——しかしsyscallレベルでコンテナの内部で何が起きているかは完全に盲点だった。そのとき、Falcoを導入することを決意した。
Falcoとは何か、そして既存ツールとの違い
FalcoはSysdigが開発し、現在はCNCFのgraduatedプロジェクトだ。その差別化ポイントはブランドではなく、どこを見るかにある。メトリクスやログではなく、Linuxカーネルのsyscallレイヤーを直接監視する。コンテナが行うすべての操作——ファイルのオープン、プロセスの生成、ネットワーク接続——はすべてここを通過する。
Prometheus + Grafanaが「システムはどう動いているか」という問いに答えるとすれば、Falcoは「私のコンテナの中で誰が何をしているか」という問いに答える。
動作の仕組み
FalcoがKernelにフックする方法は2つある:
- カーネルモジュール:カーネルに直接モジュールをロードする——パフォーマンスは高いが、特別な権限が必要でカーネルバージョンに依存する。
- eBPFプローブ:eBPF(extended Berkeley Packet Filter)を使用する——より安全で、カーネルモジュール不要。現代のKubernetesに推奨される選択肢。
仕組みはシンプルだ。syscallをリアルタイムで読み取り、YAMLで定義されたルールのセットと照合し、マッチしたらアラートを発する。デフォルトのルールは最も一般的な危険なパターンをカバーしている:コンテナ内のシェル、/etc/shadowの読み取り、機密パスのマウント、特権昇格など。
HelmでKubernetesにFalcoをインストールする
前提条件
- Kubernetes cluster (1.19+)
- Helm 3.x
- cluster-admin権限のあるkubectl
ステップ1:Helmリポジトリを追加してインストール
# Falcoリポジトリを追加
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update
# 専用のネームスペースを作成
kubectl create namespace falco
# eBPFドライバーでFalcoをインストール(推奨)
helm install falco falcosecurity/falco \
--namespace falco \
--set driver.kind=ebpf \
--set falcosidekick.enabled=true \
--set falcosidekick.webui.enabled=true
フラグfalcosidekick.enabled=trueはFalcosidekickも一緒にインストールする——FalcoのアラートをSlack、Telegram、PagerDuty、Elasticsearchなど50以上のアウトプット先に転送するフォワーダーだ。これを省略すると、手動でログを読む以外にアラートを受け取る手段がなくなる。
ステップ2:Podの稼働確認
kubectl get pods -n falco
# 期待される出力:
# NAME READY STATUS RESTARTS
# falco-6xk9p 2/2 Running 0
# falco-falcosidekick-7d8f9c-abc12 1/1 Running 0
# falco-falcosidekick-ui-5f6b8d-xyz34 1/1 Running 0
FalcoはDaemonSetとして動作する——各ノードに1つのPodが配置され、クラスター全体がカバーされる。
ステップ3:最初のアラートを確認する
# FalcoのリアルタイムログをTail
kubectl logs -n falco -l app.kubernetes.io/name=falco -f
# アラートをトリガーしてみる:実行中のコンテナにexec
kubectl exec -it <pod-name> -- /bin/sh
# Falcoのログに即座に表示される:
# Notice A shell was spawned in a container with an attached terminal
# (user=root shell=sh parent=runc cmdline=sh container_id=abc123...)
コンテナにexecするだけでアラートがトリガーされる。「Terminal shell in container」は最も疑わしい兆候の一つだ——開発者がデバッグのためにやることもあるが、攻撃者も侵入後に同じことをする。
自分の環境に合わせたルールのカスタマイズ
Falcoのデフォルトルールはかなりノイジーだ——チームが時々デバッグのためにコンテナにexecする場合、誤検知が多発する。チューニングが必要だ。
カスタムルールの作成
custom-rules.yamlファイルを作成する:
customRules:
custom-rules.yaml: |-
# 'dev'ネームスペースのコンテナへのexecはアラートしない
- rule: Terminal shell in container
condition: >
spawned_process
and container
and shell_procs
and proc.tty != 0
and not container.image.repository in (trusted_images)
and not k8s.ns.name in (dev, staging)
desc: A shell was spawned in a container
output: >
Shell spawned in production container
(user=%user.name container=%container.name image=%container.image.repository
pod=%k8s.pod.name ns=%k8s.ns.name)
priority: WARNING
tags: [shell, mitre_execution]
# 新しいルール:暗号通貨マイナーを検知
- rule: Outbound connection to known crypto mining pool
desc: Detect connection to cryptocurrency mining pools
condition: >
outbound
and fd.sip.name in (mining_pool_domains)
output: >
Crypto mining connection detected
(pod=%k8s.pod.name image=%container.image.repository
dest=%fd.sip.name:%fd.sport)
priority: CRITICAL
tags: [network, cryptomining]
# カスタムルールを適用
helm upgrade falco falcosecurity/falco \
--namespace falco \
--set driver.kind=ebpf \
--set falcosidekick.enabled=true \
-f custom-rules.yaml
ルールが読み込まれているか確認
# Falcoがルールを正常に読み込んでいるか確認、シンタックスエラーがないこと
kubectl logs -n falco -l app.kubernetes.io/name=falco | grep -E "(rule|error|warn)" | head -20
FalcoをSlackまたはTelegramに接続する
Falcosidekickは50以上のアウトプット先をサポートしている。Slackの設定が最も手軽だ:
helm upgrade falco falcosecurity/falco \
--namespace falco \
--set driver.kind=ebpf \
--set falcosidekick.enabled=true \
--set falcosidekick.config.slack.webhookurl="https://hooks.slack.com/services/YOUR/WEBHOOK" \
--set falcosidekick.config.slack.minimumpriority="warning"
これにより、コンテナ内でシェルが起動したとき、誰かが/proc/*/memにアクセスしたとき、あるいは/etc/passwdに書き込みがあったとき——Slackにすぐ通知が来る。アラートにはコンテキストが十分含まれている:Pod名、ネームスペース、イメージ、ユーザー、コマンドライン。
Falcosidekick UIを確認する
# ダッシュボードを確認するためにPort-forward
kubectl port-forward svc/falco-falcosidekick-ui 2802:2802 -n falco
# ブラウザを開く: http://localhost:2802
インシデント調査のときによくこのUIを開く。アラートのタイムライン、priority(Critical/Warning/Notice)・ネームスペース・ルールでのフィルタリング——見れば何が起きているか、いつからかがすぐわかる。
最初から有効にすべきルール
数百のルールが同梱されているが、すべてが同じ重要度というわけではない。本番環境で特に有用だと感じたものを以下に挙げる:
- Write below etc:
/etcに書き込むプロセス——コンテナ内では極めて異常な動作。 - Read sensitive file untrusted:
/etc/shadow、/etc/sudoers、SSH秘密鍵の読み取り。 - Netcat Remote Code Execution in Container:リバースシェル作成に使われるnetcat/ncat。
- Contact K8S API Server From Container:コンテナがKubernetes APIを直接呼び出す——コンテナエスケープの可能性がある。
- Privilege Escalation Using Sudo:コンテナ内のsudoは明らかなレッドフラグ。
まとめ
あの午前2時の事件の後、翌週にはFalcoをクラスター全体にデプロイした。それ以降、さらに2件の問題を検知した。1件はdeserializationの脆弱性を通じてリバースシェルをインジェクトされたコンテナ、もう1件は開発者がうっかりイメージにクレデンシャルをハードコードしてしまいscript kiddiesにスキャンされたケースだ。
FalcoはPrometheusやGrafanaに取って代わるものではない——メトリクスベースの監視では見えない盲点を埋めるものだ。メトリクスはシステムが遅いと教えてくれる。Falcoはなぜ遅いのかを教えてくれる——そしてその答えがパフォーマンス問題ではなく、セキュリティインシデントであることもある。
本番ワークロードを実行しているクラスターにランタイムセキュリティ監視がまだない場合、これはインシデントが起きてからではなく、起きる前に導入すべきものだ。

