GKEでFalcoを使ってみる

# GKEでFalcoを使ってみる

## Falcoの概要

https://falco.org/ja/

FalcoはSysdigにて作成されたオープンソースのセキュリティツール。
CNCFに寄贈され、インキュベーションプロジェクトとなっている。

ざっくり言うと、コンテナの侵入検知を行える。事前にNGとなるルールを定義し、意図しない振る舞いをしていないかを検知出来る。
脆弱性を突かれてコンテナ内に侵入された際も、何を実行されたのか等を後追いできるためフォレンジックに役立つ。

仕組みとしては、FalcoではカーネルからのLinuxシステムコールを解析し、事前定義したルールに基づきエンジンがチェックする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33101/18823c72-1214-b87d-f321-5b27d18859b8.png)

※ https://falco.org/ja/docs/getting-started/ より引用

以下にも書かれているが、デフォルトのルールとしては以下がある。

https://falco.org/ja/docs/#falco%E3%81%AF%E4%BD%95%E3%82%92%E8%A6%8B%E3%81%A6%E3%81%84%E3%82%8B%E3%81%AE%E3%81%8B

> デフォルトでは、Falco には成熟したルールのセットが同梱されています。 
>
> * 特権コンテナを使用した特権のエスカレーション
> * setns のようなツールを使ったネームスペースの変更
> * /etc, /usr/bin, /usr/sbin などのよく知られたディレクトリへの読み込み/書き込み
> * シンボリックリンクの作成
> * 所有権とモードの変更
> * 予期しないネットワーク接続またはソケットの変異
> * execve を使ってプロセスをSpawnした
> * sh, bash, csh, zsh などのシェルバイナリの実行
> * SSH バイナリ ssh, scp, sftp などを実行する
> * Linux の coreutils 実行ファイルを変異させる
> * ログインバイナリの変異
> * shadowutil や passwd の実行ファイルを変異させる
>   * shadowconfig
>   * pwck
>   * chpasswd
>   * getpasswd
>   * change
>   * useradd
>
> などなど

ノイズなどが多い場合や、検知したい項目がある場合は以下のyamlを修正することでルールの変更が出来る。
デフォルトで非常に多くの項目(3000行以上)があるので、先ずはデフォルトのルールに従って運用していって、設定ファイルを育てていくのが良さそう。

https://github.com/falcosecurity/charts/blob/master/falco/rules/falco_rules.yaml


## 環境作成

### GKEクラスタの作成

今回は GKE version 1.20.12-gke.1500 を使用した。
またDataplane v2も有効化している。

### helmリポジトリの登録

Falcoを実行する最も安全な方法はホスト(GKEのノード側)に直接インストールすることとされている。
理由としてはFalco自身がKubernetesから分離されているため。

GKEの場合はノードのイメージはCOS(Container-OptimizedOS)を使うのが一般的なため、独自のイメージを作るのは避けたい。
そもそも、COSはセキュリティが強化されており、システムコールをFalcoが処理するためのカーネルモジュールを挿入できない。
しかし、COSの場合はeBPFを使用してシステムコールのストリームをFalcoに提供する機能があるため、実現できる。

helmにて導入を行う。


https://github.com/falcosecurity/charts/tree/master/falco

```shell
~ helm repo add falcosecurity https://falcosecurity.github.io/charts
~ helm repo update
~ helm repo list | grep falco
falcosecurity	https://falcosecurity.github.io/charts
```

### Falcoのインストール

```shell
~ helm install falco falcosecurity/falco --set ebpf.enabled=true
NAME: falco
LAST DEPLOYED: Fri Dec 17 11:19:02 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Falco agents are spinning up on each node in your cluster. After a few
seconds, they are going to start monitoring your containers looking for
security issues.


No further action should be required.


Tip:
You can easily forward Falco events to Slack, Kafka, AWS Lambda and more with falcosidekick.
Full list of outputs: https://github.com/falcosecurity/charts/falcosidekick.
You can enable its deployment with `--set falcosidekick.enabled=true` or in your values.yaml.
See: https://github.com/falcosecurity/charts/blob/master/falcosidekick/values.yaml for configuration values.
```

podが起動している。

```shell
~ kubectl get pod
NAME          READY   STATUS    RESTARTS   AGE
falco-cpmbq   1/1     Running   0          11m
falco-j6nmt   1/1     Running   0          11m

kubectl get configmap
NAME               DATA   AGE
falco              5      29m


```

## どのようなログが出るか見てみる

### podの起動

nginxを起動して、その中で試してみる。

```yaml:deploy_nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 #
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.21.4
        ports:
        - containerPort: 80
```

```shell
~ kubectl apply -f deploy_nginx.yml
deployment.apps/nginx-deployment created
```

Falcoのログは標準出力に出ているため、 sternを使用して見ていく

https://github.com/wercker/stern

```shell
stern falco
```

### sshで接続

nginxコンテナにsshで接続する

```shell

~ kubectl exec -it nginx-deployment-6b689c98c5-nbz7r -- sh
```

以下のルールにひっかかる。

https://github.com/falcosecurity/charts/blob/master/falco/rules/falco_rules.yaml#L1990-L2001

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


Falcoには以下のログが記録されている

```shell
falco-cpmbq falco 09:25:27.022956239: Notice A shell was spawned in a container with an attached terminal (user=root user_loginuid=-1 k8s.ns=default k8s.pod=nginx-deployment-6b689c98c5-2vmhk container=d003af23ea19 shell=sh parent=runc cmdline=sh terminal=34816 container_id=d003af23ea19 image=docker.io/library/nginx) k8s.ns=default k8s.pod=nginx-deployment-6b689c98c5-2vmhk container=d003af23ea19
```

### ファイルの追加

nginxのコンテナ内にファイルを追加してみる。

```shell
touch /etc/sakon.conf
```

以下のルールにひっかかる。

https://github.com/falcosecurity/charts/blob/master/falco/rules/falco_rules.yaml#L1246-L1251

```yaml
- rule: Write below etc
  desc: an attempt to write to any file below /etc
  condition: write_etc_common
  output: "File below /etc opened for writing (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline parent=%proc.pname pcmdline=%proc.pcmdline file=%fd.name program=%proc.name gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4] container_id=%container.id image=%container.image.repository)"
  priority: ERROR
  tags: [filesystem, mitre_persistence]
```

Falcoには以下のログが記録されている

```shell
falco-cpmbq falco 09:30:22.522301023: Error File below /etc opened for writing (user=root user_loginuid=-1 command=touch /etc/sakon.conf parent=sh pcmdline=sh file=/etc/sakon.conf program=touch gparent=<NA> ggparent=<NA> gggparent=<NA> container_id=d003af23ea19 image=docker.io/library/nginx) k8s.ns=default k8s.pod=nginx-deployment-6b689c98c5-2vmhk container=d003af23ea19 k8s.ns=default k8s.pod=nginx-deployment-6b689c98c5-2vmhk container=d003af23ea19
```

### パッケージのインストール

```
# apt update
Get:1 http://security.debian.org/debian-security bullseye-security InRelease [44.1 kB]
Get:2 http://deb.debian.org/debian bullseye InRelease [116 kB]
Get:3 http://deb.debian.org/debian bullseye-updates InRelease [39.4 kB]
Get:4 http://security.debian.org/debian-security bullseye-security/main amd64 Packages [99.5 kB]
Get:5 http://deb.debian.org/debian bullseye/main amd64 Packages [8180 kB]
Get:6 http://deb.debian.org/debian bullseye-updates/main amd64 Packages [2592 B]
Fetched 8481 kB in 2s (4443 kB/s)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
All packages are up to date.
```

Falcoには以下のログが記録されている

```
falco-cpmbq falco 04:21:47.738779670: Error Package management process launched in container (user=root user_loginuid=-1 command=apt update container_id=a041c1608bbd container_name=nginx image=docker.io/library/nginx:1.21.4) k8s.ns=default k8s.pod=nginx-deployment-6b689c98c5-nbz7r container=a041c1608bbd k8s.ns=default k8s.pod=nginx-deployment-6b689c98c5-nbz7r container=a041c1608bbd
```

vimのインストール

```
# apt install vim
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  libgpm2 vim-common vim-runtime xxd
Suggested packages:
  gpm ctags vim-doc vim-scripts
The following NEW packages will be installed:
  libgpm2 vim vim-common vim-runtime xxd
0 upgraded, 5 newly installed, 0 to remove and 0 not upgraded.
Need to get 8173 kB of archives.
After this operation, 36.9 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
```

Falcoには以下のログが記録されている

```
falco-cpmbq falco 04:22:54.512922215: Error Package management process launched in container (user=root user_loginuid=-1 command=apt install vim container_id=a041c1608bbd container_name=nginx image=docker.io/library/nginx:1.21.4) k8s.ns=default k8s.pod=nginx-deployment-6b689c98c5-nbz7r container=a041c1608bbd k8s.ns=default k8s.pod=nginx-deployment-6b689c98c5-nbz7r container=a041c1608bbd
```

以下のルールにひっかかる。

https://github.com/falcosecurity/charts/blob/master/falco/rules/falco_rules.yaml#L2419-L2433


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

## falcosidekickを使ってみる

Falcoには `falcosidekick` という様々なエコシステムに接続するためのdaemon機能が追加出来る。
UIに接続できたり、SlackやTeams、Google Chatなどに通知を送ったり、DatadogやPrometheusにメトリクスを送ったりすることが可能となる。
KafkaやGCPのPub/SubやAWS SQS,SNSなどにもStreamingを送ることが可能。

https://github.com/falcosecurity/falcosidekick

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33101/0b04819a-3904-cd66-0628-6d6cbe749704.png)

※ https://falco.org/blog/extend-falco-outputs-with-falcosidekick/ より引用

### falcosidekickを有効にする

```shell
helm upgrade falco falcosecurity/falco \
--set falcosidekick.enabled=true \
--set falcosidekick.webui.enabled=true \
--set falcosidekick.config.slack.webhookurl="https://hooks.slack.com/services/XXXXXXXX" \
--set ebpf.enabled=true
```

podが上がってきている。また、serviceも作られている

```shell
 ~ kubectl get pod
NAME                                      READY   STATUS    RESTARTS   AGE
falco-2dn9w                               1/1     Running   0          7m3s
falco-falcosidekick-c6fcc8d5c-24hc9       1/1     Running   0          9m47s
falco-falcosidekick-c6fcc8d5c-q9wds       1/1     Running   0          9m47s
falco-falcosidekick-ui-7cb9856769-z4qxp   1/1     Running   0          9m47s
falco-k7dfq                               1/1     Running   0          7m41s
nginx-deployment-6b689c98c5-2vmhk         1/1     Running   1          19h
nginx-deployment-6b689c98c5-62gdl         1/1     Running   0          19h

~ kubectl get svc
NAME                     TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
falco-falcosidekick      ClusterIP   10.108.6.189   <none>        2801/TCP   10m
falco-falcosidekick-ui   ClusterIP   10.108.12.65   <none>        2802/TCP   10m
kubernetes               ClusterIP   10.108.0.1     <none>        443/TCP    2d4h
```

### slack通知を確認する

先程同様touchでファイルを作ってみる

```shell
touch /etc/sakon2.conf
```

以下のように通知が送られる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33101/0a902126-00ce-d7e5-127e-27205f86080d.png)


### UIに接続する

```shell
kubectl port-forward svc/falco-falcosidekick 2801
```

`http://localhost:2802/ui/#/` でブラウザからアクセス可能


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33101/c48cf4cf-8943-1c94-77b8-2744170ed453.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33101/e178512e-5cad-edd1-91bb-95716f915a09.png)