Kubescape HTTP Handler 实战指南:用 REST API 将 Kubernetes 安全扫描嵌入 CI/CD 与自动化平台
【免费下载链接】kubescapeKubescape is an open-source Kubernetes security platform for your IDE, CI/CD pipelines, and clusters. It includes risk analysis, security, compliance, and misconfiguration scanning, saving Kubernetes users and administrators precious time, effort, and resources.项目地址: https://gitcode.com/GitHub_Trending/ku/kubescape
导读
Kubescape 不仅是一个命令行扫描工具,还内置了一个可独立部署的 HTTP Handler(服务端)模块:当以服务形式运行时,它会在8080端口启动 Web 服务器,对外暴露一套 REST API,用于以编程方式触发安全扫描、拉取扫描结果、查询扫描状态以及管理缓存结果。本文以仓库中的 httphandler/README.md 为骨架,结合 httphandler 目录下的源码与部署示例,完整讲解四个核心 API 的请求/响应契约、请求体字段、全部环境变量、优雅停机语义、pprof 性能剖析,以及微服务与 Prometheus 两种落地部署方式。读完本文,你将能独立部署 Kubescape 扫描服务,并把"扫描即 API"的能力接入 CI/CD 流水线、自定义仪表盘和定时巡检任务。
Overview:服务化扫描的整体形态
当 Kubescape 以服务(Server)模式运行时,它不再是一次性执行的 CLI 进程,而是一个常驻的 Web 服务。从入口 httphandler/main.go 可以看到,服务启动后会依次完成配置加载(config.LoadConfig("/etc/config"))、凭据加载、服务发现(SaaS 后端接线)、存储初始化,最终调用listener.SetupHTTPListener(ctx)拉起 HTTP 监听。
在 httphandler/listener/setup.go 中,路由注册清晰地划分了三个边界:
- 健康检查(无鉴权):
GET /livez与GET /readyz,供 kubelet 探活使用,因此刻意不设鉴权; - OpenAPI 文档:
GET /docs前缀下的 OpenAPI UI; - 核心业务 API(
/v1/*):包括扫描触发、状态查询、结果获取与删除,以及 Prometheus 指标端点。
完整的/v1路由如下(见 setup.go):
| 方法 | 路径 | 说明 |
|---|---|---|
POST | /v1/scan | 触发一次扫描(异步/同步) |
DELETE | /v1/scan | 取消正在排队或执行的扫描 |
GET | /v1/status | 查询扫描是否仍在进行 |
GET | /v1/results | 获取扫描结果 |
DELETE | /v1/results | 删除缓存的扫描结果 |
GET | /v1/metrics | Prometheus 指标(标记为 deprecated) |
端口默认8080,可通过KS_PORT环境变量覆盖(见 setup.go)。服务支持通过KS_CERT_FILE/KS_KEY_FILE配置 TLS 证书对内网启用 HTTPS,两者必须同时设置。
优雅停机(Graceful Shutdown)
生产环境中最容易忽略的细节是停机行为。HTTP Handler 在收到SIGTERM或SIGINT后不会立刻杀进程,而是执行一套分阶段的优雅停机协议:
- 停止接收新连接与新扫描:服务关闭 admission(准入),正在解析阶段的扫描请求(包括 metrics 扫描)会收到
503 Service Unavailable; - 排空已接受扫描(最长 20 秒):已入队的扫描会继续执行完,包括结果处理与持久化;
- 取消剩余扫描:超过排空窗口仍未完成的扫描,会复用与
DELETE /v1/scan相同的取消机制(context 取消)终止; - 等待 worker 退出:成功的停机必须等到扫描 worker 完全退出;如果 HTTP 排空与 worker 退出在25 秒内未完成,停机会报错、关闭剩余连接,并在尝试一次 OpenTelemetry flush(额外最多 5 秒)后以失败状态退出——该失败路径不保证持久化;
- Completion 回调不参与 worker-join 保证:回调仍保持原有的 best-effort 语义。
上述常量在 listener/setup.go 中定义为scanDrainPeriod = 20 * time.Second与applicationShutdownTimeout = 25 * time.Second,停机编排逻辑实现在serveUntilShutdown(见 setup.go)。worker 侧的排空/取消逻辑见 requestshandler.go 的BeginShutdown与Shutdown。
实践提示:文档明确建议根据自身负载合理设置 Pod 的terminationGracePeriodSeconds,否则 Kubernetes 可能在清理完成前强制终止进程。仓库自带的部署清单 ks-deployment.yaml 给出的参考值是35s(25 秒停机 + 5 秒遥测 + 调度余量)。
API Reference:四个核心端点
POST /v1/scan —— 触发扫描
扫描默认异步执行:请求立即返回一个 scan ID,扫描在后台队列中执行。
Query 参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
wait | bool | false | 是否等待扫描完成(同步模式) |
keep | bool | false | 返回后是否在缓存中保留结果 |
skipPersistence | bool | false | 扫描后不持久化数据 |
callback | string | - | 扫描完成信号回调 URL(仅携带 scan ID,结果仍需GET /v1/results获取) |
说明:
skipPersistence与callback在 README 参数表中未列出,但它们真实存在于 requestparser.go 的ScanQueryParams结构中,是同步扫描与事件驱动集成的有用补充。
异步响应示例:
{ "id": "scan-12345", "type": "busy", "response": "scanning in progress" }同步响应(wait=true):与GET /v1/results的响应一致,直接返回结果对象。
背压与限流:服务接受"有界数量"的排队扫描。从源码看,requestshandler.go 定义了defaultScanQueueCapacity = 10与defaultMaxScanRequestBodyBytes = 1 MiB,分别对应环境变量KS_SCAN_QUEUE_CAPACITY和KS_SCAN_REQUEST_MAX_BYTES。行为包括:
- 队列满时返回
429 Too Many Requests,并携带Retry-After响应头(源码中固定为1秒,见 requestshandler.go); - 请求体超过配置上限时,在扫描被准入之前即返回
413 Request Entity Too Large(通过http.MaxBytesReader实现,见 requestshandler.go); - 停机期间的新扫描请求返回
503 Service Unavailable。
取消扫描(DELETE /v1/scan):虽然 README 的 API 参考未单列,但源码与路由表都支持该端点。带id参数取消指定扫描,不带则取消正在运行的用户扫描;无进行中扫描时返回404,成功则返回type: notBusy的响应(见 requestshandler.go)。
GET /v1/results —— 获取结果
Query 参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
id | string | - | 扫描 ID;为空时返回最新一次扫描结果 |
keep | bool | false | 返回后是否在缓存中保留结果 |
响应(成功):
{ "id": "scan-12345", "type": "v1results", "response": { /* scan results object */ } }响应(错误):
{ "id": "scan-12345", "type": "error", "response": "error message" }响应(进行中):
{ "id": "scan-12345", "type": "busy", "response": "scanning in progress" }源码层面的行为细节(见 requestshandler.go 的validateScanID与GetResults):
- 在线(非 offline)模式下,
id为空会被视为参数错误返回400;offline 模式下才回退到"最新用户扫描"; - 请求的扫描仍在进行时返回
type: busy; - 结果文件不存在时返回
204 No Content; - 扫描执行失败时,服务会把错误明文写入
FailedOutputDir,此时GetResults返回500且response为真正的失败原因(ScanFailedError),而不是 JSON 解析错误(见 requestshandlerutils.go); - 默认情况下结果在返回后被删除(
keep=false),但"最新扫描回退"场景刻意保留结果以防误删。
GET /v1/status —— 检查状态
适合轮询场景:只查状态,不拉取完整结果,开销更小。
Query 参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
id | string | - | 扫描 ID;为空时检查是否有任意扫描在进行 |
响应(进行中):
{ "id": "scan-12345", "type": "busy", "response": "scanning in progress" }响应(完成):
{ "id": "scan-12345", "type": "notBusy", "response": "scanning completed" }注意一个细节:id为空时,服务会先解析为"最新用户扫描",再判断其是否忙碌——这是为了避免/v1/metrics抓取覆盖 latestID 导致状态误报(见 requestshandler.go)。
DELETE /v1/results —— 删除缓存结果
Query 参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
id | string | - | 要删除的扫描 ID;为空时删除最新结果 |
all | bool | false | 删除全部缓存结果 |
all=true时清空OutputDir与FailedOutputDir两个目录(见 requestshandler.go)。removeResultsFile在删除时不仅清理无扩展名的规范 JSON 文件,还会按json/junit/sarif/html/pdf/prometheus/yaml/csv/cyclonedx/spdx等打印器扩展名逐一清理伴生文件(见 requestshandlerutils.go)。
Request / Response Objects:请求体与响应对象详解
Trigger Scan Object(扫描请求体)
{ "format": "json", "excludedNamespaces": ["kube-system", "kube-public"], "includeNamespaces": ["production", "staging"], "useCachedArtifacts": false, "keepLocal": true, "targetType": "framework", "targetNames": ["nsa", "mitre"] }| 字段 | 类型 | 说明 |
|---|---|---|
format | string | 输出格式(默认:json) |
excludedNamespaces | []string | 扫描时要排除的命名空间 |
includeNamespaces | []string | 扫描时要包含的命名空间 |
useCachedArtifacts | bool | 使用本地缓存的策略工件(离线模式) |
keepLocal | bool | 不把结果提交到后端(SaaS) |
targetType | string | "framework"或"control" |
targetNames | []string | 要扫描的框架/控制项名称 |
从 datastructuremethods.go 的ToScanInfo可以补充以下语义:
targetType为framework时,targetNames中含"all"或空串会触发全框架扫描;targetType为control时只扫描指定控制项;未知类型则回退为全量扫描;useCachedArtifacts=true等价于让扫描从getter.DefaultLocalStore读取工件,避免每次扫描都联网下载策略;- 请求体还支持源码中实现的
submit(显式提交结果到 SaaS)、hostScanner(启用主机扫描器)、scanObject(单资源扫描)、exceptions(内联异常策略,服务会将其临时落盘并在扫描后清理)等字段; - 请求体中的命名空间列表会被
strings.Join为逗号分隔字符串后交给ScanInfo,与KS_EXCLUDE_NAMESPACES/KS_INCLUDE_NAMESPACES环境变量同样处理。
安全边界:
account/accessKey会被忽略。这些端点无鉴权,因此服务永远不会从请求体中读取 Kubescape SaaS 身份——否则任何调用者都能把扫描结果(可能包含集群 Secret 与 RBAC 数据)重定向到其控制的账号。身份只来自服务端自身配置:KS_ACCOUNT_ID/KS_ACCESS_KEY,或启动时从凭据文件加载的 credentials(见 datastructuremethods.go 与 main.go 的loadAndSetCredentials)。请求体仍接受这些字段仅为向后兼容,实际不产生任何效果。
Response Object(统一响应对象)
{ "id": "scan-12345", "type": "v1results", "response": { /* payload */ } }| 字段 | 类型 | 说明 |
|---|---|---|
id | string | 扫描标识 |
type | string | 响应类型(见下表) |
response | any | 响应载荷 |
响应类型(Response Types):
| 类型 | 说明 |
|---|---|
v1results | 扫描结果对象 |
busy | 扫描进行中 |
notBusy | 无扫描进行中 |
ready | 扫描完成,结果就绪 |
error | 发生错误 |
API Examples:可直接复制的实战命令
1. 基础异步扫描(三连:触发 → 轮询 → 拉结果)
# 1. 触发扫描 curl -X POST http://127.0.0.1:8080/v1/scan \ -H "Content-Type: application/json" \ -d '{"targetType": "framework", "targetNames": ["nsa"]}' # 2. 检查状态 curl http://127.0.0.1:8080/v1/status # 3. 获取结果 curl http://127.0.0.1:8080/v1/results -o results.json2. 同步扫描(一次调用直接拿到结果)
curl -X POST "http://127.0.0.1:8080/v1/scan?wait=true" \ -H "Content-Type: application/json" \ -d '{"targetType": "framework", "targetNames": ["nsa"]}' \ -o results.json同步模式非常适合 CI 门禁:wait=true会阻塞直到扫描完成并返回完整结果,此时 HTTP 请求可能持续数分钟——这正是 setup.go 中刻意不设置ReadTimeout/WriteTimeout的原因(只设置ReadHeaderTimeout: 10s防御 slowloris)。
3. 只扫描指定命名空间
curl -X POST http://127.0.0.1:8080/v1/scan \ -H "Content-Type: application/json" \ -d '{ "includeNamespaces": ["production"], "targetType": "framework", "targetNames": ["nsa", "mitre"] }'4. 账号集成(在服务端配置,而非每次请求携带)
账号与访问密钥配置在服务端,而不是随请求发送(原因见上文安全边界说明):
# 在服务端 / Helm values 中配置 export KS_ACCOUNT_ID="YOUR-ACCOUNT-ID" export KS_ACCESS_KEY="YOUR-ACCESS-KEY"curl -X POST http://127.0.0.1:8080/v1/scan \ -H "Content-Type: application/json" \ -d '{ "submit": true, "targetType": "framework", "targetNames": ["nsa"] }'5. 删除全部缓存结果
curl -X DELETE "http://127.0.0.1:8080/v1/results?all=true"6. 取消进行中的扫描
# 取消指定扫描(也支持不带 id 取消当前运行中的扫描) curl -X DELETE "http://127.0.0.1:8080/v1/scan?id=scan-12345"7. 事件驱动:扫描完成回调
callback参数允许服务在扫描完成时向指定 URL POST 一个仅含id与status的信号({"id":"...","status":"completed"|"failed"}),接收方需再通过GET /v1/results拉取数据。回调默认关闭(防止服务被当作任意出站请求发射器),需设置KS_CALLBACK_ENABLED=true或配置KS_CALLBACK_ALLOWED_CIDRS白名单才可用;投递为 at-least-once、best-effort,接收方应基于 ID 去重并保留轮询兜底(详见 requestshandlerutils.go)。
Environment Variables:完整环境变量参考
HTTP Handler 的所有行为都由环境变量控制。除 README 列出的变量外,下表同时整合了 main.go、setup.go 与 requestshandlerutils.go 中实际读取的全部变量:
| 变量 | 说明 | 示例 |
|---|---|---|
KS_ACCOUNT_ID | 每次扫描使用的 Kubescape SaaS 账号 ID | xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx |
KS_ACCESS_KEY | 每次扫描使用的 Kubescape SaaS 访问密钥 | your-access-key |
KS_EXCLUDE_NAMESPACES | 默认排除的命名空间(逗号分隔) | kube-system,kube-public |
KS_INCLUDE_NAMESPACES | 默认包含的命名空间(逗号分隔) | production,staging |
KS_FORMAT | 默认输出格式 | json |
KS_FORMAT_VERSION | 输出格式版本 | v2 |
KS_LOGGER_NAME | Logger 名称 | kubescape |
KS_LOGGER_LEVEL | 日志级别 | info,debug,warning,error |
KS_DOWNLOAD_ARTIFACTS | 每次扫描是否下载策略工件;false时从本地缓存加载 | true,false |
KS_SCAN_QUEUE_CAPACITY | 活动扫描之后最多排队的扫描数(默认10) | 10 |
KS_SCAN_REQUEST_MAX_BYTES | POST /v1/scan请求体最大字节数(默认1048576,即 1 MiB) | 1048576 |
KS_PPROF_ENABLED | 启用 pprof 调试服务(默认关闭;仅绑定回环地址) | true,false |
KS_PPROF_ADDR | 启用时 pprof 调试服务的绑定地址 | 127.0.0.1:6060 |
KS_API_TOKEN | /v1/*API 的 Bearer Token 鉴权(可选,默认关闭)。设置后,每个/v1/scan、/v1/results、/v1/status请求都必须携带Authorization: Bearer <token>,否则返回401;健康探针/livez、/readyz与 OpenAPI 文档保持开放。若将:8080暴露到集群之外,建议设置随机值并启用 TLS(KS_CERT_FILE/KS_KEY_FILE)或使用 TLS 终结的 Ingress | openssl rand -hex 32生成 |
KS_PORT | HTTP 监听端口(默认8080) | 8080 |
KS_CERT_FILE/KS_KEY_FILE | TLS 证书与私钥路径(须成对设置) | /etc/tls/tls.crt |
KS_OFFLINE | true时强制离线模式(使用本地工件缓存) | true |
KS_CONTEXT | 集群上下文名称 | my-cluster |
KS_KEEP_LOCAL | 不向 Kubescape SaaS 提交结果 | true |
KS_SUBMIT | 显式开启结果提交(存在即生效,解析失败会告警并忽略) | true |
KS_REGO_PRINT | 打印 rego 规则 | false |
KS_ENABLE_HOST_SCANNER | 启用主机扫描器 | true |
KS_HOST_SCAN_YAML | 主机扫描 YAML 路径 | /path/to/host-scan.yaml |
KS_CALLBACK_ENABLED | 开启扫描完成回调(默认关闭) | true |
KS_CALLBACK_ALLOWED_CIDRS | 回调目标 IP 白名单(逗号分隔 CIDR,配置后即视为开启回调) | 10.0.0.0/8 |
KS_SERVICE_DISCOVERY_FILE_PATH | 文件式服务发现路径(默认/etc/config/services.json),支持 sidecar 与私有集群注入后端端点 | /etc/config/services.json |
KS_CREDENTIALS_SECRET_PATH | 凭据文件路径(默认/etc/credentials) | /etc/credentials |
鉴权细节(源码佐证):bearerAuthMiddleware使用subtle.ConstantTimeCompare做常数时间比较以防时序侧信道,并接受大小写不敏感的Bearer方案(见 setup.go)。鉴权是"增量式加固":扫描 API 默认开放以保证集群内既有安装不因升级而中断,这与默认关闭的 pprof 不同(见 setup.go)。
Deployment Examples:两种典型落地方式
方式一:微服务部署(API 驱动扫描)
在集群内将 Kubescape 部署为微服务,通过 REST API 驱动扫描,是 CI/CD 集成、自定义仪表盘和自动化编排的基础形态。
快速部署:
kubectl apply -f httphandler/examples/microservice/ks-deployment.yaml部署清单 ks-deployment.yaml 已经内置了完整资源:kubescape命名空间、kubescape-discoveryServiceAccount、具有get/list/describe全资源权限的 ClusterRole 与绑定、NodePort 类型 Service,以及 Deployment(quay.io/kubescape/kubescape:latest,启动命令ksserver)。其中值得关注的默认配置:
terminationGracePeriodSeconds: 35,与优雅停机协议匹配;/livez与/readyz健康探针(每 3 秒一次,初始延迟 3 秒);KS_ENABLE_HOST_SCANNER=true启用主机扫描器;KS_DOWNLOAD_ARTIFACTS=true每次扫描都下载最新策略工件。
验证与访问:
# 检查 Pod 状态 kubectl get pods -l app=kubescape # 检查 Service kubectl get svc kubescape # 本地端口转发访问 kubectl port-forward svc/kubescape 8080:8080 # 或获取 LoadBalancer 外部 IP(若修改 serviceType) kubectl get svc kubescape -o jsonpath='{.status.loadBalancer.ingress[0].ip}'部署前应结合集群实际调整:
serviceType(ClusterIP / NodePort / LoadBalancer)、命名空间、资源配额、ServiceAccount 权限。完整部署指南见 httphandler/examples/microservice/README.md。
典型 CI 门禁脚本(来自微服务示例文档):同步扫描后提取合规分数,低于阈值即让流水线失败:
#!/bin/bash RESULT=$(curl -s --header "Content-Type: application/json" \ --request POST \ --data '{"targetType": "framework", "targetNames": ["nsa"]}' \ "http://kubescape:8080/v1/scan?wait=true") # 提取合规分数 SCORE=$(echo $RESULT | jq '.response.summaryDetails.complianceScore') # 分数低于阈值则失败 if (( $(echo "$SCORE < 80" | bc -l) )); then echo "Compliance score $SCORE is below threshold (80)" exit 1 fi定时扫描 CronJob:每 6 小时触发一次 NSA 与 MITRE 框架扫描:
apiVersion: batch/v1 kind: CronJob metadata: name: kubescape-scheduled-scan spec: schedule: "0 */6 * * *" # 每 6 小时 jobTemplate: spec: template: spec: containers: - name: scanner image: curlimages/curl command: - /bin/sh - -c - | curl -X POST http://kubescape:8080/v1/scan \ -H "Content-Type: application/json" \ -d '{"targetType": "framework", "targetNames": ["nsa", "mitre"]}' restartPolicy: OnFailure大集群超时建议:异步触发 + 轮询,而不是长阻塞的同步调用:
# 触发扫描(立即返回) curl -X POST http://127.0.0.1:8080/v1/scan \ -H "Content-Type: application/json" \ -d '{"targetType": "framework", "targetNames": ["nsa"]}' # 轮询状态 while true; do STATUS=$(curl -s http://127.0.0.1:8080/v1/status | jq -r '.type') if [ "$STATUS" != "busy" ]; then break fi sleep 10 done # 获取结果 curl http://127.0.0.1:8080/v1/results -o results.json方式二:Prometheus 集成(指标暴露)
将 Kubescape 指标暴露给 Prometheus 抓取,可把安全态势接入现有可观测体系。指标端点挂载在/v1/metrics(带鉴权与 OpenTelemetry 中间件,见 setup.go),实现在 prometheus.go。抓取方式与 ServiceMonitor 配置请参考 httphandler/examples/prometheus/README.md。
Debugging:调试与性能剖析
开启调试日志
export KS_LOGGER_LEVEL=debug源码中日志级别通过logger.L().SetLevel(...)应用;级别字符串无效时回退到debug并记录错误(见 main.go)。
pprof 性能剖析
pprof 调试服务默认关闭,且只绑定127.0.0.1,因此只能从 Pod 自身的网络命名空间内访问,无法从网络直接触达(这是刻意的安全设计——历史上它曾因日志级别为 debug 而默认暴露未鉴权的剖析端点,见 setup.go 的注释)。启用后通过kubectl port-forward访问:
export KS_PPROF_ENABLED=true # 然后,例如:kubectl port-forward <pod> 6060:6060 # 堆剖析 go tool pprof http://127.0.0.1:6060/debug/pprof/heap # CPU 剖析(采样 30 秒) go tool pprof http://127.0.0.1:6060/debug/pprof/profile?seconds=30 # Goroutine 剖析 go tool pprof http://127.0.0.1:6060/debug/pprof/goroutine若6060端口与 Pod 内 sidecar 冲突,可用KS_PPROF_ADDR修改绑定地址(如KS_PPROF_ADDR=127.0.0.1:6061)。绑定到非回环地址属于刻意的显式选择,仅在可信网络上才应这样做。pprof 处理器注册在独立 mux 上而非http.DefaultServeMux,保证该依赖自包含且由编译器强制(见 setup.go)。
相关文档
- CLI Reference
- Architecture
- Getting Started Guide
- Troubleshooting
- Microservice Deployment Guide
- Prometheus Integration Guide
小结
Kubescape HTTP Handler 将 Kubernetes 安全扫描包装为一组语义清晰、背压可控的 REST API,配合优雅停机、可选的 Bearer 鉴权、pprof 剖析与完善的部署清单,足以支撑从 CI 门禁到定时巡检的各类自动化场景。理解其请求/响应契约(尤其busy/notBusy/v1results/error四种响应类型)、环境变量矩阵与"账号身份只来自服务端配置"的安全边界,是把它正确接入生产环境的关键。若需从源码层面继续深入,可依次阅读 httphandler/listener/setup.go(路由与停机)、httphandler/handlerequests/v1/requestshandler.go(四端点实现)与 httphandler/handlerequests/v1/requestshandlerutils.go(扫描执行与回调投递)。
【免费下载链接】kubescapeKubescape is an open-source Kubernetes security platform for your IDE, CI/CD pipelines, and clusters. It includes risk analysis, security, compliance, and misconfiguration scanning, saving Kubernetes users and administrators precious time, effort, and resources.项目地址: https://gitcode.com/GitHub_Trending/ku/kubescape
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考