动静结合的防御体系:Kubernetes 网络零信任与漏洞扫描实战
作者:庸子
适用版本:Kubernetes v1.28+ (Cilium v1.14+, Trivy v0.45+)
阅读时长:约 30 分钟
目录
[动静结合的防御体系:Kubernetes 网络零信任与漏洞扫描实战](#动静结合的防御体系:Kubernetes 网络零信任与漏洞扫描实战)
[第一部分:从单机到全域------构建多层次的 Network Policy 隔离体系](#第一部分:从单机到全域——构建多层次的 Network Policy 隔离体系)
[第二部分:透视流量------利用 Hubble 实现网络可观测性](#第二部分:透视流量——利用 Hubble 实现网络可观测性)
[第三部分:超越 CVE------SBOM 与供应链安全深度扫描](#第三部分:超越 CVE——SBOM 与供应链安全深度扫描)
第一部分:从单机到全域------构建多层次的 Network Policy 隔离体系
【专栏正文】
在上一节我们了解了基础的三层隔离。但在企业级生产环境中,仅有 Pod 之间的隔离是不够的。我们还需要关注 Namespace(命名空间) 和 Egress(出口流量) 的边界控制。
- 命名空间隔离策略
为了实现多租户安全,最理想的做法是:默认跨 Namespace 不可达。我们需要在每个 Namespace 下部署一个 default-deny-all 策略,然后显式放行跨 Namespace 的访问。
实战案例:允许 frontend NS 访问 backend NS
# 在 backend namespace 中应用
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-frontend
namespace: backend
spec:
podSelector: {} # 匹配 backend 下的所有 pod
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
role: frontend # 必须给 frontend NS 打上 label: role=frontend
- Egress 出口管控(防止数据外泄与挖矿)
Pod 不仅会被攻击,也可能成为攻击源(如被植入挖矿病毒连接矿池)。我们需要限制 Pod 只能访问必要的外部地址。
实战案例:只允许访问特定外部域名(需配合 DNS 策略)
注意:原生 K8s NetworkPolicy 不支持域名解析。这需要 Cilium、Calico 等高级 CNI 的支持。此处以 Cilium 为例。
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: egress-to-external-api
namespace: payments
spec:
endpointSelector:
matchLabels:
app: transaction-worker
egress:
# 1. 必须允许 DNS 解析,否则无法解析域名
- toEndpoints:
- matchLabels:
k8s:io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: UDP
# 2. 允许访问外部 API
- toFQDNs:
- matchName: "api.stripe.com"
toPorts:
- ports:
- port: "443"
protocol: TCP
【架构师手记】
实战中的"坑"与"解":
陷阱 1:IPBlock 的不确定性
使用ipBlock时要小心,Pod 的 IP 地址往往是动态的。如果你使用ipBlock排除10.0.0.0/8中的某一段,可能会意外屏蔽掉某个合法的 NodeIP 或 Service IP,导致网络中断。
陷阱 2:DNS 死锁
当配置 Egress 策略时,永远不要忘记放行 DNS。很多新手配置了严格的 Egress 白名单,结果 Pod 连 CoreDNS 都连不上,导致Connection Refused排查一整天。记住:DNS 是所有网络通信的基石。
架构建议:在生产环境中,建议先在 Test Namespace 开启default-deny-all,观察一周日志(Audit 模式),确认没有遗漏的白名单后,再切换到Enforce模式。这是一种"灰度发布"的思想在安全配置中的应用。
第二部分:透视流量------利用 Hubble 实现网络可观测性
【专栏正文】
如果你无法看见流量,就无法证明你的隔离策略是有效的。Hubble 是 Cilium 的网络可观测性平台,它利用 eBPF 提供了深度的流量可视化能力。它不仅仅是一个监控工具,更是安全审计的"黑匣子"。
Hubble 的核心能力:
- Service Map:自动生成服务间的实时拓扑图,展示谁在和谁通信。
- L7 协议可视化:展示 HTTP 的请求路径、状态码(如 404, 500),帮助发现异常扫描。
- 安全事件审计:当流量被 Network Policy 丢弃时,Hubble 会立即记录被丢弃的数据包详情(来源、目的、端口、原因)。
实战操作:
开启 Hubble Relay 和 UI 后,你可以通过 CLI 或 Web 界面查询:
# 查看被 drop 的流量
hubble observe --drop
# 实时监控 namespace payments 中的 HTTP 流量
hubble observe --namespace payments --protocol http
【架构师手记】
架构师的排错心法:
很多时候,网络不通不是因为策略配错了,而是因为应用连错了地址(比如硬编码了旧 IP)或者配置了错误的端口。
在复杂的微服务网络中,tcpdump已经过时了。利用 Hubble,你可以像上帝视角一样看到:"哦,原来order-svc在尝试连接mysql的 8080 端口,而不是 3306,所以被 Drop 了。"
高阶玩法:将 Hubble 的日志对接到 Prometheus/Grafana,你可以建立一套 "安全仪表盘",实时展示集群内的被拒绝连接数。如果这个数值突然飙升,说明可能正在进行大规模的扫描攻击或横向移动尝试。
第三部分:超越 CVE------SBOM 与供应链安全深度扫描
【专栏正文】
传统的漏洞扫描只告诉你"有漏洞"。在 Log4j 爆发时,很多团队花了数天时间在日志里搜索字符串。SBOM (Software Bill of Materials,软件物料清单) 是现代云原生安全的新标准。它记录了镜像内每一个软件包的精确版本、来源和依赖关系。
Trivy 的深度集成:
Trivy 不仅是一个扫描器,它还是一个强大的 SBOM 生成工具。
- 生成 SBOM
# 生成镜像的 SBOM (SPDX 格式)
trivy image --format spdx-json --output sbom.json nginx:latest
- 基于漏洞数据库的策略选择
Trivy 支持配置不同的漏洞数据库,这对架构设计很重要:
- Trivy-DB (轻量级):覆盖 NVD(国家漏洞数据库),更新快,适合 CI/CD 中的快速扫描。
- GitHub Advisory-DB (全面):包含更多特定语言生态的漏洞信息,适合深度分析。
实战:在 CI/CD 中集成 SBOM 上报
在构建流水线中,不仅要扫描,还要将生成的 SBOM 上传到仓库(如 Harbor 或 OCI Registry)。这允许我们在运行时,甚至在发生 0day 攻击时,快速回溯"我的哪个镜像包含了那个有问题的版本"。
# .gitlab-ci.yml 片段
image-scan:
stage: test
script:
- trivy image --exit-code 1 --severity HIGH,CRITICAL $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- trivy image --format cyclonedx --output sbom.json $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- # 将 sbom.json 存储为产物
artifacts:
paths:
- sbom.json
【架构师手记】
为什么 SBOM 是架构师的必选项?
没有清单,你就是在盲修瞎补。假设 OpenSSL 漏洞爆发,如果没有 SBOM,你只能通知所有团队:"请自查你们的镜像是否用了 OpenSSL"。效率极低。
有了 SBOM,架构师只需在集中式数据库中查询:"列出所有依赖了openssl < 1.1.1的镜像"。10 分钟内就能定位所有风险资产。
性能权衡:SBOM 文件可能会很大。在高并发的 CI 流水线中,生成和上传 SBOM 会增加构建时间。建议仅对生产环境发布的镜像生成全量 SBOM,对开发环境仅进行轻量级扫描。
第四部分:防御闭环------镜像签名与准入控制的终极结合
【专栏正文】
如果镜像可以被伪造,漏洞扫描就失去了意义。攻击者可能扫描完镜像,并在推送到仓库的瞬间替换掉镜像层。因此,镜像签名(Image Signing)是漏洞扫描的守护神。
我们引入 Sigstore/Cosign 来实现这一点。
- 签名镜像
在镜像构建成功并通过扫描后,生成签名:
cosign sign --key cosign.key <registry/image:tag>
- Kyverno 验证与扫描的双重策略
我们在 Kubernetes 准入控制层设置两道关卡:
- 关卡 A (Verify):验证镜像签名是否有效。如果签名不对,直接拒绝(拦截了篡改)。
- 关卡 B (ImageVerify):利用 Kyverno 集成的
ImageData调用 Trivy 引擎,实时检查漏洞数量。如果漏洞过多,拒绝(拦截了风险)。
Kyverno 综合策略示例:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: secure-supply-chain
spec:
validationFailureAction: Enforce
background: true
rules:
- name: check-signature-and-scan
match:
resources:
kinds:
- Pod
context:
# 1. 验证签名
- name: sigstore-verify
imageVerify:
image: "{{ request.object.spec.containers[0].image }}"
key: | # 公钥
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8nXh...
-----END PUBLIC KEY-----
validate:
message: "Image must be signed and free of critical vulnerabilities."
foreach:
- list: "context.sigstore-verify.scanResults" # 利用签名验证附带的扫描结果
deny:
conditions:
- key: "{{ element.Severity }}"
operator: In
value:
- CRITICAL
【架构师手记】
架构师的终极防线思考:
安全是一个链条,任何一环断裂都前功尽弃。
- Network Policy 锁住了网络。
- Trivy 发现了漏洞。
- Cosign 保证了身份。
但最大的挑战往往是"例外管理"。业务方总是会跑来找你:"我们要紧急上线,这个镜像有高危漏洞,能不能先让我过?"
架构方案:不要修改通用的ClusterPolicy。使用ValidatingAdmissionPolicy或 AdmissionReview Response Mutations 来提供临时豁免码,或者在 Namespace 上打上特殊的exception: true标签。
关键点:所有的豁免操作必须被 审计日志 完整记录。架构师需要定期审查这份豁免名单,这代表了你的"技术债务"。
总结
这篇进阶文章为你构建了更立体的防御视角:
- 网络:从 Pod 间隔离上升到 Namespace 隔离和 Egress 出口管控。
- 可观测:利用 Hubble 让网络流量"白盒化",告别盲猜。
- 供应链:从单纯的 CVE 扫描演进到 SBOM 管理和镜像签名验证。
这套组合拳,足以应对企业级 Kubernetes 环境中 90% 的安全挑战。