RichardoC/kube-audit-rest

GitHub: RichardoC/kube-audit-rest

一款针对托管 Kubernetes 环境的轻量级审计日志工具,通过 ValidatingWebhook 捕获并记录集群中的变更与创建 API 请求,帮助用户在不控制控制平面的前提下以更低成本获取细粒度审计数据。

Stars: 93 | Forks: 7

# kube-audit-rest 想要获取 Kubernetes 审计日志,却没有权限配置 kube-api-server(例如在使用 [EKS](https://docs.aws.amazon.com/eks/latest/userguide/control-plane-logs.html)、[GKE](https://issuetracker.google.com/issues/185868707) 或 [AKS](https://learn.microsoft.com/en-us/azure/aks/monitor-aks#collect-resource-logs) 时)吗? 使用 kube-audit-rest 将所有变更/创建 API 调用捕获到磁盘,然后再将其导出到您的日志基础设施中。 这应该比云服务提供商的托管产品便宜得多,因为后者通常按 API 调用次数收费,并且不支持导入过滤。 如果您确实可以控制 kube-api-server,请使用[内置审计日志](https://kubernetes.io/docs/tasks/debug/debug-cluster/audit/),而不是 kube-audit-rest。 此工具由 [Richard Tweed](https://github.com/RichardoC) 创建并维护。 ## 这是什么 一个用于记录发往 k8s API 的变更/创建请求的简单日志工具。 ## 这不是什么 一个过滤/脱敏/转发系统。这可以通过许多不同的工具来完成,因此该工具不依赖于任何特定的工具链。有关使用 kube-audit-rest 和 Elastic Search 的示例,可以在 中找到。 ## 为什么需要关注? 您可以使用 kube-audit-rest 来避免每年为每个集群支付数千美元的不可过滤 Kubernetes 审计日志费用。 使用 kube-audit-rest,您可以准确配置要记录的事件,并将它们直接发送到您的 SIEM,与仅支持开启/关闭配置(例如 [EKS](https://docs.aws.amazon.com/eks/latest/userguide/control-plane-logs.html))相比,这可以大幅减少存储和摄入费用。 ## Kubernetes 发行版兼容性 未知,但由于 ValidatingWebhook API 对 Kubernetes operator 来说非常基础,因此它可能适用于所有发行版。在最坏的情况下,可以改用 MutatingAdmissionWebhook API,尽管这确实意味着破解此二进制文件可能会导致集群被接管,并且它可能不会记录对象的最终版本。 ## 用法 在 `./k8s` 中可以找到如何部署此服务的示例,并在 `testing/setup.sh` 中可以找到实际部署的步骤。 您可以集中运行此工具(尽管很难区分哪些 API 调用来自哪个集群),也可以在每个集群中运行。 至少您需要: - 在目标 k8s 集群上创建 ValidatingWebhookConfiguration 的权限。 - 一个 CA,以及一个由 Kubernetes 控制平面连接到 kube-audit-rest 的地址签名的 TLS 证书。 - kube-audit-rest 运行在 Kubernetes 控制平面可连接到的某个位置。 - 一些供 kube-audit-rest 写入的磁盘空间。默认为 `/tmp`,这在大多数 linux 发行版上是 ramfs,但在 Kubernetes 上不是。 - 您可以自行构建二进制文件副本,或者通过 [packages 页面](https://github.com/RichardoC/kube-audit-rest/pkgs/container/kube-audit-rest)上的步骤下载 docker 镜像副本。该镜像提供 distroless 版本(默认以及 `latest`),后缀为 -distroless;以及基于 alpine docker 镜像的 -alpine 版本。 如果您在 Kubernetes 集群内部运行 kube-audit-rest 来审计该集群,您还需要: - 一个正在运行的 kube-audit-rest deployment - 一个指向 kube-audit-rest pod 的 service ## 镜像变体 kube-audit-rest 镜像有多种风格,每种风格专为特定用例设计。 这些镜像均适用于 linux/amd64 和 linux/arm64。 VERSION 指的是 github 发布的版本。 COMMIT 指的是对 main 分支的提交。 ### 可用的容器标签 虽然存在以下标签,但建议固定为您希望使用的容器镜像的 digest,这些可以在 上找到。 #### VERSION-distroless 这是生产环境推荐使用的镜像,它仅包含必需的 kube-audit-rest 二进制文件,不包含其他任何内容。 这意味着它的体积最小(约 14 MB),并且容器层数最少,从而减少了镜像拉取时间。 由于它不包含 OS 或任何其他包,因此它将包含最少可能(被报告)的漏洞。 #### VERSION-alpine 这是开发环境推荐使用的镜像,它包含必需的 kube-audit-rest 二进制文件,并使用包含 shell 的默认 alpine 镜像。 它比较大,但由于包含 shell 和其他实用程序,因此最适合用于试验 kube-audit-rest 和诊断问题。 #### COMMIT-distroless 每次提交都会推送生成的容器镜像,因此您可以在等待生成正式版本的同时,体验新功能或错误修复。除此以外,它与 `VERSION-distroless` 相同。 #### COMMIT-alpine 每次提交都会推送生成的容器镜像,因此您可以在等待生成正式版本的同时,体验新功能或错误修复。除此以外,它与 `VERSION-alpine` 相同。 #### latest 这指向最新的 `VERSION-distroless` 镜像,仅推荐用于演示目的。若要稳定使用,请使用带版本号的镜像。 ### 二进制选项 ``` $ kube-audit-rest --help Usage: kube-audit-rest [OPTIONS] Application Options: --logger-filename= Location to log audit log to (default: /tmp/kube-audit-rest.log) --audit-to-std-log Not recommended - log to stderr/stdout rather than a file --logger-max-size= Maximum size for each log file in megabytes (default: 500) --logger-max-backups= Maximum number of rolled log files to store, 0 means store all rolled files (default: 1) --cert-filename= Location of certificate for TLS (default: /etc/tls/tls.crt) --cert-key-filename= Location of certificate key for TLS (default: /etc/tls/tls.key) --server-port= Port to run https server on (default: 9090) -v, --verbosity Uses zap Development default verbose mode rather than production Help Options: -h, --help Show this help message ``` ### 示例用法 这些可以在 <./examples> 目录中找到,并在此 readme 中进行了说明。 ### 资源要求 未知,如果有人进行了基准测试,请提交包含您发现的 pull request。可以按照[此处](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/)的说明进行设置。 当前的设置似乎可以处理每秒 > 12 个请求。 ### 限制记录的请求 在您的 `ValidatingWebhookConfiguration` 中,使用您希望记录的有限资源和动词,而不是 `./k8s/webhook.yaml` 中的 `*`,请参考 [Kubernetes 文档](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#webhook-configuration)。 ## kube-audit-rest 输出的 API 规范 这是注入了 RFC3339 格式的 requestReceivedTimestamp 的 [AdmissionRequest](https://kubernetes.io/docs/reference/config-api/apiserver-admission.v1/#admission-k8s-io-v1-AdmissionRequest) 请求(原因见 #26)。 kube-audit-rest 将每个请求按行记录,格式为压缩后的 json。 ### 示例 ``` {"kind":"AdmissionReview","apiVersion":"admission.k8s.io/v1","request":{"uid":"f452d444-9782-45ce-8eea-85e7c5a2801b","kind":{"group":"authorization.k8s.io","version":"v1","kind":"SelfSubjectAccessReview"},"resource":{"group":"authorization.k8s.io","version":"v1","resource":"selfsubjectaccessreviews"},"requestKind":{"group":"authorization.k8s.io","version":"v1","kind":"SelfSubjectAccessReview"},"requestResource":{"group":"authorization.k8s.io","version":"v1","resource":"selfsubjectaccessreviews"},"operation":"CREATE","userInfo":{"username":"system:admin","groups":["system:masters","system:authenticated"]},"object":{"kind":"SelfSubjectAccessReview","apiVersion":"authorization.k8s.io/v1","metadata":{"creationTimestamp":null,"managedFields":[{"manager":"steve","operation":"Update","apiVersion":"authorization.k8s.io/v1","time":"2022-11-30T17:46:52Z","fieldsType":"FieldsV1","fieldsV1":{"f:spec":{"f:resourceAttributes":{".":{},"f:group":{},"f:resource":{},"f:verb":{},"f:version":{}}}}}]},"spec":{"resourceAttributes":{"verb":"list","group":"helm.cattle.io","version":"v1","resource":"helmchartconfigs"}},"status":{"allowed":false}},"oldObject":null,"dryRun":false,"options":{"kind":"CreateOptions","apiVersion":"meta.k8s.io/v1"}},"requestReceivedTimestamp":"2023-02-04T21:56:41.610688981Z"} {"kind":"AdmissionReview","apiVersion":"admission.k8s.io/v1","request":{"uid":"f3491090-1952-4c4f-8825-6a1d1738e709","kind":{"group":"authorization.k8s.io","version":"v1","kind":"SelfSubjectAccessReview"},"resource":{"group":"authorization.k8s.io","version":"v1","resource":"selfsubjectaccessreviews"},"requestKind":{"group":"authorization.k8s.io","version":"v1","kind":"SelfSubjectAccessReview"},"requestResource":{"group":"authorization.k8s.io","version":"v1","resource":"selfsubjectaccessreviews"},"operation":"CREATE","userInfo":{"username":"system:admin","groups":["system:masters","system:authenticated"]},"object":{"kind":"SelfSubjectAccessReview","apiVersion":"authorization.k8s.io/v1","metadata":{"creationTimestamp":null,"managedFields":[{"manager":"steve","operation":"Update","apiVersion":"authorization.k8s.io/v1","time":"2022-11-30T17:46:51Z","fieldsType":"FieldsV1","fieldsV1":{"f:spec":{"f:resourceAttributes":{".":{},"f:group":{},"f:resource":{},"f:verb":{},"f:version":{}}}}}]},"spec":{"resourceAttributes":{"verb":"list","group":"batch","version":"v1","resource":"jobs"}},"status":{"allowed":false}},"oldObject":null,"dryRun":false,"options":{"kind":"CreateOptions","apiVersion":"meta.k8s.io/v1"}},"requestReceivedTimestamp":"2023-02-04T21:56:41.409906164Z"} ``` ## 指标 kube-audit-rest 提供了一些描述其自身操作的指标,既包括作为特定应用程序的指标,也包括作为 go 二进制文件的指标。 所有特定的应用程序指标都以 `kube_audit_rest_` 为前缀。 | 指标名称 | 指标类型 | 标签 | 描述 | | ---------------------------------------------- | ----------- | ------ | ------------------------------------------- | | kube_audit_rest_valid_requests_processed_total | Counter | | 已处理的有效请求总数 | | kube_audit_rest_http_requests_total | Counter | | 发往 kube-audit-rest 的请求总数 | kube-audit-rest 还公开了来自 (Prometheus Go collector)[https://github.com/prometheus/client_golang/blob/main/prometheus/go_collector.go] 的所有默认 go 指标。 ## 构建 需要 docker 和 rancher desktop 作为在本地使用 k8s 进行构建/测试的方式。 ``` ./testing/setup.sh # 清理 ./testing/cleanup.sh ``` ### 测试 通过构建命令运行,然后以下内容应包含各种准入请求 ``` kubectl -n kube-audit-rest logs -l app=kube-audit-rest ``` 确认 k8s API 对此 webhook 感到满意(日志位置可能有所不同,请查阅 Rancher Desktop 文档) 如果正常工作,应该不会提到此 webhook。 ``` vim $HOME/.local/share/rancher-desktop/logs/k3s.log ``` 失败示例 ``` W1127 13:26:10.911971 3402 dispatcher.go:142] Failed calling webhook, failing open kube-audit-rest.kube-audit-rest.svc.cluster.local: failed calling webhook "kube-audit-rest.kube-audit-rest.svc.cluster.local": failed to call webhook: Post "https://kube-audit-rest.kube-audit-rest.svc:443/log-request?timeout=1s": x509: certificate signed by unknown authority (possibly because of "crypto/rsa: verification error" while trying to verify candidate authority certificate "ca.local") W1127 13:35:04.936121 3402 dispatcher.go:142] Failed calling webhook, failing open kube-audit-rest.kube-audit-rest.svc.cluster.local: failed calling webhook "kube-audit-rest.kube-audit-rest.svc.cluster.local": failed to call webhook: Post "https://kube-audit-rest.kube-audit-rest.svc:443/log-request?timeout=1s": no endpoints available for service "kube-audit-rest" E1127 13:35:04.936459 3402 dispatcher.go:149] failed calling webhook "kube-audit-rest.kube-audit-rest.svc.cluster.local": failed to call webhook: Post "https://kube-audit-rest.kube-audit-rest.svc:443/log-request?timeout=1s": no endpoints available for service "kube-audit-rest" ``` ### 本地测试 这需要安装 [Go 1.21+ 的 go 工具链](https://go.dev/doc/install)、openssl 和 bash。 ``` testing/locally/local-testing.sh ... Test passed {"level":"info","msg":"Server is shutting down...","time":"2022-12-01T19:43:01Z"} {"level":"info","msg":"Server stopped","time":"2022-12-01T19:43:01Z"} Terminated ``` 如果失败,您将看到 `output not as expected`。 ### 单元测试 构成此应用程序的各个组件都有单元测试。要运行它们: ``` go test ./... ``` ## 开发者指南 如果您想了解项目的结构和/或想参与其中协作,可以阅读以下 文档:[ForDevelopers](docs/ForDevelopers.md) ## 已知限制和警告 摘自 k8s 文档 [参见规则](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#validatingwebhook-v1-admissionregistration-k8s-io) ``` Rules describes what operations on what resources/subresources the webhook cares about. The webhook cares about an operation if it matches _any_ Rule. However, in order to prevent ValidatingAdmissionWebhooks and MutatingAdmissionWebhooks from putting the cluster in a state which cannot be recovered from without completely disabling the plugin, ValidatingAdmissionWebhooks and MutatingAdmissionWebhooks are never called on admission requests for ValidatingWebhookConfiguration and MutatingWebhookConfiguration objects. ``` 此 webhook 也无法知道所有其他验证 webhook 是否通过,因此可能会记录之后被其他验证 webhook 拒绝的请求。 由于示例 webhook 配置中存在 `failure: ignore`,为了保障 Kubernetes API 的可用性,可能会存在未被记录的丢失请求。 警告:这将记录请求的所有详细信息!必须对该 namespace 进行非常严格的锁定,以防止权限提升! 此 webhook 还会记录 dry-run 请求。 只有当有效的 API 调用发送到 webhook 二进制文件时,审计日志文件才会存在。 由于 Kubernetes 会重复调用 [webhook](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#reinvocation-policy),API 调用可能会被重复记录,因此可能不会按时间顺序排列。 警告:这只能记录变更/创建请求。不幸的是,只读请求 _不会_ 被发送到变更或验证 webhook。 由于托管 Kubernetes 集群上的动态准入控制工作原理,kube-audit-rest 无法验证请求是否来自控制平面,因此存在攻击者可能用无意义信息淹没日志的风险。这可以通过将 kube-audit-rest 注册为自定义 API(使用 https://github.com/kubernetes-sigs/apiserver-runtime https://kubernetes.io/docs/concepts/extend-kubernetes/)并使用该自定义 API 作为 webhook 来纠正,因为 api server 使用 MTLS 进行身份验证,但如果 kube-audit-rest 服务器宕机,这可能会导致拒绝服务,因此暂时不会这样做。 如果宿主机磁盘已满,kube-audit-rest 将无法写入审计日志。 ### 证书过期/无效 应用程序日志中将充满以下错误,并且在修复之前,您 _不会_ 获得更多的审计日志。 `2022/11/27 15:36:42 http: TLS handshake error from 10.42.0.1:46380: EOF` Kubernetes 可能不会按照您期望的方式在 kube-audit-rest 的副本之间进行负载均衡,因为此行为似乎未在文档中说明。 ### 只读操作未被记录 不幸的是,准入控制器仅在变更和创建时被调用,因此这不能用于捕获只读 API 调用。 一些行为良好的 API 客户端在进行任何 API 调用之前会创建一个 `SubjectAccessReview`。这些可用于发现这些客户端发出的所有 API 调用,但这并不是强制要求的(而且大多数客户端都不会这么做)。 ## 后续步骤 - 解释在完成上述工作之前不提供任何稳定性保证 - 遵循 GH 关于 workflows 等的最佳实践 - 添加 prometheus 指标,特别是针对已处理的总请求数/请求延迟/客户端拒绝无效证书,因为这可能需要警报提示,以说明证书需要更换... - 澄清使用 stdout 是个多么糟糕的主意,最好能提供一个 PoC exploit,演示如何利用它通过日志接管集群... - 让测试用的 main.go 启动/关闭二进制文件,而不是使用 bash,并明确说明 diff 是必需的。 ## 已完成的后续步骤 - 为证书位置使用 flags - 写入文件而不是 STDOUT,并支持轮转和/或最大容量限制 - 使用结构化日志 - 将名称从 kube-rest-audit 重命名为 kube-audit-rest - 添加 examples 文件夹 - 添加本地测试 - 使用 zap 而不是 logrus 进行日志记录,以获得更美观的 http 错误日志 - 尽管存在一些问题,但依然使记录到 stdout/stderr 成为可能,这对于直接捕获不太敏感的信息而无需基础设施非常有用 - 在 git commit 时上传镜像 - 制作 distroless 版本 - 澄清由于 k8s 不保证请求按顺序到达,因此不保证日志是有序的。 - 解释如何通过 webhook resource 限制其记录的资源(只需一个指向 k8s 文档的链接) - 明确指出只有在发送了请求时日志文件才会存在 - 澄清日志文件格式是原始响应,json 中没有换行符,每行一个响应。 - 澄清 Kubernetes 可能不会像预期的那样在副本之间进行负载均衡。 - 说明镜像默认为 distroless - 添加基本指标 - 进行正规的测试,而不是使用 sleeps 来处理异步事件... - 正确配置 GOMAXPROCS 以减少无益的节流 - 设置 workflow 以便在 maintainer 为 PR 添加标签后测试是否可以创建 docker 镜像。 - 明确指出由于 k8s API 的限制,它仅跟踪变更操作。 - 展示 kube-audit-rest 与完整的 elastic stack 配合使用的情况
标签:ETW劫持, EVTX分析, ValidatingWebhook, 子域名突变, 审计日志, 底层编程, 日志审计, 日志记录, 自定义请求头, 请求拦截, 运维工具