Falco:DockerコンテナへのリアルタイムDash侵入検知とSlack通知の設定

Docker tutorial - IT technology blog
Docker tutorial - IT technology blog

以前、ECサービスのプロジェクトでマイクロサービスをデプロイしていたとき、あるコンテナがスパムメール送信に悪用されていることを発見するまで2日近くかかったことがある。アプリのログはまったく正常、CPUも異常なし——しかしコンテナは見知らぬIPへの接続を繰り返し開いていた。あのときFalcoがあれば、アラートは最初の1分から届いていたはずだ。

Falcoはコンテナのシステムコールをリアルタイムで追跡する——アプリのログでもCPU/RAMメトリクスでもなく、カーネルへの一つひとつの呼び出しを監視する。ハードニング設定やセキュリティのベストプラクティス(静的な状態を確認するだけのもの)とは異なり、Falcoは今まさに起きている動作を監視する:どのファイルが盗み読みされているか、どの不審なプロセスがスポーンされているか、どの外部接続が開かれているか。FalcoはCNCFのグラデュエイテッドプロジェクト——KubernetesやPrometheusと同じ成熟度レベルにある。

5分でFalcoを起動する

最も手軽な試し方は、userspace driverを使ってDockerでFalcoを実行することだ——カーネルモジュールのインストールが不要で、ローカルマシンや開発環境でのテストに適している:

# userspaceモードでFalcoを実行(カーネルモジュール不要)
docker run --rm -it \
  --privileged \
  -v /var/run/docker.sock:/host/var/run/docker.sock \
  -v /proc:/host/proc:ro \
  -v /boot:/host/boot:ro \
  -v /lib/modules:/host/lib/modules:ro \
  -v /usr:/host/usr:ro \
  -v /etc:/host/etc:ro \
  falcosecurity/falco-no-driver:latest

Starting internal webserver, listening on port 8765という行が表示されたらFalcoが起動している。別のターミナルを開いてアラートをトリガーする:

# 実行中のコンテナにシェルでアクセス — Falcoが即座に検知
docker exec -it $(docker ps -q | head -1) /bin/sh

Falcoのログがすぐに表示される:

Warning evt_type=execve user=root container.id=abc123 container.name=my-app \
  proc.name=sh proc.cmdline="sh" \
  rule="Terminal shell in container" \
  output="A shell was spawned in a container with an attached terminal"

Falcoをホストに直接インストールしてProduction運用する

本番運用で使うなら、コンテナには入れずホストに直接Falcoをインストールすること。カーネルモジュールまたはeBPFがOSの最低レベルでシステムコールをキャプチャするため、コンテナの再起動やイメージ変更の影響を受けない。

Ubuntu / Debian

# Falcoリポジトリを追加
curl -fsSL https://falco.org/repo/falcosecurity-packages.asc | \
  sudo gpg --dearmor -o /usr/share/keyrings/falco-archive-keyring.gpg

echo "deb [signed-by=/usr/share/keyrings/falco-archive-keyring.gpg] \
  https://download.falco.org/packages/deb stable main" | \
  sudo tee /etc/apt/sources.list.d/falcosecurity.list

sudo apt-get update && sudo apt-get install -y falco

インストーラーがどのドライバーを使うか質問する:

  • Kernel module:高速で安定している——カーネルアップグレード後に再ビルドが必要
  • eBPF:より現代的でアップグレード後の再ビルドが不要。カーネル ≥ 4.14 が必要
  • Modern eBPF:カーネル ≥ 5.8 なら最善の選択。モジュール不要で組み込み済み
# Falcoを有効化して起動
sudo systemctl enable --now falco
sudo systemctl status falco

# リアルタイムでログを監視
sudo journalctl -fu falco

ルール構造を理解する——検知ロジックの核心

RuleのYAMLが、Falcoが何を検知するかを正確に定義する場所だ。各ルールには4つの主要コンポーネントがある:condition(いつトリガーするか)、output(アラートの内容)、priority(深刻度)、tags(MITRE ATT&CKによる分類):

# Falcoルールの構造
- rule: Read sensitive file untrusted
  desc: 信頼されていないプロセスが機密ファイルを読み取ることを検知
  condition: >
    sensitive_files and open_read
    and not proc.name in (trusted_binaries)
    and not container.image.repository in (trusted_images)
  output: >
    Sensitive file opened for reading
    (user=%user.name command=%proc.cmdline
     file=%fd.name container_id=%container.id
     image=%container.image.repository)
  priority: WARNING
  tags: [filesystem, mitre_credential_access]

よく使われるoutput変数:

  • %container.id — 違反したコンテナのID
  • %container.image.repository — 悪用されているイメージ
  • %proc.cmdline — その時点で実行されているコマンド
  • %fd.rip:%fd.rport — ネットワーク接続の宛先IPとポート

実際のユースケース向けにカスタムルールを作成する

Falcoのデフォルトルールはかなり汎用的だ——実際のプロダクション環境ではカスタマイズが必要になる。/etc/falco/rules.d/custom_rules.yamlを作成すると、Falcoは起動時にこのディレクトリ内の全ファイルを自動でロードする:

# ホワイトリストにないポートへのコンテナのアウトバウンド接続を検知
- rule: Unexpected outbound connection
  desc: 予期しないポートへのアウトバウンド接続をコンテナが開いている
  condition: >
    outbound and container
    and not fd.sport in (80, 443, 3306, 5432, 6379, 27017)
    and not proc.name in (curl, wget, apt, pip, npm)
  output: >
    Unexpected outbound (container=%container.name
    dest=%fd.rip:%fd.rport proto=%fd.l4proto
    command=%proc.cmdline)
  priority: NOTICE

# 実行中のコンテナでのパッケージインストールを検知
- rule: Package manager in running container
  desc: productionコンテナでapt/yum/pipが実行されている——侵害の兆候
  condition: >
    spawned_process and container
    and proc.name in (apt, apt-get, yum, dnf, pip, pip3, npm, yarn)
  output: >
    Package manager detected (command=%proc.cmdline
    container=%container.name
    image=%container.image.repository)
  priority: ERROR

FalcosidekickでSlack通知を統合する

Falco自体はログを記録するだけだ。Slackにアラートを送りたい場合——PagerDuty、Elasticsearch、webhookなど50以上の宛先も含め——Falcosidekickが必要だ。これはFalcoからイベントを受け取って転送する軽量なサイドカーだ。Docker Composeでセットアップする:

# docker-compose.yml
services:
  falco:
    image: falcosecurity/falco-no-driver:latest
    privileged: true
    volumes:
      - /var/run/docker.sock:/host/var/run/docker.sock
      - /proc:/host/proc:ro
      - /boot:/host/boot:ro
      - /lib/modules:/host/lib/modules:ro
      - /usr:/host/usr:ro
      - /etc:/host/etc:ro
      - ./falco.yaml:/etc/falco/falco.yaml
    depends_on:
      - falcosidekick

  falcosidekick:
    image: falcosecurity/falcosidekick:latest
    environment:
      - SLACK_WEBHOOKURL=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
      - SLACK_CHANNEL=#security-alerts
      - SLACK_MINIMUMPRIORITY=warning
      - CUSTOMFIELDS_ENVIRONMENT=production
      - CUSTOMFIELDS_TEAM=devops
    ports:
      - "2801:2801"
      - "2802:2802"  # Web UI

次にFalcoをFalcosidekickに接続する——falco.yamlに追加する:

http_output:
  enabled: true
  url: "http://falcosidekick:2801/"
  user_agent: "falcosecurity/falco"

json_output: true
json_include_output_property: true
# スタックを起動
docker compose up -d

# テストトリガー: コンテナにシェルアクセス → 数秒でSlackにアラートが届く
docker exec -it some-container bash

Slackでの表示はこのようになる:

[WARNING] Terminal shell in container
Container : my-webapp (id: abc123def456)
Image     : nginx:latest
Command   : bash
User      : root
Host      : prod-server-01
Time      : 2024-01-15 14:32:11 UTC

実際の運用経験から学んだTips

Falcoはメモリリークを直接デバッグするわけではない——ただし、早期に症状を検知する:メモリをダンプするための不審なプロセスのスポーンや、コンテナが/tmpに異常な速度で書き込むケースなどだ。そこから根本原因をトレースバックする方が、ログを1行ずつ読むよりもはるかに早い。

Falcoをproductionでチューニングした後の実践的なポイント:

  • WARNING以上のpriorityから始める:Falcoにはデフォルトルールが数百ある——フィルタなしで実行するとすぐにアラートが溢れる。まずSLACK_MINIMUMPRIORITY=warningを設定してから、徐々に調整していく。
  • 信頼できるイメージを最初からホワイトリストに登録する:社内レジストリのイメージは独自の権限が必要なことが多い。trusted_imagesマクロを早めに作成してfalse positiveを防ぎ、チームの疲弊を避けよう。
  • IDではなくコンテナ名を使う:コンテナIDは再起動のたびに変わる。container.nameやラベルでフィルタする方がはるかに安定している。
  • Falcosidekick Web UI:ポート2802のダッシュボードが非常に便利だ——リアルタイムでイベントを確認し、priorityでフィルタして、最もアラートを発生させているコンテナをすばやく特定できる。
# 最も頻繁にトリガーされているルールを確認(priorityのチューニング用)
sudo journalctl -u falco --since "1 hour ago" | \
  grep -oP 'rule="[^"]+"' | sort | uniq -c | sort -rn | head -20

# Falcoのヘルスチェック
curl -s http://localhost:8765/healthz
# {"status": "healthy"}

ファイアウォールとネットワークポリシーがネットワークフローを保護する——Falcoは内側を保護する:実行中のコンテナ内の各プロセスの動作だ。コンテナ管理にPortainerを組み合わせ、ランタイムの動作監視にFalcoを使えば、高価な商用ソフトウェアなしに堅固なセキュリティレイヤーが構築できる。

Share: