TECHSTEP

ITインフラ関連の記事を公開してます。

Falcoに入門する

今回はCloud-Nativeなランタイムセキュリティ機能を提供するFalcoを試しました。

Falcoとは

FalcoSysdig社が開発元であるランタイムセキュリティツールです。CNCFがホストとなっているOpen Sourceであり、2020年12月時点でプロジェクトの成熟度はIncubatingとされています。

Falcoの前に、Container Runtime Securityについて少し触れておきます。本番環境で動作するコンテナは、インターネットからの外部通信や、サービス・システム内部のマイクロサービスからの通信を受け取り、常に攻撃者からの標的となります。またコンテナを利用したシステムはコンテナ単体では動作せず、サーバ・ネットワークなどのインフラレイヤー、ユーザーに対して実際のサービスの機能を提供するアプリケーションレイヤーなど、様々な要素が連携して成り立っています。さらにコンテナを利用するシステムはコンテナの起動する数やコンテナを実行するホストの構成など、システム全体が動的に変化します。このような、構成が複雑かつ動的に変動する環境では、従来のような脆弱性診断やID管理などだけでは、セキュリティ対策として不十分になります。

コンテナ実行基盤として代表的なKubernetes上でセキュリティを強化するうえで、従来の観点に加えて追加するべき対策として、CNCF Webinar (動画)では以下のようなものが挙げられています。

  • Prevention/Enforcement: Kubernetes上で「誰が」「何を」行うことを許可するかをコントロールする。
  • Detection/Audit: Kubernetes上で何が起こっているかを検知する。
  • Blocking: 攻撃者からの攻撃をブロックする。システムの入り口にFirewallを設置するなどの対策を行う。
  • Incident response + Forensics: セキュリティの問題が発生した際、何が起こったかを把握し、素早く対応・修理できる必要がある。

一つ目のステップであるPreventionについては、Kubernetesがネイティブに備えるいくつかの機能(RBAC / Network Policy / Pod Security Policy)を利用することができます。それに加え、Admission Controlerを利用したOPAによる制御も有効です(OPAについては前回の投稿をご覧ください)。

しかし一つ目の対策で防げない場合、二つ目の対策であるDetectionが重要となります。これは事前の対応が難しいような問題が発生した際、後の調査や対策を検討することも含め、実際に何が起こったかを追跡し、原因を特定できるようにする必要があるため、セキュリティにおける最終ラインであるとも言えます。

Detectionを行うために検討できる方法としてはいくつかの選択肢が考えられましたが、Sysdig社のエンジニアはKernelベースでシステムのイベントをモニタリングする方式を採用し、それをFalcoに利用しました。

falco-image

FalcoはLinux System Callを利用したモニタリングを行います。FalcoはLinuxのSystem Callをパースして、あらかじめ設定されたRuleベースにそれを評価し、違反する場合はそれを検知してログ等に出力します。また検出時はSlack等へ通知を送ることも可能です。

Falcoはモニタリングする内容をRuleというYAMLファイルで定義します。Falco ver 0.8.0からは、デフォルトで利用できるRuleファイル(falco_rules.yaml)が用意され、インストールした直後からFalcoの機能を利用することができます。利用者がカスタマイズする場合はfalco_rules.local.yamlというローカルファイルを編集することで、Ruleの追加や上書きが可能になります。

Falcoは大きく3つのコンポーネントから構成されています。

  • Userspace Program (falco CLI): Falcoと接続するのに利用する。シグナルをコントロールし、Falco Driverからの情報(syscall)をパースし、必要ならアラートを送る。

  • Configuration: Falcoに関する設定。Falco自体の設定に加え、利用するRuleやアラートの送信方法などを定義する。

  • Driver: FalcoのDriver仕様に準拠したソフトウェアで、syscall情報を送信する。DriverをインストールしなければFalcoを起動することはできない。現在は3種類のDriverをサポートしている。

    • libscap libsinspというライブラリ上に構築されたKernelモジュール
    • 同モジュール上に構成されたeBPF probe
    • Userspaceで実行されるUserspace Instrumentation

Falcoの構成は以下のような図で表されます。System CallがKernelモジュールやeBPFからlibscap libsinspを経由してFalcoへ送られ、Ruleに基づいて疑わしいイベントを検知し、アラートを送信します。またKubernetesAudit Logから情報を受け取ったり、アラートの送信先としてfalco-exporterを経由してPrometheusを利用することも可能です。

※図:いずれもCNCF Webinar資料より一部抜粋

f:id:FY0323:20201227232812j:plain

f:id:FY0323:20201227232821j:plain

Falcoを使ってみる

ここから実際にFalcoを操作してみます。

検証環境

Falcoのインストール

FalcoをKubernetes上にインストールする場合はHelmを利用します。こちらのGitHubリポジトリにはHelmチャートが用意されており、これを利用すればインストールを簡単に実行できます。今回はhelm templateコマンドを利用してマニフェストファイルを生成し、それを利用してインストールを行いました。

# Chartの取得
$ git clone https://github.com/falcosecurity/charts.git
$ cd charts/


# Templateの生成
$ mkdir testdir
$ helm template --output-dir ./testdir ./falco/
wrote ./testdir/falco/templates/serviceaccount.yaml
wrote ./testdir/falco/templates/configmap.yaml
wrote ./testdir/falco/templates/clusterrole.yaml
wrote ./testdir/falco/templates/clusterrolebinding.yaml
wrote ./testdir/falco/templates/daemonset.yaml

マニフェストファイルは以下の通りです。ファイル中のRELEASE-NAME-という箇所は、適宜修正を行ってからデプロイします。またconfigmap.yamlは、設定するConfigの情報が膨大なため、ここでは省略しています(設定ファイルへのリンクのみ記載)。

serviceaccount.yaml

---
# Source: falco/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: RELEASE-NAME-falco
  namespace: default
  labels:
    app: RELEASE-NAME-falco
    chart: "falco-1.5.7"
    release: "RELEASE-NAME"
    heritage: "Helm"

clusterrole.yaml

---
# Source: falco/templates/clusterrole.yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: RELEASE-NAME-falco
  labels:
    app: RELEASE-NAME-falco
    chart: "falco-1.5.7"
    release: "RELEASE-NAME"
    heritage: "Helm"
rules:
  - apiGroups:
      - extensions
      - ""
    resources:
      - nodes
      - namespaces
      - pods
      - replicationcontrollers
      - replicasets
      - services
      - daemonsets
      - deployments
      - events
      - configmaps
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - apps
    resources:
      - daemonsets
      - deployments
      - replicasets
      - statefulsets
    verbs:
      - get
      - list
      - watch
  - nonResourceURLs:
      - /healthz
      - /healthz/*
    verbs:
      - get

clusterrolebinding.yaml

---
# Source: falco/templates/clusterrolebinding.yaml
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: RELEASE-NAME-falco
  labels:
    app: RELEASE-NAME-falco
    chart: "falco-1.5.7"
    release: "RELEASE-NAME"
    heritage: "Helm"
subjects:
  - kind: ServiceAccount
    name: RELEASE-NAME-falco
    namespace: default
roleRef:
  kind: ClusterRole
  name: RELEASE-NAME-falco
  apiGroup: rbac.authorization.k8s.io

configmap.yaml

---
# Source: falco/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: RELEASE-NAME-falco
  namespace: default
  labels:
    app: RELEASE-NAME-falco
    chart: "falco-1.5.7"
    release: "RELEASE-NAME"
    heritage: "Helm"
data:
  falco.yaml: |-
(中略)
  application_rules.yaml: |
(中略)
  falco_rules.local.yaml: |
(中略)
  falco_rules.yaml:
(中略)
  k8s_audit_rules.yaml: 
(中略)

daemonset.yaml

---
# Source: falco/templates/daemonset.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: RELEASE-NAME-falco
  namespace: default
  labels:
    app: RELEASE-NAME-falco
    chart: "falco-1.5.7"
    release: "RELEASE-NAME"
    heritage: "Helm"
spec:
  selector:
    matchLabels:
      app: RELEASE-NAME-falco
      role: security
  template:
    metadata:
      name: RELEASE-NAME-falco
      labels:
        app: RELEASE-NAME-falco
        role: security
      annotations:
        checksum/config: 87dc39d25a867a7fb6f376d0f62aae0ef2cd2476a5b6ab25af75ee23b3c55f95
        checksum/rules: 01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b
        checksum/certs: 01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b
    spec:
      serviceAccountName: RELEASE-NAME-falco
      tolerations:
        - effect: NoSchedule
          key: node-role.kubernetes.io/master
      containers:
        - name: falco
          image: docker.io/falcosecurity/falco:0.26.2
          imagePullPolicy: IfNotPresent
          resources:
            limits:
              cpu: 200m
              memory: 1024Mi
            requests:
              cpu: 100m
              memory: 512Mi
          securityContext:
            privileged: true
          args:
            - /usr/bin/falco
            - --cri
            - /run/containerd/containerd.sock
            - -K
            - /var/run/secrets/kubernetes.io/serviceaccount/token
            - -k
            - "https://$(KUBERNETES_SERVICE_HOST)"
            - -pk
          env:
          volumeMounts:
            - mountPath: /host/var/run/docker.sock
              name: docker-socket
            - mountPath: /host/run/containerd/containerd.sock
              name: containerd-socket
            - mountPath: /host/dev
              name: dev-fs
              readOnly: true
            - mountPath: /host/proc
              name: proc-fs
              readOnly: true
            - mountPath: /host/boot
              name: boot-fs
              readOnly: true
            - mountPath: /host/lib/modules
              name: lib-modules
            - mountPath: /host/usr
              name: usr-fs
              readOnly: true
            - mountPath: /dev/shm
              name: dshm
            - mountPath: /host/etc
              name: etc-fs
              readOnly: true
            - mountPath: /etc/falco
              name: config-volume
      volumes:
        - name: dshm
          emptyDir:
            medium: Memory
        - name: docker-socket
          hostPath:
            path: /var/run/docker.sock
        - name: containerd-socket
          hostPath:
            path: /run/containerd/containerd.sock
        - name: dev-fs
          hostPath:
            path: /dev
        - name: proc-fs
          hostPath:
            path: /proc
        - name: boot-fs
          hostPath:
            path: /boot
        - name: lib-modules
          hostPath:
            path: /lib/modules
        - name: usr-fs
          hostPath:
            path: /usr
        - name: etc-fs
          hostPath:
            path: /etc
        - name: config-volume
          configMap:
            name: RELEASE-NAME-falco
            items:
              - key: falco.yaml
                path: falco.yaml
              - key: falco_rules.yaml
                path: falco_rules.yaml
              - key: falco_rules.local.yaml
                path: falco_rules.local.yaml
              - key: application_rules.yaml
                path: rules.available/application_rules.yaml
  updateStrategy:
    type: RollingUpdate

configmap.yamlの設定ファイル:


上記マニフェストファイルを修正後、デプロイします。FalcoはDaemonSetとして定義されているので、各Node上にPodが配置されます。各Node上に配置されたFalco Podは、それぞれのNode上のイベントを監視し、デフォルトではFalco Podのログとしてアラートを出力します。

# 今回は2Node
$ kubectl get nodes
NAME                                               STATUS   ROLES    AGE   VERSION
ip-192-168-1-144.ap-northeast-1.compute.internal   Ready    <none>   33h   v1.18.9-eks-d1db3c
ip-192-168-2-241.ap-northeast-1.compute.internal   Ready    <none>   33h   v1.18.9-eks-d1db3c


# Falcoのインストール
$ kubectl apply -f testdir/falco/templates/
clusterrole.rbac.authorization.k8s.io/falco created
clusterrolebinding.rbac.authorization.k8s.io/falco created
configmap/falco created
daemonset.apps/falco created
serviceaccount/falco created


# インストール後の確認
$ kubectl get cm
NAME    DATA   AGE
falco   5      9s


$ kubectl get ds
NAME    DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
falco   2         2         0       2            0           <none>          17s


$ kubectl get pods
NAME          READY   STATUS    RESTARTS   AGE
falco-hgkqh   1/1     Running   0          32s
falco-w5ld8   1/1     Running   0          32s

Falcoの動作確認

Falcoのインストールが完了したので、Falcoがどのように動作するかを見ていきます。今回はDefault Ruleに定義されたモニタリング項目をいくつか取り上げ、Falcoのログとしてアラートが生成される様子を確認しました。

コンテナへのログイン

まずはkubectl execコマンドを利用してFalcoコンテナへのログイン・ログアウトを実行しました。コンテナ上でShellを実行することは、いくつかの設定管理ソフトウェアで例があるものの、基本的にはあまり実行することは想定されていません。そのため、コンテナ上でShellが実行されたイベントが発生すると、Falcoはそれをアラートとして出力します。またそれと関連して(?)shellスクリプトからexitした際も、Falcoはそのイベントをアラート対象と設定しています。

falco_rules.yamlでの該当するRuleはこちらこちらの箇所になります。

falco_rules.yaml

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

(中略)

- rule: Delete or rename shell history
  desc: Detect shell history deletion
  condition: >
    (modify_shell_history or truncate_shell_history) and
       not var_lib_docker_filepath and
       not proc.name in (docker_binaries)
  output: >
    Shell history had been deleted or renamed (user=%user.name user_loginuid=%user.loginuid type=%evt.type command=%proc.cmdline fd.name=%fd.name name=%evt.arg.name path=%evt.arg.path oldpath=%evt.arg.oldpath %container.info)
  priority:
    WARNING
  tags: [process, mitre_defense_evasion]
# 別ターミナルでFalco Logsを流しておく
$ kubectl logs falco-hgkqh -f


# Falcoコンテナへログイン
$ kubectl exec -it falco-hgkqh bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
root@falco-hgkqh:/# 


# ログアウト
root@falco-hgkqh:/# exit
exit
$


# 以下のようなログが流れる

03:40:38.696280739: Notice A shell was spawned in a container with an attached terminal (user=root user_loginuid=-1 k8s.ns=default k8s.pod=falco-hgkqh container=2b1d9a24cdc0 shell=bash parent=runc cmdline=bash terminal=34816 container_id=2b1d9a24cdc0 image=falcosecurity/falco) k8s.ns=default k8s.pod=falco-hgkqh container=2b1d9a24cdc0

03:40:49.213841028: Warning Shell history had been deleted or renamed (user=root user_loginuid=-1 type=openat command=bash fd.name=/root/.bash_history name=/root/.bash_history path=<NA> oldpath=<NA> k8s.ns=default k8s.pod=falco-hgkqh container=2b1d9a24cdc0) k8s.ns=default k8s.pod=falco-hgkqh container=2b1d9a24cdc0
コンテナ上でパッケージインストール

次にログインしたコンテナ上でパッケージインストールを実行しました。コンテナは本来immutableな状態であるべきで、パッケージのインストールはコンテナイメージのBuild時になされるべきです。Falcoはコンテナ上でパッケージインストールを行うというイベントをモニタリング対象としており、イベント発生を契機にアラートを生成します。ここで該当するRuleはこちらの箇所になります。

falco-rules.yaml

# Container is supposed to be immutable. Package management should be done in building the image.
- rule: Launch Package Management Process in Container
  desc: Package management process ran inside container
  condition: >
    spawned_process
    and container
    and user.name != "_apt"
    and package_mgmt_procs
    and not package_mgmt_ancestor_procs
    and not user_known_package_manager_in_container
  output: >
    Package management process launched in container (user=%user.name user_loginuid=%user.loginuid
    command=%proc.cmdline container_id=%container.id container_name=%container.name image=%container.image.repository:%container.image.tag)
  priority: ERROR
  tags: [process, mitre_persistence]
# テスト用コンテナの起動
$ kubectl run nginx --image nginx:latest
pod/nginx created


$ kubectl get pods -o wide
NAME          READY   STATUS    RESTARTS   AGE    IP              NODE                                               NOMINATED NODE   READINESS GATES
falco-hgkqh   1/1     Running   0          15m    192.168.2.126   ip-192-168-2-241.ap-northeast-1.compute.internal   <none>           <none>
falco-w5ld8   1/1     Running   0          15m    192.168.1.117   ip-192-168-1-144.ap-northeast-1.compute.internal   <none>           <none>
nginx         1/1     Running   0          112s   192.168.1.45    ip-192-168-1-144.ap-northeast-1.compute.internal   <none>           <none>


# Nginx Podが起動したNodeに存在するFalcoのログを流しておく
$ kubectl logs falco-w5ld8 -f


# パッケージ更新
$ kubectl exec -it nginx -- apt-get update -y


# 以下のようなログが確認できる

05:16:58.737843387: Error Package management process launched in container (user=root user_loginuid=-1 command=apt-get update -y container_id=5f7008d770cd container_name=k8s_nginx_nginx_default_f7a69089-ac2a-4006-94af-78ad15ded39d_0 image=nginx:latest) k8s.ns=default k8s.pod=nginx container=5f7008d770cd k8s.ns=default k8s.pod=nginx container=5f7008d770cd
Networkツールの実行

コンテナ上でnmap digのような「疑わしい」Networkツールを実行した際も、Falcoはそれをアラートとして検知します(ここではnc ncat nmap dig tcpdump tshark ngrep telnet mitmproxy socat zmapが対象として設定されています)。Default Ruleではこちらに定義されています。

falco-rules.yaml

- rule: Launch Suspicious Network Tool in Container
  desc: Detect network tools launched inside container
  condition: >
    spawned_process and container and network_tool_procs and not user_known_network_tool_activities
  output: >
    Network tool launched in container (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline parent_process=%proc.pname
    container_id=%container.id container_name=%container.name image=%container.image.repository:%container.image.tag)
  priority: NOTICE
  tags: [network, process, mitre_discovery, mitre_exfiltration]

ここではdigコマンドを実行してみます。実際にDNSサーバへの問い合わせを行わなくとも、ログとして出力される様子がわかります。

# Falcoログのモニタリング
$ kubectl logs falco-w5ld8 -f


# Nginx Podへのdigコマンドインストール
$ kubectl exec -it nginx -- apt-get install dnsutils -y


# digコマンドの実行
$ kubectl exec -it nginx -- dig -h
Usage:  dig [@global-server] [domain] [q-type] [q-class] {q-opt}
            {global-d-opt} host [@local-server] {local-d-opt}
            [ host [@local-server] {local-d-opt} [...]]
(中略)


# 以下のようなログが確認できる

09:17:51.427951077: Notice Network tool launched in container (user=root user_loginuid=-1 command=dig -h parent_process=runc container_id=5f7008d770cd container_name=k8s_nginx_nginx_default_f7a69089-ac2a-4006-94af-78ad15ded39d_0 image=nginx:latest) k8s.ns=default k8s.pod=nginx container=5f7008d770cd k8s.ns=default k8s.pod=nginx container=5f7008d770cd
ホストディレクトリのマウント

FalcoはPodの起動するNode上のディレクトリのうち/etc /procなど重要なファイルが配置されているディレクトリを対象に、これらがコンテナからマウントされた場合にアラートを発行します。Default Rulesではこちらの箇所が該当します。

falco_rules.yaml

- rule: Launch Sensitive Mount Container
  desc: >
    Detect the initial process started by a container that has a mount from a sensitive host directory
    (i.e. /proc). Exceptions are made for known trusted images.
  condition: >
    container_started and container
    and sensitive_mount
    and not falco_sensitive_mount_containers
    and not user_sensitive_mount_containers
  output: Container with sensitive mount started (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline %container.info image=%container.image.repository:%container.image.tag mounts=%container.mounts)
  priority: INFO
  tags: [container, cis, mitre_lateral_movement]

ここではhostpathを利用してコンテナから/etcディレクトリをマウントします。

# Falcoログのモニタリング
$ kubectl logs falco-w5ld8 -f
$ kubectl logs falco-hgkqh -f


# hostpath-nginxの作成
 kubectl apply -f hostpath-nginx.yml 
pod/hostpath-nginx created

$ kubectl get pods
NAME             READY   STATUS    RESTARTS   AGE
falco-hgkqh      1/1     Running   0          101m
falco-w5ld8      1/1     Running   0          101m
hostpath-nginx   1/1     Running   0          5s
nginx            1/1     Running   0          87m


# ログの確認

05:13:24.185024277: Notice Container with sensitive mount started (user=root user_loginuid=0 command=container:3a70a57615fd k8s.ns=<NA> k8s.pod=<NA> container=3a70a57615fd image=nginx:latest mounts=/var/lib/kubelet/pods/64ea869e-3778-4edc-9b14-8fe36d1cb439/etc-hosts:/etc/hosts::true:rprivate,/var/lib/kubelet/pods/64ea869e-3778-4edc-9b14-8fe36d1cb439/containers/sec-ctx-nginx/ea0ec6e1:/dev/termination-log::true:rprivate,/etc:/test-pd::true:rprivate,/var/lib/kubelet/pods/64ea869e-3778-4edc-9b14-8fe36d1cb439/volumes/kubernetes.io~secret/default-token-s4dhx:/var/run/secrets/kubernetes.io/serviceaccount:ro:false:rprivate) k8s.ns=<NA> k8s.pod=<NA> container=3a70a57615fd

05:13:24.202081499: Notice Container with sensitive mount started (user=root user_loginuid=-1 command=docker-entrypoi /docker-entrypoint.sh nginx -g daemon off; k8s.ns=<NA> k8s.pod=<NA> container=3a70a57615fd image=nginx:latest mounts=/var/lib/kubelet/pods/64ea869e-3778-4edc-9b14-8fe36d1cb439/etc-hosts:/etc/hosts::true:rprivate,/var/lib/kubelet/pods/64ea869e-3778-4edc-9b14-8fe36d1cb439/containers/sec-ctx-nginx/ea0ec6e1:/dev/termination-log::true:rprivate,/etc:/test-pd::true:rprivate,/var/lib/kubelet/pods/64ea869e-3778-4edc-9b14-8fe36d1cb439/volumes/kubernetes.io~secret/default-token-s4dhx:/var/run/secrets/kubernetes.io/serviceaccount:ro:false:rprivate) k8s.ns=<NA> k8s.pod=<NA> container=3a70a57615fd

05:13:24.202099569: Notice Container with sensitive mount started (user=root user_loginuid=-1 command=docker-entrypoi /docker-entrypoint.sh nginx -g daemon off; k8s.ns=<NA> k8s.pod=<NA> container=3a70a57615fd image=nginx:latest mounts=/var/lib/kubelet/pods/64ea869e-3778-4edc-9b14-8fe36d1cb439/etc-hosts:/etc/hosts::true:rprivate,/var/lib/kubelet/pods/64ea869e-3778-4edc-9b14-8fe36d1cb439/containers/sec-ctx-nginx/ea0ec6e1:/dev/termination-log::true:rprivate,/etc:/test-pd::true:rprivate,/var/lib/kubelet/pods/64ea869e-3778-4edc-9b14-8fe36d1cb439/volumes/kubernetes.io~secret/default-token-s4dhx:/var/run/secrets/kubernetes.io/serviceaccount:ro:false:rprivate) k8s.ns=<NA> k8s.pod=<NA> container=3a70a57615fd

05:13:24.202205924: Notice Container with sensitive mount started (user=root user_loginuid=-1 command=nginx -g daemon off; k8s.ns=<NA> k8s.pod=<NA> container=3a70a57615fd image=nginx:latest mounts=/var/lib/kubelet/pods/64ea869e-3778-4edc-9b14-8fe36d1cb439/etc-hosts:/etc/hosts::true:rprivate,/var/lib/kubelet/pods/64ea869e-3778-4edc-9b14-8fe36d1cb439/containers/sec-ctx-nginx/ea0ec6e1:/dev/termination-log::true:rprivate,/etc:/test-pd::true:rprivate,/var/lib/kubelet/pods/64ea869e-3778-4edc-9b14-8fe36d1cb439/volumes/kubernetes.io~secret/default-token-s4dhx:/var/run/secrets/kubernetes.io/serviceaccount:ro:false:rprivate) k8s.ns=<NA> k8s.pod=<NA> container=3a70a57615fd

ファイルの書き換え

Falcoは/bin /sbin /usr/bin /usr/sbinというBinaryディレクトリ上でのファイルの書き込みが発生した場合、それをアラートとして検出します。Default Rulesではこちらの箇所が該当します。

falco_rules.yaml

- rule: Write below binary dir
  desc: an attempt to write to any file below a set of binary directories
  condition: >
    bin_dir and evt.dir = < and open_write
    and not package_mgmt_procs
    and not exe_running_docker_save
    and not python_running_get_pip
    and not python_running_ms_oms
    and not user_known_write_below_binary_dir_activities
  output: >
    File below a known binary directory opened for writing (user=%user.name user_loginuid=%user.loginuid
    command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline gparent=%proc.aname[2] container_id=%container.id image=%container.image.repository)
  priority: ERROR
  tags: [filesystem, mitre_persistence]
# Falcoログのモニタリング
$ kubectl logs falco-w5ld8 -f


# Ngins Pod上で新しいファイルを作成
$ kubectl exec -it nginx -- touch /usr/bin/test.txt


# Falcoログの確認

05:35:59.018418997: Error File below a known binary directory opened for writing (user=root user_loginuid=-1 command=touch /usr/bin/test.txt file=/usr/bin/test.txt parent=<NA> pcmdline=<NA> gparent=<NA> container_id=5f7008d770cd image=nginx) k8s.ns=default k8s.pod=nginx container=5f7008d770cd k8s.ns=default k8s.pod=nginx container=5f7008d770cd
その他

Falcoは上記5つのほかにも多くのイベントをデフォルトのモニタリング対象として設定しています。

  • Privilegedコンテナによる権限昇格
  • setns等によるNamespaceの変更
  • Symlinkの作成
  • ssh scpなどSSHバイナリの実行
  • Linux coreutilsパッケージに含まれる実行ファイルの変更
  • パスワード管理に関連する実行ファイル(shadow-utilsパッケージ、passwdなど)の変更

参考ドキュメント