Day2 Falcoコンテナセキュリティ – ルールのチューニング

By 清水 孝郎 - MAY 23, 2023

SHARE:

本文の内容は、2023年5月23日にNIGEL DOUGLAS が投稿したブログ(https://sysdig.com/blog/day-2-falco-container-security-tuning-the-rules/)を元に日本語に翻訳・再構成した内容となっております。

サイバーセキュリティの世界では、ノイズはDay2オペレーションに関連する重要な問題です。ノイズの複雑な性質と検出精度や誤検出への影響から、Falcoのようなツールを含め、検出ルールを作成する際に取り組むべき難しいトピックとなっています。この記事では、Falcoのコンテナセキュリティルールをチューニングしてノイズを除去するためのガイドラインを提供します。

検出精度と誤検知の間の緊張は業界で常に課題となっており、誤検知がない唯一のルールセットはルールがまったく存在しないルールセットである、とよく言われます。 誤検知を完全に回避するのは非現実的な目標かもしれませんが、誤検知の影響を最小限に抑え、ノイズを軽減するために従うことができるガイドラインがあります。

テストと検証

本番環境でルールを使用する前に、できるだけ多くの環境(異なるOSディストリビューション、カーネル、コンテナエンジン、オーケストレーター)で広範囲にテストするようにします。その好例が、AWSのEC2メタデータサービスへの疑わしいアウトバウンド接続を検出する機能です。

デフォルトでは、Falcoのこのルールは無効になっています – そしてそれには正当な理由があります!AWS EC2インスタンスでは、169.254.169.254はインスタンスに関するメタデータをフェッチするために使用される特別なIPです。特定のコンテナからこのIPへのアクセスを防ぐことが望ましいかもしれませんが、オペレータPodがAWS EC2メタデータサービスに接続する必要がある正当なケースもあります。

- rule: Contact EC2 Instance Metadata Service From Container
  desc: Detect attempts to contact the EC2 Instance Metadata Service from a container
  condition: outbound and fd.sip="169.254.169.254" and container and not ec2_metadata_containers
  output: Outbound connection to EC2 instance metadata service (command=%proc.cmdline pid=%proc.pid connection=%fd.name %container.info image=%container.image.repository:%container.image.tag)
  priority: NOTICE
  enabled: FALSE
  tags: [network, aws, container, mitre_discovery, T1565]Code language: JavaScript (javascript)

検証について、FalcoはどのワークロードがEC2メタデータサービスと通信する必要があるかを本質的に知ることができないため、何を “疑わしい “とみなすべきかを知ることができません。アイデアとしては、テスト環境でこのルールを有効にし、どのような検出が発生するかを確認し、今後の検出から除外する必要があるものを知ることです。このように、大規模な本番環境でやみくもにルールを有効にする前に、テストと検証を行うことで、ノイズの低減に大きく貢献することができます。

優先順位に基づくフィルタリング

ERRORまたはCRITICALを優先して初めてルールをデプロイすることは避けてください。DEBUGやINFOから始めて、何が起こるか確認し、ノイズが少ないようであれば値を上げてください。優先順位の低いルールは、出力パイプラインの異なるステージで簡単にフィルタリングできるため、夜中にセキュリティオペレーションセンターチームを目覚めさせる危険はありません。

- rule: reading sensitive file with incorrect priority
  desc: Detects when the file secret.env is read
  condition: evt.type = open and fd.name = /etc/secret.env
  output: "Reading of cryptographic symmetric key from environmental variable"
  priority: ERROR
  tags: [incorrect_priority, sensitive_file]Code language: JavaScript (javascript)


すべてのFalcoのルールは、ルール違反がどの程度深刻であるかを示すプライオリティを持っています。これは、私たちが syslog メッセージの重大度として知っているものと似ています。優先順位は、メッセージ/JSON出力/などに含まれます。

ルールに優先順位を割り当てるために使用される一般的なガイドラインは、次のとおりです:

  • ルールがファイルシステムなどの状態の書き込みに関連する場合、その優先順位はERRORです。
  • ルールが不正な状態の読み取り(機密ファイルの読み取りなど)に関連している場合、その優先順位はWARNINGです。
  • ルールが予期せぬ動作(コンテナ内で予期せぬシェルを起動する、予期せぬネットワーク接続を開くなど)に関連している場合、その優先順位は「NOTICE」です。
  • ルールが良い習慣に反する動作(予期しない特権付きコンテナ、機密性の高いマウントを持つコンテナ、rootとしての対話型コマンドの実行)に関連している場合、その優先順位はINFOになります。

タグの活用

ルールに付与したタグは、FalcoのgRPCやJSONの出力に含まれます。これは、優先順位を補完し、さらに柔軟な方法で Falco の出力をフィルタリングするために、それらを使用できることを意味します。良い例としては、関連するアラート通知を処理すべき適切なチームに対するタグを使用することが挙げられます。

- rule: Detect outbound connections to common miner pool ports
  desc: Miners typically connect to miner pools on common ports.
  condition: net_miner_pool and not trusted_images_query_miner_domain_dns
  enabled: FALSE
  output: Outbound connection to IP/Port flagged by https://cryptoioc.ch (command=%proc.cmdline pid=%proc.pid port=%fd.rport ip=%fd.rip container=%container.info image=%container.image.repository)
  priority: CRITICAL
  tags: [host, container, NETWORK, mitre_execution, T1496]Code language: PHP (php)

セキュリティオペレーションセンター(SOC)チームは、必ずしもすべてのアラート通知を見る必要がない場合があります。クリプトジャッキングの場合、SOCチームは、クリプトマイニングのバイナリがインストールまたは開始されたタイミングを知ることが望ましいかもしれません。そのため、そのマイナーを環境から削除することを検討することができるでしょう。一方、SOCチームはコンテナやKubernetesのネットワークアクティビティをコントロールできないかもしれません。

その代わりに、ネットワークエンジニアがネットワークアクティビティに関連する通知を受け取ることは理にかなっているかもしれません。上記のFalcoのルールの場合、ネットワークチームは、コンテナがどのIPアドレス、FQDN(Fully-Qualified Domain Name)、および/またはポート番号にegressトラフィックを実行したかを確認するでしょう。そして、ネットワークチームは、その Pod またはコンテナに関連するネームスペースにネットワークポリシーを適用して、接続をブロックすることができます。

(1)最も重要なアラートを最も関連性の高いチームに送信して対処してもらう。(2)すべてのアラートをすべてのチームにルーティングするのではなく、最も関連性の高いアラートのみをルーティングして対処してもらうことにより、各チームにとってのノイズを減らします。

インフラストラクチャーによって異なるルール

ステージング環境と本番環境など、インフラストラクチャーごとに異なるルールを作成する必要があるのは、それぞれのコンテキストに固有の違いや特定の要件があるためです。ステージング環境は、しばしば新機能やアップデートのテスト場として機能し、開発者は 自由に実験し、潜在的な問題を特定することができます。この場合、Falco ルールは、開発速度を妨げないように、より寛容なものとすることができ、より迅速な反復とフィードバックのサイクルを可能にします。

- rule: Disallowed SSH Connection
  desc: Detect any new ssh connection to a host other than those in an allowed group of hosts
  condition: (inbound_outbound) and ssh_port and not allowed_ssh_hosts
  enabled: false
  output: Disallowed SSH Connection (command=%proc.cmdline pid=%proc.pid connection=%fd.name user=%user.name user_loginuid=%user.loginuid container_id=%container.id image=%container.image.repository)
  priority: NOTICE
  tags: [host, container, network, mitre_cc, mitre_lateral_movement, T1021.004]Code language: JavaScript (javascript)

上記の Falco ルールファイルでは、SSH アクセスが許可されている特定の本番ホストを知る方法がないので、以下のマクロは  ssh_port を繰り返すだけで、実質的にすべてのホストからの ssh を許可しています。

- macro: allowed_ssh_hosts
  condition: ssh_port
- macro: ssh_port
  condition: fd.sport=22


Day 2 オペレーションの場合、ssh 接続が許可されるサーバーを列挙するために、このマクロをオーバーライドする必要がある場合がほとんどでしょう。たとえば、ssh接続が許可されるsshゲートウェイホストがあるかもしれません。条件は次のようなものです:

- macro: ssh_ProductionAllowList
  condition: (fd.sip="a.b.c.d" or fd.sip="e.f.g.h" intersects (ssh_hosts))Code language: JavaScript (javascript)


本番環境では、より高いレベルのセキュリティと安定性が求められるはずで、Falcoルールは、悪意ある活動や不正な活動を検知・防止するために、より厳格であるべきです。そのため、私たちは異なる環境に関連するマクロを変更します。このようにして、ルールは ステージングから本番環境までほぼ同じであることを保証しますが、マクロ はそれぞれのケースで多少ユニークであるべきです。

これらのルールとサポートするマクロは、IP、ネットマスク、および完全なドメイン名に対して接続情報を照合するために、 fd.*ip  および  fd.*ip.name  フィールドを使用する方法の一例です。前述のFalcoルールを使用するには、それを有効にし、 allowed_{source,destination}_{ipaddrs,networks,domains} に、自分の環境で意味のある値を入力する必要があります。

- list: allowed_outbound_destination_ipaddrs
  items: ['"127.0.0.1"', '"8.8.8.8"']
- list: allowed_outbound_destination_networks
  items: ['"127.0.0.1/8"']
- list: allowed_outbound_destination_domains
  items: [google.com, www.yahoo.com]Code language: CSS (css)

したがって、各環境に関連する固有の特性や潜在的なリスクを考慮し、効果的な監視と保護を確保するために、カスタマイズされたFalcoルールが必要です。

アップグレード計画

Falco コンテナセキュリティユーザは、アップグレードに関して、特に「Day2」オペレーションの観点か ら、様々な側面を慎重に検討する必要があります。

まず、Helmを使用することが、自動的に簡単にアップグレードとロールバックを行う最も安全な方法です。FalcoのHelmチャートは、DaemonSetを使ってKubernetesクラスター内のすべてのノードにFalcoを追加します。そして、デプロイされた各Falco Podは、自身のノードにドライバーをインストールしようとします。これは、syscall instrumentationのデフォルトの構成です。Helmの使用は、超迅速かつ信頼性が高いです。バージョン間で何か問題が発生した場合、数秒で簡単に以前のバージョンにロールバックすることができます。したがって、Day2 オペレーションで潜在的なダウンタイムを回避することができます。

次に、ルールのライフサイクル(インストール、アップデート)を管理するためのアウトオブボック スソリューションとして、Falcoctl が提供されています。その名が示すように、Falcoctlは、Falco管理者にとっていくつかの有用なタスクを実行できるCLIツールであり、その1つは、コンテナセキュリティチームが異なるソース(GitHub Audit Logging Services、AWS CloudTrail、Kubernetes Audit Logsなど)からイベント処理のための関連Falcoプラグインをスムーズにインストールできるようにすることです。

Falcoctl は、個人レポまたは共有コミュニティレポから、関連するダウンタイムを伴わ ず、自動的にルールをプルすることができます。既知の CI/CD テクニックを使用して、最新のルールを配布可能なオブジェクトにパック することができます。Falcoルールは、安定したバージョンにこだわる場合でも、複数のバージョンに柔軟に対応する場合でも、GitのパワーとOCIの標準を組み合わせることで、各プラットフォームに最も適したルールを選択的に取得することが可能です。さらに、デーモンとして実行することで、定期的にアーティファクトのリポジトリをチェックし、新しいバージョンを自動的にインストールする機能を提供します。

Indexes:
  - name: falcosecurity
    url: https://falcosecurity.github.io/falcoctl/index.yaml
Artifact:
  Install:
    Refs:
      - k8saudit:0.5.0
  Follow:
    every: 6h0m0s
    falcoVersions: http://localhost:8765/versions
    Refs:
      - k8saudit:-rules:0.5Code language: JavaScript (javascript)

この動作の設定は、 /etc/falcoctl/falcoctl.yamlでも確認できます。

Falco コンテナセキュリティパフォーマンスチューニング

Falco は通常、高頻度のデータソースで動作するため、パフォーマンスはルールの作成とデプロイを検討する上でもう一つの重要なトピックです。Falco をカーネルモジュールや eBPF プローブのようなシステムコールと一緒に使用している場合、 ルールセット全体が 1 秒間に数百万回評価されるかもしれません。このような頻度では、ルールのパフォーマンスが鍵となります。

タイトなルールセットを持つことは、Falco の CPU 使用率を抑制するための良い習慣であることは間違いありません。しかし、あなたが作成するすべての新しいルールがパフォーマンスに対して最適化されて いることを確認することも重要です。ルールのオーバーヘッドは、多かれ少なかれ、ルールの条件がすべての入力イベントに対して実行す る必要のあるフィールド比較の数に比例します。したがって、次のような単純な条件であれば、期待できるはずです:

proc.name=p1


これは、以下のような複雑な交差ルールよりもはるかに少ない CPU 使用量で済むはずです:

- macro: mount_info
  condition: (proc.args="" or proc.args intersects ("-V", "-l", "-h"))Code language: JavaScript (javascript)


したがって、ルールの最適化とは、ほとんどの一般的な状況において、Falcoエンジンが可能な限り少ない数の比較を実行することを要求するようにすることです。これらのルールに関連する CPU オーバーヘッドを削減するために、以下のような考慮事項 を推奨します:

  1. ルールは常にイベントタイプのチェックで開始すること
    Falcoは、あなたのルールがいくつかのイベントタイプにのみ制限されている場合を理解します。したがって、マッチするイベントを受け取ったときにのみ、そのルールを評価します。例えば、あなたのルールが evt.type=open で始まる場合、Falco は ‘open’ システムコールでないイベントに対しては、そのルールの評価を開始することすらありません。ルールにイベントタイプに関するチェックが含まれていない場合に警告チェックを実装 することは、無効なルールをプロダクションに送信することを避けるために重要です。
  2. Falco のconditions は、ソフトウェアプログラミングにおける ‘if’ ステートメントのように機能します
    Falco ルールは、何かが失敗するまで左から右へ評価されます。条件を早く失敗させればさせるほど、その条件が完了するまでに必要な作業は少なくなります。ルールの範囲を制限する簡単な方法を見つけるようにしましょう。
  3. 重い複雑なルールは右へプッシュする
    前のポイントで説明した積極的な比較から始める必要があり、以前に失敗する可能性が高かったルールを含めた後でのみ、重くて複雑なルール ロジックをプッシュします。 複雑なルール ロジックの例には、ルールの最後に属する長い例外リストが含まれます。
  4. 複数の比較の代わりに、複数の値演算子を使用する
    値演算子には、 in, and, pmatchのようなものがあります。
    多重比較を記述すると、 evt.type  evt.type=mkdiratのような形になります。
     evt.type in (mkdir, mkdirat)のように、値演算子で記述する方がパフォーマンス的に優れています。
  5. ルールはなるべく小さくする
    これはルールの処理を高速化するだけでなく、Day2オペレーションの観点から、ルールの可読性と保守性を確保するためです。

避けられない例外を想定する

優れたルールは、既知および未知の例外を考慮し、読みやすく、モジュール化され、容易に拡張できる方法で設計されています。例えば、デフォルトのルールセット Write Below RPM Database ルールを見てみましょう:

- rule: Write below rpm database
  desc: an attempt to write to the rpm database by any non-rpm related program
  condition: >
    fd.name startswith /var/lib/rpm and open_write
    AND NOT rpm_procs
    AND NOT ansible_running_python
    AND NOT python_running_chef
    AND NOT exe_running_docker_save
    AND NOT amazon_linux_running_python_yum
    AND NOT user_known_write_rpm_database_activities
  output: "Rpm database opened for writing by a non-rpm program (command=%proc.cmdline pid=%proc.pid file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline container_id=%container.id image=%container.image.repository)"
  priority: ERROR
  tags: [host, container, filesystem, software_mgmt, mitre_persistence, T1072]Code language: JavaScript (javascript)


既知の例外がマクロ( (rpm_procsansible_running_pythonなど)としてルールに含まれていますが、ルールにはマクロ(user_known_write_rpm_database_activities) も含まれており、オーバーライド機構によってユーザーが独自の例外を追加できることができます。

まとめ

まとめとして、Falco は、Day2 オペレーションの一般的な問題に対処するためにうまく設計され たランタイムセキュリティツールを提供します。ルールベースのエンジンを提供することで、Falcoのセキュリティチームは、ダイナミックなクラウドネイティブ環境においてリアルタイムで脅威を検知し、対応するためのセキュリティポリシーを定義し、調整することができるようになります。

Falcoの優先度ベースのフィルタリングは、セキュリティチームが重大なセキュリティ違反とそれほど重要でない違反とを区別し、アラートの疲労を軽減し、最も重要な問題に集中することを可能にします。タグを活用することで、ネットワークおよびセキュリティチーム内のノイズをさらに減らし、関連するアラートを簡単に識別して優先順位をつけることができるようになります。

デプロイ前のルールのテストと検証も重要で、ルールが効果的であること、組織のセキュリティポリシーに合致していることを確認します。最後に、ルールに例外を適用することが必要です!すべての環境が同じようにビルドされたわけではないので、環境のユニークな特性に基づいて例外を作ることを許可する必要があります。