1. Kubernetes安全工程导论

Kubernetes 安全工程不是给集群“加一层防火墙”这么简单。它要解决的是一个分布式控制平面在持续变更中,如何保证工作负载身份可信、权限最小、数据不被越权读取、运行时行为可约束、异常可发现可追溯。理解这一章,关键是先建立三个判断:保护什么、对手从哪里进来、边界画在哪里。

一、核心目标:CIA 在集群语境下的具体含义

机密性、完整性、可用性在 Kubernetes 中都有非常具体的落点。机密性对应 Secret、etcd 数据、ServiceAccount Token、镜像中的敏感配置;完整性对应 API 对象不被篡改、镜像摘要不被替换、准入策略不被绕过;可用性对应控制平面组件、节点资源、网络插件和关键工作负载不被拒绝服务或误操作打垮。

但仅用 CIA 还不够。Kubernetes 安全工程还要额外关注身份与授权边界和供应链可信。一个 Pod 能做什么,取决于它使用的 ServiceAccount、绑定的 RBAC、所处的命名空间、挂载的卷、可访问的网络端点以及节点上的运行时权限。把这些关系理清,才能把“安全目标”翻译成可配置、可验证的工程项。

二、威胁模型:从攻击面出发,而不是从工具出发

集群的威胁模型可以按“入口—横向—持久化—影响”来拆。常见入口包括:暴露的 kube-apiserver、未授权 Dashboard、弱口令 kubeconfig、CI/CD 流水线凭据泄露、镜像仓库被投毒、供应链依赖漏洞。进入之后,攻击者往往利用过度宽松的 RBAC、默认 ServiceAccount 自动挂载 Token、特权容器、hostPath 挂载、hostNetwork/hostPID 等向节点或其他命名空间横向移动。持久化则可能通过创建 ClusterRoleBinding、部署 DaemonSet、篡改 admission webhook 或写入 etcd 实现。最终影响可能是数据窃取、加密勒索、资源耗尽或整个集群被接管。

威胁模型的价值在于:它决定了你优先加固哪一层。如果集群只在内网、由单一团队运维,外部暴露面小,重点可能是 RBAC 与工作负载隔离;如果多租户、对外提供 API,重点则要前移到认证、准入和网络策略。

Kubernetes 集群威胁模型与安全边界 外部攻击面 暴露的 apiserver 弱 kubeconfig / Token 镜像仓库投毒 CI/CD 凭据泄露 认证/准入 控制平面安全边界 kube-apiserver etcd RBAC Admission Webhook 审计日志 / 策略 调度/隔离 工作负载边界 ServiceAccount SecurityContext NetworkPolicy ResourceQuota 只读根文件系统 横向移动与持久化路径 特权容器 hostPath / hostPID 过度 RBAC cluster-admin 绑定 默认 Token 挂载 跨命名空间访问 篡改 Webhook 写入 etcd 最终影响 数据窃取 加密勒索 资源耗尽 集群接管 初始入侵

三、安全边界:把“信任”切成可管理的层

Kubernetes 的安全边界不是一条线,而是多层嵌套。最外层是集群边界:谁能访问 apiserver、是否启用匿名认证、证书与 Token 如何轮换。往内是命名空间边界:RBAC 作用域、ResourceQuota、NetworkPolicy 默认拒绝。再往内是工作负载边界:Pod 的 SecurityContext、ServiceAccount 权限、卷类型、能力集。最内层是进程与内核边界:容器运行时、seccomp、AppArmor/SELinux、用户命名空间。

工程上要避免“边界穿透”。例如,一个命名空间内的 Pod 如果挂载了 hostPath,它就可能越过工作负载边界读到节点上的 kubelet 凭据;如果 ServiceAccount 绑定了 cluster-admin,它就能越过命名空间边界操作整个集群。因此,边界设计的原则是:每一层都默认拒绝,只显式放行必要能力。

四、工程化防护体系:从策略到可观测

把安全目标落地,需要一套分层的工程体系。下面给出一个可参考的防护矩阵,字段和取值可根据实际集群调整。

防护层 关键控制 示例配置/参数 验证方式
认证与准入 禁用匿名认证、启用 Node 授权、准入 Webhook --anonymous-auth=false;--authorization-mode=Node,RBAC 匿名请求返回 401;未授权操作返回 403
RBAC 最小权限、避免通配符、定期审计绑定 Role 仅授予 get/list/watch 指定资源 kubectl auth can-i --list 检查实际权限
工作负载 非 root、只读根、禁用特权、限制能力 runAsNonRoot: true;readOnlyRootFilesystem: true;drop: ["ALL"] Pod 启动后 id 非 0;写入根目录失败
网络 默认拒绝、按需放行、限制出站 NetworkPolicy 选择 podSelector: {} 且 policyTypes: [Ingress, Egress] 未放行流量被拒绝;放行流量可连通
运行时 seccomp、AppArmor、镜像签名验证 securityContext.seccompProfile.type: RuntimeDefault 审计日志记录被拦截的系统调用
可观测 审计日志、Falco 类运行时检测、指标告警 审计策略记录 RequestResponse 级别 模拟越权操作后能在日志中定位

五、一个可执行的最小加固示例

假设有一个命名空间 prod,其中运行一个无状态 Web 服务。下面给出一个 Pod 安全上下文片段,用于把工作负载边界收紧到可接受程度:

apiVersion: v1
kind: Pod
metadata:
  name: web
  namespace: prod
spec:
  serviceAccountName: web-sa
  automountServiceAccountToken: false
  securityContext:
    runAsNonRoot: true
    runAsUser: 10001
    fsGroup: 10001
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app
    image: registry.example.com/web@sha256:abc123...
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
        drop: ["ALL"]
    volumeMounts:
    - name: tmp
      mountPath: /tmp
  volumes:
  - name: tmp
    emptyDir: {}

这段配置的关键判断点:automountServiceAccountToken: false 避免默认 Token 被挂载;runAsNonRoot 与 runAsUser 确保进程不以 root 运行;readOnlyRootFilesystem 阻止写入容器根文件系统,只保留 /tmp 可写;drop: ["ALL"] 移除所有 Linux 能力;seccompProfile 使用运行时默认 seccomp 配置。验证时,可以进入 Pod 执行 id 确认 UID 为 10001,尝试 touch /test 应失败,尝试 capsh --print 应看到能力集为空。

工程提示:安全加固不是一次性动作。每次新增工作负载、变更 RBAC、调整网络策略后,都应重新检查边界是否被意外放宽。建议把上述检查项纳入 CI 流水线,用 kubectl auth can-i、kube-score、conftest 或 OPA Gatekeeper 做策略校验。

六、从“知道”到“做到”的判断依据

判断一个集群的安全工程是否到位,可以问四个问题:第一,匿名请求是否被拒绝,未授权操作是否返回 403;第二,是否存在绑定 cluster-admin 的 ServiceAccount,是否存在通配符 RBAC;第三,工作负载是否以非 root 运行、是否禁用特权、是否限制能力;第四,网络是否默认拒绝,审计日志是否能还原一次越权尝试。这四个问题分别对应认证、授权、工作负载和可观测四个层面,任何一个层面失守,其他层面的加固效果都会被打折。