使用 Sysdig Falco 和 Kubernetes 设置运行时容器安全监控

Falco 是一个云原生运行时安全系统,可与容器和原始 Linux 主机一起使用。它由 Sysdig 开发,是 Cloud Native Computing Foundation(云原生计算基金会)的一个 沙箱 项目。Falco 的工作方式是查看文件更改、网络活动、进程表和其他数据是否存在可疑行为,然后通过可插拔后端发送警报。通过内核模块或扩展的 BPF 探测器在主机的系统调用级别检查事件。Falco 包含一组丰富的规则,您可以编辑这些规则以标记特定的异常行为,并为正常的计算机操作创建允许列表。

在本教程中,您将学习如何在 IBM Cloud 上的 Kubernetes 集群上安装和设置 Falco、如何创建合成安全事件以及如何在 Falco 中查看事件。最后,将 Falco 连接起来,在运行时向 Slack 发送安全警报。本教程适用于标准 KubernetesRed Hat OpenShift on IBM Cloud

前提条件

免费试用 IBM Cloud

利用 IBM Cloud Lite 快速轻松地构建您的下一个应用程序。您的免费帐户从不过期,而且您会获得 256 MB 的 Cloud Foundry 运行时内存和包含 Kubernetes 集群的 2 GB 存储空间。了解所有细节并确定如何开始。

在开始之前,您需要准备以下软件:

您需要获取此处的源代码:

$ git clone https://gitlab.com/nibalizer/falco-iks
$ cd falco-iks

验证您是否已设置并配置了 IBM Cloud Kubernetes Service 集群:

$ ibmcloud ks cluster get nibz-nightly-2019-03-29
Retrieving cluster nibz-nightly-2019-03-29...
OK


Name:                   nibz-nightly-2019-03-29
ID:                     0bddeb0c936d4b5a831849a399022389
State:                  normal
Created:                2019-03-29T08:01:08+0000
Location:               wdc06
Master URL:             https://c1.us-east.containers.cloud.ibm.com:30611
Master Location:        Washington D.C.
Master Status:          Ready (12 hours ago)
Ingress Subdomain:      nibz-nightly-2019-03-29.us-east.containers.appdomain.cloud
Ingress Secret:         nibz-nightly-2019-03-29
Workers:                3
Worker Zones:           wdc06
Version:                1.12.6_1546
Owner:                  skrum@us.ibm.com
Monitoring Dashboard:   -
Resource Group ID:      2a926a9173174d94a6eb13284e089f88
Resource Group Name:    default
$ kubectl get nodes -o wide
NAME             STATUS   ROLES    AGE   VERSION       INTERNAL-IP      EXTERNAL-IP      OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
10.188.103.223   Ready       12h   v1.12.6+IKS   10.188.103.223   169.63.131.195   Ubuntu 16.04.6 LTS   4.4.0-143-generic   containerd://1.1.6
10.188.103.242   Ready       12h   v1.12.6+IKS   10.188.103.242   169.63.131.201   Ubuntu 16.04.6 LTS   4.4.0-143-generic   containerd://1.1.6
10.188.103.248   Ready       12h   v1.12.6+IKS   10.188.103.248   169.63.131.248   Ubuntu 16.04.6 LTS   4.4.0-143-generic   containerd://1.1.6

容器运行时环境为 containerd

预估时间

完成本教程大约需要 20 分钟。

使用 Kubernetes 为您所需的任务配置 Falco

由于 Kubernetes 1.12 环境,本教程使用 k8s-with-rbac 文件。Falco 需要设置几个文件:用于运行 Falco daemonset 的 Kubernetes 配置与针对 daemonset 本身的配置的组合。

1:查看 Falco 文件

Falco 使用 Kubernetes 中的服务帐户来访问 Kubernetes API。 falco-account.yaml 规范设置了一种基于角色的通用访问控制三重方法: ServiceAccountClusterRoleClusterRoleBindingClusterRole 包含关于所授予的访问权限的信息。如果您在这些文件中没有进行任何更改,那么 Falco 守护进程只能读取和列示,而不能修改 Kubernetes API 中的任何对象。

$ ls -l
total 20
-rw-r--r-- 1 nibz nibz  931 Mar 29 15:46 falco-account.yaml
drwxr-xr-x 2 nibz nibz 4096 Mar 29 15:51 falco-config/
-rw-r--r-- 1 nibz nibz 2138 Mar 29 15:48 falco-daemonset-configmap.yaml
-rw-r--r-- 1 nibz nibz  196 Mar 29 15:45 falco-service.yaml
-rw-r--r-- 1 nibz nibz   13 Mar 29 15:27 Readme.md

2:配置基于角色的访问控制 (RBAC)

运行以下命令:

$ kubectl apply -f falco-account.yaml
serviceaccount/falco-account created
clusterrole.rbac.authorization.k8s.io/falco-cluster-role created
clusterrolebinding.rbac.authorization.k8s.io/falco-cluster-role-binding created

如果您使用的是 OpenShift,请为刚创建的帐户设置 OpenShift 安全上下文约束。

$ oc adm policy add-scc-to-user privileged -z falco-account

3:应用 Falco 服务对象

Falco 的 Web 前端还需要 Kubernetes 服务:

$ kubectl apply -f falco-service.yaml
service/falco-service created

4:创建 falco-config ConfigMap

Falco 的配置被分成几个文件。 falco.yaml 是指守护进程配置的细节:输出类型、端口等。其他 *_rules.yaml 文件包含 Falco 会针对其进行触发的检查(正在打开的 shell、正在修改的文件等)。通过将 --from-file 自变量与目录一起使用,将所有这些文件组合到单个 ConfigMap 中:

$ kubectl create configmap falco-config --from-file=falco-config
configmap/falco-config created

稍后,在 daemonset 的部署中,该 configmap 将安装在 /etc/falco 下。

5:启动 Falco DaemonSet

最后,运行 Falco 应用程序。它作为 DaemonSet 运行,使您可以在每个节点上运行一个:

$ kubectl apply -f falco-daemonset-configmap.yaml
daemonset.extensions/falco-daemonset created

在首次运行安装期间,它将使用动态内核模块支持 (DKMS) 来编译和安装内核模块,这就是 Falco 选取系统调用的方式。

6:检查 pod 是否正确启动

运行以下命令以查看 pod 及其状态:

nibz@shockley:~/projects/falco/install-falco-iks/git-repo$ kubectl get pod
NAME                    READY   STATUS    RESTARTS   AGE
falco-daemonset-99p8j   1/1     Running   0          26s
falco-daemonset-wf2lf   1/1     Running   0          26s
falco-daemonset-wqrwm   1/1     Running   0          26s

7:检查日志并读取 DKMS 消息

检查日志并记下来自 DKMS 的消息。您会看到 Sysdig 是一个内核模块:

nibz@shockley:~/projects/falco/install-falco-iks/git-repo$ kubectl logs falco-daemonset-wf2lf
* Setting up /usr/src links from host
* Unloading falco-probe, if present
* Running dkms install for falco

Kernel preparation unnecessary for this kernel.  Skipping...

Building module:
cleaning build area...
make -j2 KERNELRELEASE=4.4.0-148-generic -C /lib/modules/4.4.0-148-generic/build M=/var/lib/dkms/falco/0.1.2780dev/build....
cleaning build area...

DKMS: build completed.

falco-probe.ko:
Running module version sanity check.
 - Original module
   - No original module exists within this kernel
 - Installation
   - Installing to /lib/modules/4.4.0-148-generic/kernel/extra/
mkdir: cannot create directory '/lib/modules/4.4.0-148-generic/kernel/extra': Read-only file system
cp: cannot create regular file '/lib/modules/4.4.0-148-generic/kernel/extra/falco-probe.ko': No such file or directory

depmod...

DKMS: install completed.
* Trying to load a dkms falco-probe, if present
falco-probe found and loaded in dkms
Wed May 29 14:55:40 2019: Falco initialized with configuration file /etc/falco/falco.yaml
Wed May 29 14:55:40 2019: Loading rules from file /etc/falco/falco_rules.yaml:
Wed May 29 14:55:40 2019: Loading rules from file /etc/falco/falco_rules.local.yaml:
Wed May 29 14:55:40 2019: Loading rules from file /etc/falco/k8s_audit_rules.yaml:
Wed May 29 14:55:41 2019: Starting internal webserver, listening on port 8765
{"output":"00:00:00.048356736: Informational Container with sensitive mount started (user=root command=container:7c5302fccfcb k8s.ns= k8s.pod= container=7c5302fccfcb image=registry.ng.bluemix.net/armada-master/ibm-kube-fluentd-collector:c16fe1602ab65db4af0a6ac008f99ca2a526e6f6 mounts=/etc/kubernetes/:/etc/kubernetes::false:private,/:/host::false:private,/var/log/:/var/log::false:private,/var/lib/docker:/var/lib/docker::false:private,/var/run/docker.sock:/var/run/docker.sock::false:private,/mnt/ibm-kube-fluentd-persist:/mnt/ibm-kube-fluentd-persist::true:private,/var/data/kubelet/pods/8bf0a002-81eb-11e9-b9cf-c68b81a15994/volumes/kubernetes.io~secret/logmet-secrets-volume:/mnt/logmet/secrets::false:private,/var/data/kubelet/pods/8bf0a002-81eb-11e9-b9cf-c68b81a15994/volumes/kubernetes.io~configmap/fluentd-config:/fluentd/etc/config.d/logmet/::false:private,/var/data:/var/data::false:private,/var/data/kubelet/pods/8bf0a002-81eb-11e9-b9cf-c68b81a15994/volumes/kubernetes.io~configmap/at-fluentd-config:/fluentd/etc/config.d/at/::false:private,/var/data/kubelet/pods/8bf0a002-81eb-11e9-b9cf-c68b81a15994/volumes/kubernetes.io~secret/activity-tracker-secrets-volume:/mnt/activity-tracker/secrets/::false:private,/var/log/at:/var/log/at::false:private,/var/log/at-no-rotate:/var/log/at-no-rotate::false:private,/run/containerd:/run/containerd::false:private,/run/containerd/containerd.sock:/run/containerd/containerd.sock::true:private,/var/data/kubelet/pods/8bf0a002-81eb-11e9-b9cf-c68b81a15994/volumes/kubernetes.io~secret/ibm-kube-fluentd-token-v2q5s:/var/run/secrets/kubernetes.io/serviceaccount::false:private,/var/data/kubelet/pods/8bf0a002-81eb-11e9-b9cf-c68b81a15994/etc-hosts:/etc/hosts::true:private,/var/data/kubelet/pods/8bf0a002-81eb-11e9-b9cf-c68b81a15994/containers/fluentd/35f64419:/dev/termination-log::true:private) k8s.ns= k8s.pod= container=7c5302fccfcb","priority":"Informational","rule":"Launch Sensitive Mount Container","time":"1970-01-01T00:00:00.048356736Z", "output_fields": {"container.id":"7c5302fccfcb","container.image.repository":"registry.ng.bluemix.net/armada-master/ibm-kube-fluentd-collector","container.image.tag":"c16fe1602ab65db4af0a6ac008f99ca2a526e6f6","container.mounts":"/etc/kubernetes/:/etc/kubernetes::false:private,/:/host::false:private,/var/log/:/var/log::false:private,/var/lib/docker:/var/lib/docker::false:private,/var/run/docker.sock:/var/run/docker.sock::false:private,/mnt/ibm-kube-fluentd-persist:/mnt/ibm-kube-fluentd-persist::true:private,/var/data/kubelet/pods/8bf0a002-81eb-11e9-b9cf-c68b81a15994/volumes/kubernetes.io~secret/logmet-secrets-volume:/mnt/logmet/secrets::false:private,/var/data/kubelet/pods/8bf0a002-81eb-11e9-b9cf-c68b81a15994/volumes/kubernetes.io~configmap/fluentd-config:/fluentd/etc/config.d/logmet/::false:private,/var/data:/var/data::false:private,/var/data/kubelet/pods/8bf0a002-81eb-11e9-b9cf-c68b81a15994/volumes/kubernetes.io~configmap/at-fluentd-config:/fluentd/etc/config.d/at/::false:private,/var/data/kubelet/pods/8bf0a002-81eb-11e9-b9cf-c68b81a15994/volumes/kubernetes.io~secret/activity-tracker-secrets-volume:/mnt/activity-tracker/secrets/::false:private,/var/log/at:/var/log/at::false:private,/var/log/at-no-rotate:/var/log/at-no-rotate::false:private,/run/containerd:/run/containerd::false:private,/run/containerd/containerd.sock:/run/containerd/containerd.sock::true:private,/var/data/kubelet/pods/8bf0a002-81eb-11e9-b9cf-c68b81a15994/volumes/kubernetes.io~secret/ibm-kube-fluentd-token-v2q5s:/var/run/secrets/kubernetes.io/serviceaccount::false:private,/var/data/kubelet/pods/8bf0a002-81eb-11e9-b9cf-c68b81a15994/etc-hosts:/etc/hosts::true:private,/var/data/kubelet/pods/8bf0a002-81eb-11e9-b9cf-c68b81a15994/containers/fluentd/35f64419:/dev/termination-log::true:private","evt.time":48356736,"k8s.ns.name":null,"k8s.pod.name":null,"proc.cmdline":"container:7c5302fccfcb","user.name":"root"}}
{"output":"00:00:00.048356736: Informational Container with sensitive mount started (user= command=container:721ef5130945 k8s.ns= k8s.pod= container=721ef5130945 image=docker.io/falcosecurity/falco:dev mounts=/run/containerd/containerd.sock:/host/run/containerd/containerd.sock::true:private,/dev:/host/dev::true:private,/proc:/host/proc::false:private,/boot:/host/boot::false:private,/lib/modules:/host/lib/modules::false:private,/usr:/host/usr::false:private,/etc:/host/etc/::false:private,/var/data/kubelet/pods/c09f7a8d-8221-11e9-b9cf-c68b81a15994/volumes/kubernetes.io~configmap/falco-config:/etc/falco::false:private,/var/data/kubelet/pods/c09f7a8d-8221-11e9-b9cf-c68b81a15994/volumes/kubernetes.io~secret/falco-account-token-jlddc:/var/run/secrets/kubernetes.io/serviceaccount::false:private,/var/data/kubelet/pods/c09f7a8d-8221-11e9-b9cf-c68b81a15994/etc-hosts:/etc/hosts::true:private,/var/data/kubelet/pods/c09f7a8d-8221-11e9-b9cf-c68b81a15994/containers/falco/aa75ae83:/dev/termination-log::true:private) k8s.ns= k8s.pod= container=721ef5130945","priority":"Informational","rule":"Launch Sensitive Mount Container","time":"1970-01-01T00:00:00.048356736Z", "output_fields": {"container.id":"721ef5130945","container.image.repository":"docker.io/falcosecurity/falco","container.image.tag":"dev","container.mounts":"/run/containerd/containerd.sock:/host/run/containerd/containerd.sock::true:private,/dev:/host/dev::true:private,/proc:/host/proc::false:private,/boot:/host/boot::false:private,/lib/modules:/host/lib/modules::false:private,/usr:/host/usr::false:private,/etc:/host/etc/::false:private,/var/data/kubelet/pods/c09f7a8d-8221-11e9-b9cf-c68b81a15994/volumes/kubernetes.io~configmap/falco-config:/etc/falco::false:private,/var/data/kubelet/pods/c09f7a8d-8221-11e9-b9cf-c68b81a15994/volumes/kubernetes.io~secret/falco-account-token-jlddc:/var/run/secrets/kubernetes.io/serviceaccount::false:private,/var/data/kubelet/pods/c09f7a8d-8221-11e9-b9cf-c68b81a15994/etc-hosts:/etc/hosts::true:private,/var/data/kubelet/pods/c09f7a8d-8221-11e9-b9cf-c68b81a15994/containers/falco/aa75ae83:/dev/termination-log::true:private","evt.time":48356736,"k8s.ns.name":null,"k8s.pod.name":null,"proc.cmdline":"container:721ef5130945","user.name":null}}

Falco 正在运行并且正在记录事件。

查看 Falco 的配置

现在,查看一下您为 Falco 设置的配置。

1:检查 DaemonSet 配置

运行以下命令,以告知 DaemonSet 使用您先前设置的服务帐户和权限来运行:

$ cat falco-daemonset-configmap.yaml | grep serviceAcc
      serviceAccount: falco-account

查看 falco-account.yaml 以获取详细信息。此配置提供对 Kubernetes API 服务器中几乎所有内容的读取访问权限。

您将许多重要的目录从 Kubernetes 主机安装到 Falco pod 中:

$ cat falco-daemonset-configmap.yaml | grep -A 11 volumes:
      volumes:
        - 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:

此步骤使 Falco 可以与容器运行时环境进行交互,以提取容器元数据(例如,容器名称和底层镜像名称),查询主机的进程表以发现进程名称。另需注意,此示例将映射 containerd-socket ,而不是 docker-socket

2:检查 Falco 配置文件

Falco 由我们通过 ConfigMap 设置的多个 YAML 文件进行配置。 Falco.yaml 将配置服务器设置, falco_rules.yaml 包含有关警报对象和警报级别的规则。

$ ls falco-config/
falco_rules.local.yaml  falco_rules.yaml  falco.yaml  k8s_audit_rules.yaml

3:查看 Falco 值

该规则监视可能有害的 Netcat 命令,并在发现其处于 WARNING 级别时发出警报。

$ cat falco-config/falco_rules.yaml | grep -A 12 'Netcat Remote'
- rule: Netcat Remote Code Execution in Container
  desc: Netcat Program runs inside container that allows remote code execution
  condition: >
    spawned_process and container and
    ((proc.name = "nc" and (proc.args contains "-e" or proc.args contains "-c")) or
     (proc.name = "ncat" and (proc.args contains "--sh-exec" or proc.args contains "--exec"))
    )
  output: >
    Netcat runs inside container that allows remote code execution (user=%user.name
    command=%proc.cmdline container_id=%container.id container_name=%container.name image=%container.image.repository:%container.image.tag)
  priority: WARNING
  tags: [network, process]

观察 Falco 的实际应用

现在让我们看看 Falco 的实际应用。您将跟踪一个终端中的日志,然后在另一终端中综合创建一些事件,并观察事件是否记录到日志。

1:跟踪第一个终端中的日志

运行以下命令:

$ kubectl get pod
NAME                    READY   STATUS    RESTARTS   AGE
falco-daemonset-99p8j   1/1     Running   0          112m
falco-daemonset-wf2lf   1/1     Running   0          112m
falco-daemonset-wqrwm   1/1     Running   0          112m
$ kubectl logs -f falco-daemonset-99p8j
* Setting up /usr/src links from host
* Unloading falco-probe, if present
* Running dkms install for falco

Kernel preparation unnecessary for this kernel.  Skipping...

Building module:
cleaning build area...
make -j2 KERNELRELEASE=4.4.0-148-generic -C /lib/modules/4.4.0-148-generic/build M=/var/lib/dkms/falco/0.1.2780dev/build....
cleaning build area...

DKMS: build completed.

falco-probe.ko:
Running module version sanity check.
 - Original module
   - No original module exists within this kernel
 - Installation
   - Installing to /lib/modules/4.4.0-148-generic/kernel/extra/
mkdir: cannot create directory '/lib/modules/4.4.0-148-generic/kernel/extra': Read-only file system
cp: cannot create regular file '/lib/modules/4.4.0-148-generic/kernel/extra/falco-probe.ko': No such file or directory

depmod...

DKMS: install completed.
* Trying to load a dkms falco-probe, if present
falco-probe found and loaded in dkms
Wed May 29 14:55:36 2019: Falco initialized with configuration file /etc/falco/falco.yaml
Wed May 29 14:55:36 2019: Loading rules from file /etc/falco/falco_rules.yaml:
Wed May 29 14:55:37 2019: Loading rules from file /etc/falco/falco_rules.local.yaml:
Wed May 29 14:55:37 2019: Loading rules from file /etc/falco/k8s_audit_rules.yaml:
Wed May 29 14:55:38 2019: Starting internal webserver, listening on port 8765
{"output":"00:00:00.020155776: Informational Container with sensitive mount started (user= command=container:9d56002def78 k8s.ns= k8s.pod= container=9d56002def78 image=docker.io/falcosecurity/falco:dev mounts=/run/containerd/containerd.sock:/host/run/containerd/containerd.sock::true:private,/dev:/host/dev::true:private,/proc:/host/proc::false:private,/boot:/host/boot::false:private,/lib/modules:/host/lib/modules::false:private,/usr:/host/usr::false:private,/etc:/host/etc/::false:private,/var/data/kubelet/pods/c0a1a131-8221-11e9-b9cf-c68b81a15994/volumes/kubernetes.io~configmap/falco-config:/etc/falco::false:private,/var/data/kubelet/pods/c0a1a131-8221-11e9-b9cf-c68b81a15994/volumes/kubernetes.io~secret/falco-account-token-jlddc:/var/run/secrets/kubernetes.io/serviceaccount::false:private,/var/data/kubelet/pods/c0a1a131-8221-11e9-b9cf-c68b81a15994/etc-hosts:/etc/hosts::true:private,/var/data/kubelet/pods/c0a1a131-8221-11e9-b9cf-c68b81a15994/containers/falco/cb0bed6e:/dev/termination-log::true:private) k8s.ns= k8s.pod= container=9d56002def78","priority":"Informational","rule":"Launch Sensitive Mount Container","time":"1970-01-01T00:00:00.020155776Z", "output_fields": {"container.id":"9d56002def78","container.image.repository":"docker.io/falcosecurity/falco","container.image.tag":"dev","container.mounts":"/run/containerd/containerd.sock:/host/run/containerd/containerd.sock::true:private,/dev:/host/dev::true:private,/proc:/host/proc::false:private,/boot:/host/boot::false:private,/lib/modules:/host/lib/modules::false:private,/usr:/host/usr::false:private,/etc:/host/etc/::false:private,/var/data/kubelet/pods/c0a1a131-8221-11e9-b9cf-c68b81a15994/volumes/kubernetes.io~configmap/falco-config:/etc/falco::false:private,/var/data/kubelet/pods/c0a1a131-8221-11e9-b9cf-c68b81a15994/volumes/kubernetes.io~secret/falco-account-token-jlddc:/var/run/secrets/kubernetes.io/serviceaccount::false:private,/var/data/kubelet/pods/c0a1a131-8221-11e9-b9cf-c68b81a15994/etc-hosts:/etc/hosts::true:private,/var/data/kubelet/pods/c0a1a131-8221-11e9-b9cf-c68b81a15994/containers/falco/cb0bed6e:/dev/termination-log::true:private","evt.time":20155776,"k8s.ns.name":null,"k8s.pod.name":null,"proc.cmdline":"container:9d56002def78","user.name":null}}
...

2:在第二个终端中创建安全事件

谨记重新导出 KUBECONFIG

$ export KUBECONFIG=/home/nibz/.bluemix/plugins/container-service/clusters/yourcluster.yml
$ kubectl get pod
NAME                    READY   STATUS    RESTARTS   AGE
falco-daemonset-99p8j   1/1     Running   0          3h2m
falco-daemonset-wf2lf   1/1     Running   0          3h2m
falco-daemonset-wqrwm   1/1     Running   0          3h2m
nibz@shockley:~/projects/falco/install-falco-iks/git-repo$ kubectl  exec -it falco-daemonset-99p8j /bin/bash
root@falco-daemonset-99p8j:/# echo "I'm in!"
I'm in!
root@falco-daemonset-99p8j:/#

在第一个终端中,您可以看到事件:

{"output":"17:58:28.064781208: Notice A shell was spawned in a container with an attached terminal (user=root k8s.ns=default k8s.pod=falco-daemonset-99p8j container=9d56002def78 shell=bash parent= cmdline=bash terminal=34816) k8s.ns=default k8s.pod=falco-daemonset-99p8j container=9d56002def78","priority":"Notice","rule":"Terminal shell in container","time":"2019-05-29T17:58:28.064781208Z", "output_fields": {"container.id":"9d56002def78","evt.time":1559152708064781208,"k8s.ns.name":"default","k8s.pod.name":"falco-daemonset-99p8j","proc.cmdline":"bash","proc.name":"bash","proc.pname":null,"proc.tty":34816,"user.name":"root"}}

3:使用 jq 处理事件

当您使用 jq 处理事件时,Falco 会提供有关安全事件以及事件的完整 Kubernetes 上下文的有用信息,例如 pod 名称和名称空间:

$ echo '{"output":"17:58:28.064781208: Notice A shell was spawned in a container with an attached terminal (user=root k8s.ns=default k8s.pod=falco-daemonset-99p8j container=9d56002def78 shell=bash parent= cmdline=bash terminal=34816) k8s.ns=default k8s.pod=falco-daemonset-99p8j container=9d56002def78","priority":"Notice","rule":"Terminal shell in container","time":"2019-05-29T17:58:28.064781208Z", "output_fields": {"container.id":"9d56002def78","evt.time":1559152708064781208,"k8s.ns.name":"default","k8s.pod.name":"falco-daemonset-99p8j","proc.cmdline":"bash","proc.name":"bash","proc.pname":null,"proc.tty":34816,"user.name":"root"}}
> ' | jq '.'
{
  "output": "17:58:28.064781208: Notice A shell was spawned in a container with an attached terminal (user=root k8s.ns=default k8s.pod=falco-daemonset-99p8j container=9d56002def78 shell=bash parent= cmdline=bash terminal=34816) k8s.ns=default k8s.pod=falco-daemonset-99p8j container=9d56002def78",
  "priority": "Notice",
  "rule": "Terminal shell in container",
  "time": "2019-05-29T17:58:28.064781208Z",
  "output_fields": {
    "container.id": "9d56002def78",
    "evt.time": 1559152708064781300,
    "k8s.ns.name": "default",
    "k8s.pod.name": "falco-daemonset-99p8j",
    "proc.cmdline": "bash",
    "proc.name": "bash",
    "proc.pname": null,
    "proc.tty": 34816,
    "user.name": "root"
  }
}

现在您可以触发早前显示的 Netcat 规则:

root@falco-daemonset-99p8j:/# nc -l 4444
^C
kubectl logs falco-daemonset-99p8j
...

{"output":"18:00:41.530249297: Notice Network tool launched in container (user=root command=nc -l 4444 container_id=9d56002def78 container_name=falco image=docker.io/falcosecurity/falco:dev) k8s.ns=default k8s.pod=falco-daemonset-99p8j container=9d56002def78 k8s.ns=default k8s.pod=falco-daemonset-99p8j container=9d56002def78","priority":"Notice","rule":"Lauch Suspicious Network Tool in Container","time":"2019-05-29T18:00:41.530249297Z", "output_fields": {"container.id":"9d56002def78","container.image.repository":"docker.io/falcosecurity/falco","container.image.tag":"dev","container.name":"falco","evt.time":1559152841530249297,"k8s.ns.name":"default","k8s.pod.name":"falco-daemonset-99p8j","proc.cmdline":"nc -l 4444","user.name":"root"}}
...
$ echo '{"output":"18:00:41.530249297: Notice Network tool launched in container (user=root command=nc -l 4444 contain    er_id=9d56002def78 container_name=falco image=docker.io/falcosecurity/falco:dev) k8s.ns=default k8s.pod=falco-    daemonset-99p8j container=9d56002def78 k8s.ns=default k8s.pod=falco-daemonset-99p8j container=9d56002def78","priority":"Notice","rule":"Lauch Suspicious Network Tool in Container","time":"2019-05-29T18:00:41.530249297Z",     "output_fields": {"container.id":"9d56002def78","container.image.repository":"docker.io/falcosecurity/falco",    "container.image.tag":"dev","container.name":"falco","evt.time":1559152841530249297,"k8s.ns.name":"default","k    8s.pod.name":"falco-daemonset-99p8j","proc.cmdline":"nc -l 4444","user.name":"root"}}' | jq '.'
{
  "output": "18:00:41.530249297: Notice Network tool launched in container (user=root command=nc -l 4444 contain    er_id=9d56002def78 container_name=falco image=docker.io/falcosecurity/falco:dev) k8s.ns=default k8s.pod=falco-    daemonset-99p8j container=9d56002def78 k8s.ns=default k8s.pod=falco-daemonset-99p8j container=9d56002def78",
  "priority": "Notice",
  "rule": "Lauch Suspicious Network Tool in Container",
  "time": "2019-05-29T18:00:41.530249297Z",
  "output_fields": {
    "container.id": "9d56002def78",
    "container.image.repository": "docker.io/falcosecurity/falco",
    "container.image.tag": "dev",
    "container.name": "falco",
    "evt.time": 1559152841530249200,
    "k8s.ns.name": "default",
    "k8s.pod.name": "falco-daemonset-99p8j",
    "proc.cmdline": "nc -l 4444",
    "user.name": "root"
  }
}

您已看到 Falco 可以发现什么样的事件以及如何进行配置。

将警报发送到 Slack 通道

现在,您不仅可以将警报转储到标准输出中,还可以对警报进行更有趣的操作。 Falco 可以对警报执行一些其他操作 ,但是本教程展示了如何将警报发送到 Slack 通道。

  1. 更改 falco-config/falco.yaml 以包含您的 slack webhook,并将 enabled 更改为 true

    api.slack.com/incoming-webhooks 查看如何在 Slack 中创建传入 webhook。

    $ cat falco-config/falco.yaml | grep -A1 -B3 hooks.slack
    --
    program_output:
      enabled: false
      keep_alive: false
      program: "jq '{text: .output}' | curl -d @- -X POST https://hooks.slack.com/services/XXX"
    vim falco-config/falco.yaml
    $ cat falco-config/falco.yaml | grep -A1 -B3 hooks.slack
    program_output:
      enabled: true
      keep_alive: false
      program: "jq '{text: .output}' | curl -d @- -X POST https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXX/xxxxxxxxxxxxxxxxxxxxxxxx"
  2. 重做 ConfigMapDaemonSet
    $ kubectl delete configmap falco-config
    $ kubectl create configmap falco-config --from-file=falco-config
    $ kubectl delete -f falco-daemonset-configmap.yaml
    $ kubectl apply -f falco-daemonset-configmap.yaml
  3. 使用 spawn  命令启动 shell,然后您会看到安全警报发布至 Slack:

结束语

您可以使用 Falco 做更多事情,包括将 Falco 事件关联到无服务器计算平台,例如 OpenWhisk 和Knative。希望本介绍为您提供了一些基本信息,帮助您开始下一个项目。

致谢

我非常感谢 Michael Ducy 帮助我完成了本教程。

参考资源

本文翻译自: Set up runtime container security monitoring with Sysdig Falco and Kubernetes (2019-07-02)