FalcoでKubernetesのセキュリティモニタリング

はじめに

最近のWEBアプリケーションは、クラウド環境上にLinuxコンテナクラスタとしてデプロイすることが多くなってきました。 Linuxコンテナクラスタを管理するツールとして、Kubernetesが大変人気があります。 Kubernetesを使うと、設定ファイルの記述通りにコンテナクラスタが生成され、その状態が維持されるので、WEBアプリケーションの管理が容易になります。 その一方で、このような環境では数多くのコンテナが動的に生成、破棄されるので、セキュリティのモニタリングやインシデント検知が非常に難しくなってしまいます。

オープンソースのセキュリティ監視ツールであるFalcoは、Kubernetesとシームレスに統合できるため、クラウド上のWEBアプリケーションのセキュリティモニタリングに非常に適しています。 FalcoはLinuxカーネルのシステムコールを監視し、あらかじめ定義したルールに基づき、不正なアクティビティを検知します。 Falcoの監視と通知は、リアルタイムで行われるため、セキュリティインシデントに対する迅速な対応が可能となり、攻撃や侵入の検出に役立ちます。

今回、Falcoの仕組みやデプロイ方法、どのようなアクティビティが検出可能かなどについて調査を行いましたので、このブログで紹介したいと思います。

Falcoの概要

Falcoの仕組みと特徴

FalcoはLinux OS向けのランタイムセキュリティツールです。 システム上での異常なアクティビティや潜在的なセキュリティリスクをリアルタイムで検知し、警告するように設計されています。 その中核は、カーネル内でのシステムコール監視モジュールと、監視ルールに基づいて異常なイベントを検知するエージェント、さらに外部への通知を行うFalcosidekickエージェントからなっています。

以下がその仕組みと特徴です。

  • Falcoは、Linuxカーネルモジュールまたはebpfモジュールを用い、カーネル内でシステムコール監視します。
  • Falcoエージェントプログラムは、事前に定義された監視ルールに一致するアクティビティを検知します。
  • Falcosidekickエージェントは、事前に設定した方法(ログ出力、電子メール通知、Slack通知など)でリアルタイムに通知を行います。

Falcoの監視ルールは開発元が用意したものをそのまま利用しても良いですし、組織のセキュリティポリシーに合わせてカスタマイズすることも可能です。 最新のFalcoではシステムコールのモニタリング機能に加え、プラグインを介してより多くのデータソースからセキュリティイベントを取り込むことも可能です。

Falcoで検出できるもの

Falcoでは以下に示したようなイベントを検出できるので、セキュリティリスクの早期検知に役立ちます。

  • 特権コンテナを利用したPrivilege escalation
  • setnsなどを使ったNamespaceからの脱出
  • /etc、/usr/bin、/usr/sbinなどへの読み書き監視
  • symlink、hardlink作成
  • ファイルオーナー、モードの変更
  • execveによるプロセス生成
  • shellやsshの実行
  • 重要なファイルの置き換え

Falcoのデプロイ

デプロイされるもの

Falcoの主要コンポーネントは、以下の通りです。

  • Linuxカーネルモジュール又はebpfモジュール: Kubernetesの各ノード上でLinuxカーネルのシステムコールを監視します。
  • Falcoエージェント: Kubernetesの各ノード上で動作し、ルールにマッチしたイベントを検知します。
  • Falcosidekick : Falcoエージェントで検知したイベントを収集し、設定した方法(ログ収集基盤へ出力、電子メール通知、Slack通知など)で通知します。
  • Falcosidekick-ui: Falcoに付いてくるWeb UI。NodePortやIngress、Port Forward経由でアクセス可能です。

Kubernetes環境では、Falco podはdaemonsetとしてすべてのノード上にデプロイされます。 Falco podは、Linuxカーネルモジュール又はebpfのモジュールローダ、Falcoエージェント、監視ルールの自動アップデーターなどの複数コンテナで構成されます。 モジュールローダは、リポジトリからコンパイル済みのLinuxカーネルモジュール、ebpfモジュール等を自動的にダウンロードし、カーネルにロードします。 リポジトリに適切なバージョンのモジュールが存在しない場合には、コンテナ内でソースからモジュールをコンパイルしカーネルにロードします。

Linuxカーネルモジュール、ebpfモジュールどちらを使うのか

FalcoではLinuxカーネルモジュールまたはebpfモジュールをカーネルにロードし、システムコールの監視を行いますが、カーネルにモジュールをロードする行為自体がセキュリティリスクとみなされることもあるため、クラウド環境などではモジュールのロード自体が許されていない場合があります。 したがって現実的には、インフラ環境によって推奨されるモジュールを利用することになると思います。

Falcoのブログには、環境ごとの推奨モジュール、インストール方法がまとめられています。 本ブログの執筆時点では、AWS EKSではカーネルモジュールが推奨され、GKEではebpfモジュールが推奨されるようです。

Helm Chartによるデプロイ

Falcoプロジェクトでは、FalcoをKubernetes環境上にデプロイする方法として、kustomization.yamlによる方法とHelm Chartによる方法を用意しているようです。 本稿ではHelm Chartによるデプロイ方法について説明します。

HelmはKubernetes用のアプリケーションをパッケージ化し、簡単にデプロイおよび管理するためのツールです。次のような手順でHelmをセットアップし、falcoをデプロイすることができます。

Helmのインストール

    
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh 
    
  

Helm Chartリポジトリの追加

    
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update
    
  

Falcoのデプロイ

    
helm install falco falcosecurity/falco -f myvalues.yaml --namespace falco --create-namespace
    
  

ここでのオプションの内容は以下の通りです。

  • --namespace falco : デプロイ先として falco ネームスペースを指定。
  • --create-namespace : 指定したネームスペースが存在しなければ作成する。
  • -f myvalues.yaml : Helm Chartのカスタマイズ内容を myvalues.yaml ファイルから読み込む指定です。

Helm Chartカスタマイズ

Helm Chartのデフォルト設定は、次のレポジトリの values.yaml に定義されています。このデフォルト設定をオーバーライドしたい場合に、myvalues.yamlを利用します。

myvalues.yamlの内容は、例えば以下のように記述します。

    
      driver:
      loader:
        enabled: true
    
    falcosidekick:
      enabled: true
      webui:
        enabled: true
        redis:
          storageClass: "local-storage"
        service:
          type: "NodePort"
    
  

上記の設定では、次のようなカスタマイズを行っています。

  • FalcoのLinuxカーネルモジュールの自動ロード
  • Falcosidekick及びWeb UIの有効化
  • Web UIのredis用ストレージに"local-storage"を指定
  • Web UIのNodePortサービス有効化

動作確認

Falcoが正しくデプロイできたかどうかは、helm list コマンド、kubectl get pods コマンドなどで確認できます。

helm list コマンドでは、Chartのデプロイ状況が確認できます。

    
# helm list -n falco
NAME    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
falco   falco           1               2023-11-20 17:49:41.962917835 +0900 JST deployed        falco-3.7.1     0.36.0
    
  

kubectl get pods コマンドでは、Kubernetes上にデプロイされた各podの状態が確認できます。 次の例では、falco podがv131-v136の各ノードで一つずつデプロイされていること、falco-falcosidekick、falco-falcosidekick-ui podは全体二つずつ、falco-falcosidekick-ui-redis podは全体で一つだけデプロイされていること等が分かります。

    
# kubectl get pods -n falco -o wide
NAME                                      READY   STATUS    RESTARTS        AGE     IP             NODE   NOMINATED NODE   READINESS GATES
falco-4dfjc                               2/2     Running   0               9m46s   10.244.4.204   v135              
falco-659kn                               2/2     Running   0               9m46s   10.244.1.195   v132              
falco-7scxs                               2/2     Running   0               9m46s   10.244.5.206   v136              
falco-falcosidekick-749d77d5c7-bsp5f      1/1     Running   0               9m46s   10.244.5.204   v136              
falco-falcosidekick-749d77d5c7-lzdwd      1/1     Running   0               9m46s   10.244.3.252   v134              
falco-falcosidekick-ui-6885c6cffd-k4bt8   1/1     Running   2 (9m44s ago)   9m46s   10.244.5.205   v136              
falco-falcosidekick-ui-6885c6cffd-zhrbn   1/1     Running   2 (9m45s ago)   9m46s   10.244.4.203   v135              
falco-falcosidekick-ui-redis-0            1/1     Running   0               9m46s   10.244.3.253   v134              
falco-h9s99                               2/2     Running   0               9m46s   10.244.0.211   v131              
falco-n25zx                               2/2     Running   0               9m46s   10.244.2.194   v133              
falco-zshln                               2/2     Running   0               9m46s   10.244.3.254   v134              
    
  

Falco Web UI

Falcoには次の図のような簡易的なWeb UIが容易されています。

このページ右上の EXPORT ボタンを押すと、json形式のログファイルをダウンロードすることもでき、非常に便利です。

Web UIにはNodePort、Port Forward、ingressなどを通してアクセスすることができます。 ここでは、NodePortを通してのアクセスと、Port Forwardを利用する方法についてまとめます。

kubectl get svc でKubernetesのサービスの確認が可能です。 次の例では、falco-falcosidekick-uiにクラスターIP:10.109.212.176、Port:2802がアサインされ、さらにNodePort:30282で外部からアクセス可能であることが分かります。

    
# kubectl get svc -n falco
NAME                           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
falco-falcosidekick            ClusterIP   10.109.145.202           2801/TCP         2m17s
falco-falcosidekick-ui         NodePort    10.109.212.176           2802:30282/TCP   2m17s
falco-falcosidekick-ui-redis   ClusterIP   10.97.33.253             6379/TCP         2m17s
    
  

NodePort

WEBブラウザを開きKubernetesのNodeのひとつで30282番ポート(例えばhttp://10.0.0.131:30282)にアクセスすることで、Web UIを開くことが可能です。

NodeのIPアドレスは kubectl get nodes -o wide で確認可能です。

    
root@v130:~# kubectl get nodes -o wide
NAME   STATUS   ROLES           AGE   VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE                         KERNEL-VERSION    CONTAINER-RUNTIME
v131   Ready    control-plane   54d   v1.28.2   10.0.0.131            Debian GNU/Linux 12 (bookworm)   6.4.11-64kvmg01   containerd://1.7.6
v132   Ready    control-plane   54d   v1.28.2   10.0.0.132            Debian GNU/Linux 12 (bookworm)   6.4.11-64kvmg01   containerd://1.7.6
v133   Ready    control-plane   54d   v1.28.2   10.0.0.133            Debian GNU/Linux 12 (bookworm)   6.4.11-64kvmg01   containerd://1.7.6
v134   Ready              54d   v1.28.2   10.0.0.134            Debian GNU/Linux 12 (bookworm)   6.4.11-64kvmg01   containerd://1.7.6
v135   Ready              54d   v1.28.2   10.0.0.135            Debian GNU/Linux 12 (bookworm)   6.4.11-64kvmg01   containerd://1.7.6
v136   Ready              54d   v1.28.2   10.0.0.136            Debian GNU/Linux 12 (bookworm)   6.4.11-64kvmg01   containerd://1.7.6
    
  

Port Forward

まず、次のコマンドでPort Forwardをセットアップします。WEBブラウザを開き、kubectl port-forward を実行しているホストの1234番ポート(例えばhttp://127.0.0.1:1234)にアクセスすれば、Web UIを開くことが可能です。

    
kubectl port-forward svc/falco-falcosidekick-ui -n falco --address 0.0.0.0 1234:2802
    
  

Falcoのルールファイル

デフォルトルールセット

Falcoのリポジトリには、デフォルトのルールセットが用意されており、ユーザーはそれらのルールを必要に応じて有効化したり、修正したり、独自のルールを追加したりすることができます。 デフォルトルールセットを全く使わずに、独自のルールのみでFalcoを運用することも可能です。

このブログ記事の執筆時点で、Falcoプロジェクトでは88個のデフォルトルールセットが用意されており、重要度に応じて次の4つのファイルに分けられています。

  • falco_rules.yaml
  • falco-incubating_rules.yaml
  • falco-sandbox_rules.yaml
  • falco-deprecated_rules.yaml

Helmのコマンドラインで特に何も指定しない場合は、falco_rules.yaml のみがロードされます。 falco_rules.yaml には次の25個のルールが定義されています。

  • Directory traversal monitored file read
  • Read sensitive file trusted after startup
  • Read sensitive file untrusted
  • Run shell untrusted
  • System user interactive
  • Terminal shell in container
  • Contact K8S API Server From Container
  • Netcat Remote Code Execution in Container
  • Search Private Keys or Passwords
  • Clear Log Activities
  • Remove Bulk Data from Disk
  • Create Symlink Over Sensitive Files
  • Create Hardlink Over Sensitive Files
  • Packet socket created in container
  • Redirect STDOUT/STDIN to Network Connection in Container
  • Linux Kernel Module Injection Detected
  • Debugfs Launched in Privileged Container
  • Detect release_agent File Container Escapes
  • PTRACE attached to process
  • PTRACE anti-debug attempt
  • Find AWS Credentials
  • Execution from /dev/shm
  • Drop and execute new binary in container
  • Disallowed SSH Connection Non Standard Port
  • Fileless execution via memfd_create

Falcoの公式サイトには、各ファイルのルールの内容、デフォルトで有効かどうかなどについて、わかりやすくまとめられたページが用意されています。

falco_rules.yaml の他に、falco-incubating_rules.yaml falco-sandbox_rules.yaml をロードしたい場合には、helmコマンド実行時に明示的に指定する必要があります。

    
helm install falco falcosecurity/falco \
--set "falcoctl.config.artifact.install.refs={falco-rules:2,falco-incubating-rules:2,falco-sandbox-rules:2}" \
--set "falcoctl.config.artifact.follow.refs={falco-rules:2,falco-incubating-rules:2,falco-sandbox-rules:2}" \
--set "falco.rules_file={/etc/falco/k8s_audit_rules.yaml,/etc/falco/rules.d,/etc/falco/falco_rules.yaml,/etc/falco/falco-incubating_rules.yaml,/etc/falco/falco-sandbox_rules.yaml}"
    
  

あるいは、上記のようにコマンドラインに引数として指定する代わりに、myvalues.yamlで次のような設定を行うと、helmコマンドのオプションを簡略化することができます。

    
      falcoctl:
      config:
        artifact:
          install:
            refs:
              - falco-rules:2
              - falco-incubating-rules:2
              - falco-sandbox-rules:2
          follow:
            refs:
              - falco-rules:2
              - falco-incubating-rules:2
              - falco-sandbox-rules:2
    
    falco:
      rules_file:
        - /etc/falco/k8s_audit_rules.yaml
        - /etc/falco/rules.d
        - /etc/falco/falco_rules.yaml
        - /etc/falco/falco-incubating_rules.yaml
        - /etc/falco/falco-sandbox_rules.yaml
  

その場合、helmのコマンドラインは次のようになります。

    
helm install falco falcosecurity/falco -f myvalues.yaml --namespace falco --create-namespace
    
  

Falcoプロジェクトで用意されているデフォルトルールセットには、すべてMITRE ATT&CK のタグ付けがされていて、既知の攻撃パターンを幅広く網羅していると言えます。しかしながらその逆に、未知の攻撃パターンに対しては必ずしも万全とは言えないかもしれません。

未知の攻撃パターンを検知するには、ホワイトリスト形式のカスタムルールを作成すると良いかもしれません。 現在、ホワイトリスト形式のカスタムルールの検討も行っていますが、それについては別の機会にまとめたいと思います。

Falcoルールの例

Falcoルールファイルは、List、Macro、Ruleの三種類の要素からなっています。

  • List: ルールやマクロ、その他のリストに含めることができるアイテムのコレクション。
  • Macro: ルールや他のマクロの中で再利用できるルール条件のスニペット。
  • Rule: アラートを発生させる条件とアラートの出力文字列の定義。

以下は、Disallowed SSH Connection Non Standard Port というルールの例です。

  • "macro: outbound": TCP、UDPのアウトバウンド通信にマッチするマクロです。
  • "list: ssh_non_standard_ports": sshの標準ポートが塞がれている場合に、抜け道としてよく使われるポート番号のリスト。
  • "macro: ssh_non_standard_ports_network": sshの抜け道ポート番号リストへのマッチを判定するマクロです。
これらのマクロを利用して、"rule: Disallowed SSH Connection Non Standard Port"のconditionが書かれています。
    
      - macro: outbound
      condition: >
        (((evt.type = connect and evt.dir=<) or
          (evt.type in (sendto,sendmsg) and evt.dir=< and
           fd.l4proto != tcp and fd.connected=false and fd.name_changed=true)) and
         (fd.typechar = 4 or fd.typechar = 6) and
         (fd.ip != "0.0.0.0" and fd.net != "127.0.0.0/8" and not fd.snet in (rfc_1918_addresses)) and
         (evt.rawres >= 0 or evt.res = EINPROGRESS))
    
    - list: ssh_non_standard_ports
      items: [80, 8080, 88, 443, 8443, 53, 4444]
    
    - macro: ssh_non_standard_ports_network
      condition: (fd.sport in (ssh_non_standard_ports))
    
    - rule: Disallowed SSH Connection Non Standard Port
      desc: > 
        Detect any new outbound SSH connection from the host or container using a non-standard port. This rule holds the potential 
        to detect a family of reverse shells that cause the victim machine to connect back out over SSH, with STDIN piped from 
        the SSH connection to a shell's STDIN, and STDOUT of the shell piped back over SSH. Such an attack can be launched against 
        any app that is vulnerable to command injection. The upstream rule only covers a limited selection of non-standard ports. 
        We suggest adding more ports, potentially incorporating ranges based on your environment's knowledge and custom SSH port 
        configurations. This rule can complement the "Redirect STDOUT/STDIN to Network Connection in Container" or 
        "Disallowed SSH Connection" rule.
      condition: > 
        outbound 
        and proc.exe endswith ssh 
        and fd.l4proto=tcp 
        and ssh_non_standard_ports_network
      output: >-
        Disallowed SSH Connection (connection=%fd.name lport=%fd.lport rport=%fd.rport 
      fd_type=%fd.type fd_proto=fd.l4proto evt_type=%evt.type user=%user.name user_uid=%user.uid 
      user_loginuid=%user.loginuid process=%proc.name proc_exepath=%proc.exepath parent=%proc.pname 
      command=%proc.cmdline terminal=%proc.tty exe_flags=%evt.arg.flags %container.info)
      priority: NOTICE
      tags: [maturity_stable, host, container, network, process, mitre_execution, T1059]
    
  

Falcoのデフォルトルールの自動アップデート

Falcoをhelmでデプロイした場合には、デフォルトのルールセットは定期的にアップデートされます。 定期アップデートはFalco pod内の falcoctl-artifact-follow コンテナにより行われます。

If you install the Helm chart, at least version 3.0.0 with: helm install falco Falco, by default, will load the latest rules file that is compatible with your Falco version and keep it up to date automatically via falcoctl. These are published on GitHub Packages.

- https://falco.org/docs/rules/default-custom/#rules-installed-via-the-helm-chart

Falcoのインシデント検知の例

シンプルなnginx podを起動し、次の3つの操作を実行し、falcoで検知可能かどうか確認しました。

  • kubectl execコマンドでコンテナに接続し、bashシェルを実行します。
  • コンテナ内でviをインストールし、実行します。
  • コンテナ内から外部サーバの443ポートにssh接続します。

Falcoでの検知結果はWeb UIで確認し、そこからダウンロードしたjsonログファイルの該当部分を記載しました。

nginx podの起動

    
kubectl apply -f simple-pod.yaml
    
  

simple-pod.yamlの内容

    
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80
    
  

nginxコンテナにアタッチ

実行コマンド

    
# kubectl exec -it nginx -- /bin/bash 
root@nginx:/# 
    
  

検出されるログ

    
{
  "uuid": "4b1a818b-7cd0-4985-ba95-a6f2fa897f4e",
  "output": "09:10:51.667430058: Notice A shell was spawned in a container with an attached terminal ...",
  "priority": "Notice",
  "rule": "Terminal shell in container",
  "time": "2023-11-27T09:10:51.667430058Z",
  "source": "syscall",
  "output_fields": {
    "container.id": "e6f8a1e1dd97",
    "container.image.repository": "docker.io/library/nginx",
    "container.image.tag": "latest",
    "container.name": "nginx",
    "evt.arg.flags": "EXE_WRITABLE",
    "evt.time": 1701076251667430100,
    "evt.type": "execve",
    "k8s.ns.name": "default",
    "k8s.pod.name": "nginx",
    "proc.cmdline": "bash",
    "proc.exepath": "/usr/bin/bash",
    "proc.name": "bash",
    "proc.pname": "runc",
    "proc.tty": 34817,
    "user.loginuid": -1,
    "user.name": "root",
    "user.uid": 0
  },
  "hostname": "v136",
  "tags": [
    "T1059",
    "container",
    "maturity_stable",
    "mitre_execution",
    "shell"
  ]
}
    
  

"Terminal shell in container"ルールにマッチしてインシデントが検知されていることが分かります。 このルールは、コンテナ内でシェルプロセスが実行されたことを検知します。

viでファイルを編集

実行コマンド

    
apt install vim
vi test
    
  

検出されるログ

    
{
  "uuid": "4485356c-4899-4b52-acc7-75308454a04c",
  "output": "09:14:04.692611115: Critical Executing binary not part of base image ... ",
  "priority": "Critical",
  "rule": "Drop and execute new binary in container",
  "time": "2023-11-27T09:14:04.692611115Z",
  "source": "syscall",
  "output_fields": {
    "container.id": "e6f8a1e1dd97",
    "container.image.repository": "docker.io/library/nginx",
    "container.image.tag": "latest",
    "container.name": "nginx",
    "container.start_ts": 1701069045261889000,
    "evt.arg.flags": "EXE_WRITABLE|EXE_UPPER_LAYER",
    "evt.time": 1701076444692611000,
    "evt.type": "execve",
    "k8s.ns.name": "default",
    "k8s.pod.name": "nginx",
    "proc.aname[2]": "containerd-shim",
    "proc.cmdline": "vi test",
    "proc.cwd": "/",
    "proc.exe": "vi",
    "proc.exe_ino.ctime": 1701076429805272800,
    "proc.exe_ino.ctime_duration_proc_start": 14886864198,
    "proc.exe_ino.mtime": 1683195884000000000,
    "proc.exepath": "/usr/bin/vim.basic",
    "proc.name": "vi",
    "proc.pname": "bash",
    "proc.sname": "bash",
    "proc.tty": 34816,
    "user.loginuid": -1,
    "user.name": "root",
    "user.uid": 0
  },
  "hostname": "v136",
  "tags": [
    "PCI_DSS_11.5.1",
    "TA0003",
    "container",
    "maturity_stable",
    "mitre_persistence",
    "process"
  ]
}
    
  

"Drop and execute new binary in container"ルールにマッチしてインシデントが検知されていることが分かります。 このルールはoverlayfsの最上位層に新規に作成されたファイルの実行を検知します。 なぜなら最上位層のファイルはもともとコンテナのベースイメージに存在していたものではなく、あとから侵入者が作成したものである可能性を排除できないからです。 このルールにより、侵入者がクラッキングツールをダウンロードし実行した場合などに、それを逃さずに検知することができます。

443番ポートへのssh接続

実行コマンド

    
root@nginx:/# ssh example.com -p 443
kex_exchange_identification: read: Connection reset by peer
Connection reset by 93.184.216.34 port 443
    
  

検出されるログ

    
{
  "uuid": "303636ae-93cd-4474-b796-3d87aa28c089",
  "output": "03:29:15.493403233: Notice Disallowed SSH Connection ... ", 
  "priority": "Notice",
  "rule": "Disallowed SSH Connection Non Standard Port",
  "time": "2023-11-28T03:29:15.493403233Z",
  "source": "syscall",
  "output_fields": {
    "container.id": "e6f8a1e1dd97",
    "container.image.repository": "docker.io/library/nginx",
    "container.image.tag": "latest",
    "container.name": "nginx",
    "evt.arg.flags": null,
    "evt.time": 1701142155493403100,
    "evt.type": "connect",
    "fd.lport": 36820,
    "fd.name": "10.244.5.218:36820->93.184.216.34:443",
    "fd.rport": 443,
    "fd.type": "ipv4",
    "k8s.ns.name": "default",
    "k8s.pod.name": "nginx",
    "proc.cmdline": "ssh example.com -p 443",
    "proc.exepath": "/usr/bin/ssh",
    "proc.name": "ssh",
    "proc.pname": "bash",
    "proc.tty": 34816,
    "user.loginuid": -1,
    "user.name": "root",
    "user.uid": 0
  },
  "hostname": "v136",
  "tags": [
    "T1059",
    "container",
    "host",
    "maturity_stable",
    "mitre_execution",
    "network",
    "process"
  ]
}
    
  

"Disallowed SSH Connection Non Standard Port"ルールにマッチしてインシデントが検知されていることが分かります。 このルールでは、ポート番号"80, 8080, 88, 443, 8443, 53, 4444"へのSSH接続を検知します。 これらのポートはHTTPやHTTPS、DNSなどで使われるポートなので経路上のファイアーウォールなどで塞がれることが少なく、22番ポートでの外部通信が禁止されている場合などに、SSHの代替ポートとして利用することが可能だからです。

デフォルトルールセットの問題点

Falcoのデフォルトルールセットは、既知の攻撃パターンを幅広く網羅していて非常に強力です。 しかしながら、未知の攻撃パターンに対しては必ずしも万全とは言えないかもしれません。

例えば、Falcoのインシデント検知の例で示したケースのうち次の二つについても、抜け穴が考えられます。

  • viでファイルを編集
  • 443番ポートへのssh接続

viでファイルを編集

この例では、overlayfsの最上位層に新規に作成されたファイルの実行を検知しました。 しかし、コンテナにはtmpfsがマウントされていることも多く、そこに置かれたファイルの実行は検知しません。 この例のnginxコンテナの場合、/devにtmpfsがマウントされていました。 そこで、viを/devにコピーし/dev/viを実行してみましたが、Falcoで検知することはできませんでした。

    
root@nginx:/# cp /usr/bin/vi /dev/
root@nginx:/# /dev/vi test
    
  

443番ポートへのssh接続

この例では、ポート番号"80, 8080, 88, 443, 8443, 53, 4444"へのSSH接続を検知していました。 この場合ポートを限定しているため、その他の任意のポート番号で外部接続が可能であった場合に、それを利用したSSH接続を検知することができません。

この様に、Falcoのデフォルトルールセットで検知できないエッジケースは他に数多く存在すると予想されます。 未知の攻撃パターンを検知するには、ホワイトリスト形式のカスタムルールを作成すると良いかもしれません。 その試みについては別の機会にまとめたいと思います。

まとめ

Falcoの概要、デプロイ方法、インシデント検出の例などについてまとめました。 Falcoは、Kubernetes上ではHelm Chart等により簡単にデプロイ可能です。 また、Falcoのレポジトリには、デフォルトのルールセットが用意されています。 ユーザーはこれをそのまま利用したり、各ルールを状況に応じて有効・無効を切り替えて使うことができます。 Falcoのデフォルトルールセットは強力ではありますが、デフォルトルールセットの問題点に記載しているような未知のセキュリティリスクを検知できない場合があります。 次回以降の記事でホワイトリスト形式のカスタムルールの書き方、適用方法などについてまとめたいと思います。

このブログについて

KLabのゲーム開発・運用で培われた技術や挑戦とそのノウハウを発信します。

おすすめ

合わせて読みたい

このブログについて

KLabのゲーム開発・運用で培われた技術や挑戦とそのノウハウを発信します。