Container Intrusion Detection with Falco 📢

こんにちは。Enabling team の山本です。
![1ca2477535ed-20230111.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569971/bcf99e3f-f262-a4e1-94ff-3463d0fa17ed.jpeg)


GKE Dataplane V2 は、eBPF と Cilium を用いた Dataplane を提供します。   
これを使うことで、コンテナへの侵入を検知できます。   
Ransomware や Malware などの脅威が増す中で、Security の Observability を実現します。   
また、eBPF は、Service Mesh への活用が期待されています。   
Service Mesh について、Sidecar Free を期待する人も多いと思います。   
この記事では、Falco を用いて、system call の検知を検証します。
この検証を元に、危険な system call の自動異常検知に取り組みます。

## Setup

### Create GKE Cluster
* required: `--enable-dataplane-v2`
```
gcloud beta container --project "sanbox-334000" clusters create "falco" --zone "asia-northeast1-a" --no-enable-basic-auth --cluster-version "1.24.7-gke.900" --release-channel "regular" --machine-type "e2-medium" --image-type "COS_CONTAINERD" --disk-type "pd-balanced" --disk-size "100" --metadata disable-legacy-endpoints=true --scopes "https://www.googleapis.com/auth/devstorage.read_only","https://www.googleapis.com/auth/logging.write","https://www.googleapis.com/auth/monitoring","https://www.googleapis.com/auth/servicecontrol","https://www.googleapis.com/auth/service.management.readonly","https://www.googleapis.com/auth/trace.append" --max-pods-per-node "110" --num-nodes "1" --logging=SYSTEM,WORKLOAD --monitoring=SYSTEM --enable-ip-alias --network "projects/sanbox-334000/global/networks/default" --subnetwork "projects/sanbox-334000/regions/asia-northeast1/subnetworks/default" --no-enable-intra-node-visibility --default-max-pods-per-node "110" --enable-dataplane-v2 --no-enable-master-authorized-networks --addons HorizontalPodAutoscaling,HttpLoadBalancing,GcePersistentDiskCsiDriver --enable-autoupgrade --enable-autorepair --max-surge-upgrade 1 --max-unavailable-upgrade 0 --enable-shielded-nodes --node-locations "asia-northeast1-a"
```

### Setup Falco
```
yamamoto_daisuke@cloudshell:~ (sanbox-334000)$ helm repo add falcosecurity https://falcosecurity.github.io/charts
"falcosecurity" has been added to your repositories
yamamoto_daisuke@cloudshell:~ (sanbox-334000)$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "falcosecurity" chart repository
Update Complete. ⎈Happy Helming!⎈
yamamoto_daisuke@cloudshell:~ (sanbox-334000)$ helm repo list
NAME            URL
falcosecurity   https://falcosecurity.github.io/charts
yamamoto_daisuke@cloudshell:~ (sanbox-334000)$ helm install falco falcosecurity/falco --set ebpf.enabled=true --set driver.kind=ebpf --namespace falco --create-namespace
```

```
yamamoto_daisuke@cloudshell:~ (sanbox-334000)$ alias k=kubectl
yamamoto_daisuke@cloudshell:~ (sanbox-334000)$ k get ns
NAME              STATUS   AGE
default           Active   10m
falco             Active   11s    # namespace が追加される
kube-node-lease   Active   10m
kube-public       Active   10m
kube-system       Active   10m
yamamoto_daisuke@cloudshell:~ (sanbox-334000)$
yamamoto_daisuke@cloudshell:~ (sanbox-334000)$ k get po -n falco
NAME          READY   STATUS    RESTARTS   AGE
falco-xwqmx   1/1     Running   0          111s    # Daemonset が deploy される
yamamoto_daisuke@cloudshell:~ (sanbox-334000)$
```

#### UI を追加
* required: `ebpf.enabled=true`
* required: `driver.kind=ebpf`
* 特権でアクセスするため。
```
yamamoto_daisuke@cloudshell:~ (sanbox-334000)$ helm upgrade falco falcosecurity/falco \
--set falcosidekick.enabled=true \
--set falcosidekick.webui.enabled=true \
--set ebpf.enabled=true \
--set driver.kind=ebpf  \
-n falco
Release "falco" has been upgraded. Happy Helming!
NAME: falco
LAST DEPLOYED: Tue Jan 10 23:15:43 2023
NAMESPACE: falco
STATUS: deployed
REVISION: 2
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.
yamamoto_daisuke@cloudshell:~ (sanbox-334000)$
```

#### UI 関連の Pod が起動
```
yamamoto_daisuke@cloudshell:~ (sanbox-334000)$ k get po -n falco
NAME                                      READY   STATUS    RESTARTS      AGE
falco-falcosidekick-6fd99b8cf8-5gb5s      1/1     Running   0             12m
falco-falcosidekick-6fd99b8cf8-lxmmn      1/1     Running   0             12m
falco-falcosidekick-ui-5854bc5d66-pjfkx   1/1     Running   1 (12m ago)   12m
falco-falcosidekick-ui-5854bc5d66-w2fpr   1/1     Running   2 (12m ago)   12m
falco-falcosidekick-ui-redis-0            1/1     Running   0             12m
falco-wn7rn                               1/1     Running   0             12m
yamamoto_daisuke@cloudshell:~ (sanbox-334000)$
```

#### UI 関連の Service が起動
```
yamamoto_daisuke@cloudshell:~ (sanbox-334000)$ k get svc -n falco
NAME                           TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)          AGE
falco-falcosidekick            ClusterIP      10.36.9.115   <none>          2801/TCP         13m
falco-falcosidekick-ui         ClusterIP      10.36.2.234   <none>          2802/TCP         13m
falco-falcosidekick-ui-lb      LoadBalancer   10.36.1.198   **.**.**.**   8080:30692/TCP   9m36s    # 一時的に UI を使用するため追加
falco-falcosidekick-ui-redis   ClusterIP      10.36.1.225   <none>          6379/TCP         13m
yamamoto_daisuke@cloudshell:~ (sanbox-334000)$
```

### 検証
#### 検証用の Container を作成
```
cat << EOF  | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: gcloud
  labels:
    app: gcloud
spec:
  containers:
  - name: gcloud
    image: google/cloud-sdk
    command: ['sh', '-c', 'sleep 3600']
EOF
```

#### namespase を参照
```
root@gcloud:/# kubectl get ns
Error from server (Forbidden): namespaces is forbidden: User "system:serviceaccount:default:default" cannot list resource "namespaces" in API group "" at the cluster scope
root@gcloud:/#
```

- 冒頭の画像にあるログです。
```
07:13:07.957298474: Notice Unexpected connection to K8s API Server from container (command=kubectl get ns pid=15953 k8s.ns=default k8s.pod=gcloud container=9c81ea20d30a image=docker.io/google/cloud-sdk:latest connection=10.32.1.23:50230->10.36.0.1:443)
```

## まとめ
Falco の検証準備が整いました。
盗まれた Credentials を利用した攻撃などを検証し、対応していきます。
また、NAT Rule で送信先を制限する対応も基本的な設定として運用していきます。