2020年CNCF中国云原生调查node
10人将获赠CNCF商店$100美圆礼券!python
[](https://mp.weixin.qq.com/s?__...你填了吗?git
问卷连接(https://www.wjx.cn/jq/9714648...)github
做者:Thomas Labarussiasshell
两年前,咱们向大家展现了一个基于 Falco 的 Kubernetes 响应引擎(Kubernetes Response Engine)。其想法是触发无 Kubeless 无服务器的函数来删除受感染的 pod,启动 Sysdig 捕获或将事件转发给 GCP PubSub。见README。json
为了不维护这个自定义堆栈,咱们与社区一块儿努力将全部组件集成到Falcosidekick中,并改进用户体验。在上一个版本 2.20.0 中,咱们有了最后的部分,将 Kubeless 集成为原生输出。更多细节请参见咱们的2020 年回顾。segmentfault
在这篇博文中,咱们将解释使用 Falco + Falcosidekick + Kubeless 堆栈将你本身的响应引擎集成到 K8s 中的基本概念。api
咱们须要 kubernetes 集群,至少运行 1.17 版本,并安装 helm 和 kubectl。bash
跟随官方快速入门页面:服务器
export RELEASE=$(curl -s https://api.github.com/repos/kubeless/kubeless/releases/latest | grep tag_name | cut -d '"' -f 4) kubectl create ns kubeless kubectl create -f https://github.com/kubeless/kubeless/releases/download/$RELEASE/kubeless-$RELEASE.yaml
几秒钟后,咱们能够检查控制器是否启动并运行:
kubectl get pods -n kubeless NAME READY STATUS RESTARTS AGE kubeless-controller-manager-99459cb67-tb99d 3/3 Running 3 2m34s
首先,咱们将建立命名空间给 Falco 和 Falcosidekick:
kubectl create ns falco
增长 helm 仓库:
helm repo add falcosecurity https://falcosecurity.github.io/charts
在实际的项目中,你应该使用 helm pull falcosecurity/falco --untar 获取整个 chart,而后配置 values.yaml。在本教程中,咱们会尽可能简化操做,直接经过 helm install 命令设置配置:
helm install falco falcosecurity/falco --set falco.jsonOutput=true --set falco.httpOutput.enabled=true --set falco.httpOutput.url=http://falcosidekick:2801 -n falco
你应该获得这样的输出:
NAME: falco LAST DEPLOYED: Thu Jan 14 23:43:46 2021 NAMESPACE: falco 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.
你能够看到你的新 Falco pod:
kubectl get pods -n falco NAME READY STATUS RESTARTS AGE falco-ctmzg 1/1 Running 0 111s falco-sfnn8 1/1 Running 0 111s falco-rrg28 1/1 Running 0 111s
参数(--set falco.jsonOutput=true --set falco.httpOutput.enabled=true --set falco.httpOutput.url=http://falcosidekick:2801)在那里配置事件的格式和Falco将发送事件的URL。因为Falco和Falcosidekick位于同一个命名空间中,咱们能够直接使用服务的名称(Falcosidekick)。
过程是挺同样的:
helm install falcosidekick falcosecurity/falcosidekick --set config.kubeless.namespace=kubeless --set config.kubeless.function=delete-pod -n falco
你应该获得这样的输出:
NAME: falcosidekick LAST DEPLOYED: Thu Jan 14 23:55:12 2021 NAMESPACE: falco STATUS: deployed REVISION: 1 NOTES: 1. Get the application URL by running these commands: export POD_NAME=$(kubectl get pods --namespace falco -l "app.kubernetes.io/name=falcosidekick,app.kubernetes.io/instance=falcosidekick" -o jsonpath="{.items[0].metadata.name}") kubectl port-forward $POD_NAME 2801:2801 echo "Visit http://127.0.0.1:2801 to use your application"
咱们检查日志:
kubectl logs deployment/falcosidekick -n falco 2021/01/14 22:55:31 [INFO] : Enabled Outputs : Kubeless 2021/01/14 22:55:31 [INFO] : Falco Sidekick is up and listening on port 2801
Kubeless 显示为 enabled 输出,一切正常 👍。
简单说明参数:
就是这样,咱们真的试图获得一个很好的 UX😉。
咱们不会解释如何编写或如何工做 Kubeless 函数,请阅读官方文档了解更多信息。
咱们真正基本的函数将从 Falco 接收事件(经过 Falcosidekick),检查触发的规则是否在容器中的终端 Shell(参见规则),从事件字段中提取命名空间和 pod 名称,并删除相应的 pod:
from kubernetes import client,config config.load_incluster_config() def delete_pod(event, context): rule = event['data']['rule'] or None output_fields = event['data']['output_fields'] or None if rule and rule == "Terminal shell in container" and output_fields: if output_fields['k8s.ns.name'] and output_fields['k8s.pod.name']: pod = output_fields['k8s.pod.name'] namespace = output_fields['k8s.ns.name'] print (f"Deleting pod \"{pod}\" in namespace \"{namespace}\"") client.CoreV1Api().delete_namespaced_pod(name=pod, namespace=namespace, body=client.V1DeleteOptions())
基本上,这个过程是:
+----------+ +---------------+ +----------+ | Falco +-----------------> Falcosidekick +--------------------> Kubeless | +----^-----+ sends event +---------------+ triggers +-----+----+ | | detects a shell | | | | +----+-------+ deletes | | Powned Pod <----------------------------------------------------------+ +------------+
在部署咱们的函数以前,咱们须要为它建立一个 ServiceAccount,由于它须要在任何命名空间中删除 pod 的权限:
cat <<EOF | kubectl apply -n kubeless -f - apiVersion: v1 kind: ServiceAccount metadata: name: falco-pod-delete --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: falco-pod-delete-cluster-role rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list", "delete"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: falco-pod-delete-cluster-role-binding roleRef: kind: ClusterRole name: falco-pod-delete-cluster-role apiGroup: rbac.authorization.k8s.io subjects: - kind: ServiceAccount name: falco-pod-delete namespace: kubeless EOF
namespace: kubelessetetion.k8s.io serviceaccount/falco-pod-delete created clusterrole.rbac.authorization.k8s.io/falco-pod-delete-cluster-role created clusterrolebinding.rbac.authorization.k8s.io/falco-pod-delete-cluster-role-binding created
只剩下函数自己的安装:
cat <<EOF | kubectl apply -n kubeless -f - apiVersion: kubeless.io/v1beta1 kind: Function metadata: finalizers: - kubeless.io/function generation: 1 labels: created-by: kubeless function: delete-pod name: delete-pod spec: checksum: sha256:a68bf570ea30e578e392eab18ca70dbece27bce850a8dbef2586eff55c5c7aa0 deps: | kubernetes>=12.0.1 function-content-type: text function: |- from kubernetes import client,config config.load_incluster_config() def delete_pod(event, context): rule = event['data']['rule'] or None output_fields = event['data']['output_fields'] or None if rule and rule == "Terminal shell in container" and output_fields: if output_fields['k8s.ns.name'] and output_fields['k8s.pod.name']: pod = output_fields['k8s.pod.name'] namespace = output_fields['k8s.ns.name'] print (f"Deleting pod \"{pod}\" in namespace \"{namespace}\"") client.CoreV1Api().delete_namespaced_pod(name=pod, namespace=namespace, body=client.V1DeleteOptions()) handler: delete-pod.delete_pod runtime: python3.7 deployment: spec: template: spec: serviceAccountName: falco-pod-delete EOF
function.kubeless.io/delete-pod created
在这里,过了一下子,咱们有了一个 Kubeless 函数在命名空间 Kubeless 中运行,它能够由端口 8080 上的服务 delete-pod 触发:
kubectl get pods -n kubeless NAME READY STATUS RESTARTS AGE kubeless-controller-manager-99459cb67-tb99d 3/3 Running 3 3d14h delete-pod-d6f98f6dd-cw228 1/1 Running 0 2m52s
kubectl get svc -n kubeless NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE delete-pod ClusterIP 10.43.211.201 <none> 8080/TCP 4m38s
咱们从建立一个 pod 开始:
kubectl run alpine -n default --image=alpine --restart='Never' -- sh -c "sleep 600"
kubectl get pods -n default NAME READY STATUS RESTARTS AGE alpine 1/1 Running 0 9s
让咱们在里面运行一个shell命令,看看会发生什么:
kubectl exec -i --tty alpine -n default -- sh -c "uptime" 23:44:25 up 1 day, 19:11, load average: 0.87, 0.77, 0.77
正如预期的那样,咱们获得了命令的结果,可是,若是如今获得 pod 的状态:
kubectl get pods -n default NAME READY STATUS RESTARTS AGE alpine 1/1 Terminating 0 103s
💥已被终止💥
咱们如今能够检查组件的日志了。
Falco:
kubectl logs daemonset/falco -n falco {"output":"23:39:44.834631763: Notice A shell was spawned in a container with an attached terminal (user=root user_loginuid=-1 k8s.ns=default k8s.pod=alpine container=5892b41bcf46 shell=sh parent=<NA> cmdline=sh terminal=34817 container_id=5892b41bcf46 image=<NA>) k8s.ns=default k8s.pod=alpine container=5892b41bcf46","priority":"Notice","rule":"Terminal shell in container","time":"2021-01-14T23:39:44.834631763Z", "output_fields": {"container.id":"5892b41bcf46","container.image.repository":null,"evt.time":1610667584834631763,"k8s.ns.name":"default","k8s.pod.name":"alpine","proc.cmdline":"sh","proc.name":"sh","proc.pname":null,"proc.tty":34817,"user.loginuid":-1,"user.name":"root"}}
Falcosidekick:
kubectl logs deployment/falcosidekick -n falco 2021/01/14 23:39:45 [INFO] : Kubeless - Post OK (200) 2021/01/14 23:39:45 [INFO] : Kubeless - Function Response : 2021/01/14 23:39:45 [INFO] : Kubeless - Call Function "delete-pod" OK
(注意,该函数不返回任何内容,这就是为何消息日志是空的)
delete-pod 函数:
kubectl logs deployment/delete-pod -n kubeless 10.42.0.31 - - [14/Jan/2021:23:39:45 +0000] "POST / HTTP/1.1" 200 0 "" "Falcosidekick" 0/965744 Deleting pod "alpine" in namespace "default"
经过这个很是简单的例子,咱们只触及了可能性的表面,如今一切皆有可能,因此不要犹豫,请在Kubernetes Slack #falco上与咱们分享你的评论、想法和成功。也欢迎你贡献。
注 1:你在 Kubernetes 以外运行 Falcosidekick,但仍然想使用 Kubernetes 的输出?没有问题,你能够声明一个 kubeconfig 文件来使用。见README。
注 2:对于那些想用 Knative 代替 Kubeless 的人来讲,它很快就会出现 😉
Enjoy
CNCF (Cloud Native Computing Foundation)成立于2015年12月,隶属于Linux Foundation,是非营利性组织。
CNCF(云原生计算基金会)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。咱们经过将最前沿的模式民主化,让这些创新为大众所用。扫描二维码关注CNCF微信公众号。