Kubernetes 集群安全加固检查清单:从网络策略到凭证管理的落地实践

枫少@KillBoy
枫少@KillBoy
枫少@KillBoy
管理员
279
文章
0
粉丝
云原生安全1 11字数 5088阅读16分57秒阅读模式
AI智能摘要
AI 生成的文章内容摘要

这份 Kubernetes 安全加固检查清单适用于云安全工程师、平台开发者和集群运维人员,重点覆盖 API 访问、网络策略、Pod 安全、RBAC、镜像供应链、密钥管理和审计日志。它适合用于新集群上线前、重大版本升级后以及定期安全复核,但不能替代威胁建模、漏洞修复、运行时监控和应急响应。Kubernetes 官方也明确提醒,安全清单不是“一刀切”的方案,必须结合业务通信关系、插件能力、集群版本和恢复要求进行评估。

一、先明确场景和风险边界

在执行变更前,先回答四个问题:

  • 集群是托管 Kubernetes,还是由团队自行维护控制平面?
  • CNI、Ingress、Service Mesh、密钥系统和镜像仓库分别由谁负责?
  • 哪些命名空间承载生产流量,哪些用于构建、测试或临时任务?
  • 发生误封、权限不足或控制平面异常时,能否恢复到变更前状态?

Kubernetes 的主要风险通常集中在以下位置:

风险位置常见问题主要控制措施变更影响
API Server认证过宽、匿名访问、管理凭证泄露TLS、身份认证、RBAC、访问审计可能影响运维和自动化工具登录
Pod 与容器以 root 运行、特权容器、宿主机目录挂载Pod Security、SecurityContext、准入控制可能导致部分工作负载无法启动
网络命名空间之间默认互通、出口不可控NetworkPolicy、CNI 策略、出口代理可能中断服务发现、DNS 或外部依赖
身份权限使用默认 ServiceAccount、ClusterRole 过宽最小权限 RBAC、定期审查可能导致控制器或发布流水线权限不足
镜像供应链使用未验证镜像、标签可变、构建来源不明摘要固定、签名验证、来源证明可能阻止现有镜像部署
密钥Secret 明文暴露、长期凭证未轮换外部密钥系统、加密存储、短期凭证需要同步修改应用配置和发布流程
审计与响应无法确认谁在何时执行了高风险操作Audit Policy、集中日志、告警增加日志量和存储成本

建议将生产集群的加固变更拆分为小批次,先在隔离环境和单个非关键命名空间验证,再逐步扩大范围。

Kubernetes 集群分阶段安全加固示意图

二、准备阶段:建立基线和回滚点

1. 记录版本、组件和当前状态

先保存集群版本、节点、命名空间、网络插件和关键工作负载清单:

kubectl version
kubectl get nodes -o wide
kubectl get ns
kubectl get pods -A -o wide
kubectl get crd
kubectl get storageclass
kubectl get networkpolicy -A
kubectl get clusterrolebinding

同时记录以下信息:

  • Kubernetes 版本及其支持周期;
  • CNI 类型和是否支持 NetworkPolicy;
  • Ingress、Service Mesh、策略引擎和镜像准入组件;
  • 控制平面配置的管理方式;
  • etcd 备份与恢复演练记录;
  • 生产命名空间的服务依赖关系;
  • 当前使用的 ServiceAccount、ClusterRole 和外部凭证。

不要把 kubectl get ... -o yaml 的输出直接提交到公共仓库,其中可能包含配置、注解或敏感引用。导出文件应放入受控存储,并限制访问权限。

2. 建立变更前快照

至少保存以下对象的版本化清单:

mkdir -p backup-$(date +%F)

kubectl get ns -o yaml > backup-$(date +%F)/namespaces.yaml
kubectl get deploy,statefulset,daemonset -A -o yaml 
  > backup-$(date +%F)/workloads.yaml
kubectl get role,rolebinding,clusterrole,clusterrolebinding -A -o yaml 
  > backup-$(date +%F)/rbac.yaml
kubectl get networkpolicy -A -o yaml 
  > backup-$(date +%F)/networkpolicy.yaml
kubectl get secret -A -o yaml 
  > backup-$(date +%F)/secrets-metadata.yaml

导出 Secret 时应避免将实际数据复制到普通工作站或工单系统。若需要备份 Secret,应使用加密备份机制,并明确密钥托管、恢复权限和过期策略。

3. 确定风险分级和验收指标

建议在变更单中明确:

  • 高风险:控制平面认证、默认拒绝网络策略、全局 Pod 安全策略、镜像准入;
  • 中风险:命名空间级 RBAC、审计规则、Secret 加密配置;
  • 低风险:补充标签、资源限制、日志字段和非生产环境策略。

每项变更都应有可验证的结果,例如:

  • 未授权 ServiceAccount 无法读取指定资源;
  • 不允许的跨命名空间访问被拒绝;
  • root 或特权 Pod 无法在受保护命名空间创建;
  • 未签名镜像无法进入生产命名空间;
  • 高风险 API 请求能在审计平台中检索;
  • 回滚后业务探针、队列消费和外部依赖恢复正常。

三、实施阶段:按控制面逐项加固

1. API 访问与身份认证

Kubernetes 通过 API 驱动,因此 API Server 是第一道安全边界。官方文档建议对 API 交互使用 TLS,并限制不同身份可以执行的动作。

检查项目:

  • [ ] API Server 的外部访问仅开放给必要的网络或身份入口;
  • [ ] 管理员、自动化流水线和工作负载使用不同身份;
  • [ ] 不使用匿名访问或共享管理员凭证;
  • [ ] 不把普通用户或组件放入 system:masters
  • [ ] 根 CA、客户端证书和云平台访问凭证受到独立保护;
  • [ ] 对管理员和高权限身份设置轮换、吊销和访问审查流程;
  • [ ] 明确云厂商 IAM 与 Kubernetes RBAC 的叠加关系。

可以先查看当前认证用户和权限:

kubectl auth whoami
kubectl auth can-i --list
kubectl auth can-i get secrets -n production
kubectl auth can-i create deployments -n production

不要仅凭 kubectl auth can-i --list 判断完整风险。还应检查云平台角色、Webhook 认证服务、OIDC 声明映射以及集群外部入口的访问控制

2. 网络策略:先盘点通信,再启用默认拒绝

NetworkPolicy 依赖 CNI 插件实现。启用策略前,应先绘制以下通信关系:

  • Pod 到 DNS;
  • Ingress 到应用;
  • 应用到数据库、缓存和消息系统;
  • 跨命名空间调用;
  • 访问云平台 API 或外部 SaaS;
  • 监控、日志、服务网格控制面到业务 Pod。

没有通信清单就直接应用默认拒绝,容易造成服务发现失败、指标缺失或发布流水线中断。

下面是一个命名空间级别的基础示例。它先拒绝所有入口和出口,再按实际依赖增加允许规则:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
  namespace: production
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress

如果应用需要访问同一命名空间内的 DNS 和服务,可增加最小范围规则。DNS 的命名空间标签和端口应根据实际集群确认:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-app-egress
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: orders
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: platform
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: data
          podSelector:
            matchLabels:
              app: postgres
      ports:
        - protocol: TCP
          port: 5432

实施检查:

  • [ ] 先在测试命名空间验证策略;
  • [ ] 明确 CNI 是否支持入口、出口、端口和选择器规则;
  • [ ] 避免使用过宽的 ipBlock
  • [ ] 验证 DNS、健康检查、监控和日志流量;
  • [ ] 记录每条例外规则的业务负责人和失效时间;
  • [ ] 对跨命名空间访问使用明确的命名空间和 Pod 标签;
  • [ ] 不能把 NetworkPolicy 当作节点级防火墙或完整的东西向流量审计方案。

验证示例:

kubectl -n production run netcheck 
  --image=busybox:1.36 
  --rm -it --restart=Never -- sh

# 在临时 Pod 中测试 DNS、应用端口和被禁止的地址
nslookup orders.data.svc.cluster.local
wget -T 3 -O- http://orders

镜像版本仅用于示例,生产环境应使用经过内部审核和固定摘要的诊断镜像。

3. Pod 安全标准与容器运行时约束

Pod Security Admission 可以按命名空间设置 privilegedbaselinerestricted 模式。生产命名空间通常应从审计和告警开始,再根据兼容性逐步切换为强制执行。

示例:

kubectl label ns production 
  pod-security.kubernetes.io/enforce=restricted 
  pod-security.kubernetes.io/enforce-version=v1.31 
  pod-security.kubernetes.io/audit=restricted 
  pod-security.kubernetes.io/audit-version=v1.31 
  pod-security.kubernetes.io/warn=restricted 
  pod-security.kubernetes.io/warn-version=v1.31 
  --overwrite

版本值必须与集群支持的 Pod Security 标准版本匹配,不应机械复制示例。

工作负载应尽量显式设置安全上下文:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: orders
  namespace: production
spec:
  replicas: 2
  selector:
    matchLabels:
      app: orders
  template:
    metadata:
      labels:
        app: orders
    spec:
      serviceAccountName: orders
      automountServiceAccountToken: false
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: orders
          image: registry.example.com/orders@sha256:REPLACE_WITH_DIGEST
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop:
                - ALL
            readOnlyRootFilesystem: true
          resources:
            requests:
              cpu: "100m"
              memory: "128Mi"
            limits:
              memory: "256Mi"

逐项检查:

  • [ ] 容器不以 root 身份运行;
  • [ ] 禁止不必要的特权提升
  • [ ] 删除不需要的 linux capabilities;
  • [ ] 使用默认或经验证的 seccomp 配置;
  • [ ] 避免 hostNetworkhostPIDhostIPC
  • [ ] 避免宿主机路径挂载,确有必要时说明原因;
  • [ ] 为工作负载设置资源请求和限制;
  • [ ] 只读根文件系统经过应用兼容性验证;
  • [ ] 不把调试容器权限长期保留在生产环境。

强制执行前应检查现有工作负载会受到哪些影响:

kubectl label ns production 
  pod-security.kubernetes.io/warn=restricted 
  pod-security.kubernetes.io/warn-version=v1.31 
  --overwrite

观察新发布和重启后的警告,再逐项修复,而不是直接在所有命名空间开启强制模式。

4. RBAC:从默认拒绝和命名空间边界开始

RBAC 的核心目标不是让用户“能操作”,而是让身份只获得完成任务所需的最小权限。重点检查:

  • [ ] 工作负载不使用 default ServiceAccount;
  • [ ] 不给应用绑定 cluster-admin
  • [ ] 优先使用命名空间级 RoleRoleBinding
  • [ ] 只有确有必要时才使用 ClusterRoleClusterRoleBinding
  • [ ] 读取 Secret、创建 Pod、执行 Pod 命令等权限单独审查;
  • [ ] CI/CD 身份与人工运维身份分离;
  • [ ] 定期清理离职人员、临时账号和过期绑定;
  • [ ] 对权限变更保留审批和审计记录。

最小权限示例:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: orders
  namespace: production
automountServiceAccountToken: false
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: orders-config-reader
  namespace: production
rules:
  - apiGroups: [""]
    resources: ["configmaps"]
    resourceNames: ["orders-config"]
    verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: orders-config-reader
  namespace: production
subjects:
  - kind: ServiceAccount
    name: orders
    namespace: production
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: orders-config-reader

检查高权限绑定:

kubectl get clusterrolebindings -o wide
kubectl get rolebindings,rolebindings.rbac.authorization.k8s.io -A -o wide

kubectl auth can-i --as=system:serviceaccount:production:orders 
  get configmaps -n production

kubectl auth can-i --as=system:serviceaccount:production:orders 
  get secrets -n production

注意,automountServiceAccountToken: false 只适用于不需要访问 Kubernetes API 的 Pod。若应用确实需要 API 访问,应创建专用 ServiceAccount,并为其绑定经过验证的最小权限,而不是恢复使用默认账号。

5. 镜像、签名和软件供应链

镜像安全不仅是扫描漏洞,还包括来源、构建过程、依赖和部署时的完整性验证。

检查项目:

  • [ ] 禁止使用未审核的公共镜像;
  • [ ] 生产部署使用不可变摘要,而不是仅使用可变标签;
  • [ ] 构建过程生成 SBOM,并保存构建来源;
  • [ ] 对基础镜像、依赖和构建工具进行漏洞扫描
  • [ ] 镜像签名密钥存放在受保护的密钥系统中;
  • [ ] 部署阶段验证签名、来源和允许的仓库;
  • [ ] 对例外镜像设置责任人、范围和过期日期;
  • [ ] 将镜像准入失败记录到发布系统和审计平台。

查看工作负载中的镜像引用:

kubectl get deploy,statefulset,daemonset -A 
  -o jsonpath='{range .items[*]}{.metadata.namespace}{"t"}{.metadata.name}{"t"}{range .spec.template.spec.containers[*]}{.image}{" "}{end}{"n"}{end}'

签名验证应在 CI/CD 或准入控制阶段完成。具体实现可以使用镜像仓库的签名能力或兼容 OCI 的签名工具,但不要仅凭镜像标签、仓库名称或扫描通过结果判断镜像可信。

变更影响主要包括:

  • 旧镜像未签名,导致已有发布流程失败;
  • 镜像拉取凭证权限不足;
  • 多架构镜像摘要与节点架构不匹配;
  • 调试或紧急镜像无法在生产环境部署。

回滚时应保留上一版已验证签名的镜像摘要和对应部署清单,不建议通过重新使用 latest 标签来恢复。

6. Secret 和密钥管理

Kubernetes Secret 默认适合表达敏感配置对象,但不能因此把它当作完整的密钥管理系统。应根据威胁模型决定是否使用云 KMS、外部 Secret 管理系统或工作负载身份。

检查项目:

  • [ ] 不在 Git、镜像、启动参数和普通日志中写入密钥;
  • [ ] 不把 Secret 内容输出到工单、聊天或构建日志;
  • [ ] 限制读取 Secret 的 RBAC 权限;
  • [ ] 对 etcd 启用静态数据加密,并保护加密配置中的主密钥;
  • [ ] 优先使用短期凭证和自动轮换;
  • [ ] 明确应用读取、缓存和刷新密钥的行为;
  • [ ] 轮换后验证旧凭证是否真正失效;
  • [ ] 为密钥恢复准备独立的访问流程。

检查某个 Secret 的元数据时,不要解码其内容:

kubectl get secret orders-db -n production 
  -o jsonpath='{.metadata.name}{"n"}{.metadata.creationTimestamp}{"n"}'

如果使用 Secret 加密配置,应由集群管理员依据发行版和托管平台文档实施。加密配置通常涉及 API Server 启动参数、KMS 插件或加密提供者切换,不能直接套用某一发行版的静态路径。

实施后应验证:

  • 新建 Secret 是否按预期加密存储;
  • API 读取权限是否符合 RBAC 设计;
  • 备份和恢复流程是否能获得必要的解密能力;
  • 密钥系统不可用时,工作负载是失败、使用缓存还是进入降级模式;
  • 轮换失败是否会触发告警而不是静默使用旧凭证。

7. 审计日志和检测能力

审计日志用于回答“谁在什么时候通过什么身份对什么资源执行了什么操作”。应优先记录高风险资源和高风险动作,同时控制日志规模。

重点审计:

  • 对 Secret 的读取和修改;
  • Role、RoleBinding、ClusterRoleBinding 的变化;
  • Pod、Deployment、DaemonSet 的创建和更新;
  • Exec、Attach、PortForward;
  • 准入配置和网络策略变化;
  • 节点、命名空间和 API 访问控制变化;
  • 认证失败和异常权限请求。

示例策略仅用于说明结构,字段和 API 版本应根据集群版本验证:

apiVersion: audit.k8s.io/v1
kind: Policy
omitStages:
  - RequestReceived
rules:
  - level: Metadata
    resources:
      - group: ""
        resources: ["secrets"]
  - level: RequestResponse
    resources:
      - group: ""
        resources: ["pods/exec", "pods/attach", "pods/portforward"]
  - level: Metadata
    resources:
      - group: "rbac.authorization.k8s.io"
        resources: ["roles", "rolebindings", "clusterroles", "clusterrolebindings"]
  - level: Metadata
    resources:
      - group: "networking.k8s.io"
        resources: ["networkpolicies"]

不要默认记录所有请求的完整响应。过度记录会增加存储、传输和敏感信息暴露风险。审计策略上线后,应确认日志被发送到受控位置,并设置留存、访问和告警规则。

四、验证阶段:证明控制措施确实生效

1. 身份和 RBAC 验证

为每个关键角色设计正向和反向测试:

# 应允许的操作
kubectl auth can-i get configmaps 
  --as=system:serviceaccount:production:orders 
  -n production

# 应拒绝的操作
kubectl auth can-i get secrets 
  --as=system:serviceaccount:production:orders 
  -n production

kubectl auth can-i create clusterrole 
  --as=system:serviceaccount:production:orders

测试结果应与角色设计文档一致。若 can-i 返回允许但业务不需要,应优先收紧权限,而不是把结果标记为“已知风险”后长期保留。

2. 网络策略验证

至少验证三类流量:

  1. 业务必须允许的流量,例如 Ingress 到应用;
  2. 业务必须拒绝的流量,例如不相关命名空间到数据库;
  3. 平台必须保留的流量,例如 DNS、监控和日志。

验证时同时观察应用日志、DNS 解析、服务网格状态、探针和消息消费情况。网络策略只阻断连接并不一定会在应用侧产生清晰错误,不能只看 Pod 是否处于 Running

3. Pod 安全验证

在测试命名空间尝试创建不符合策略的 Pod:

apiVersion: v1
kind: Pod
metadata:
  name: security-negative-test
  namespace: security-test
spec:
  containers:
    - name: test
      image: registry.example.com/test@sha256:REPLACE_WITH_DIGEST
      securityContext:
        privileged: true

预期结果应与当前命名空间的 enforceauditwarn 模式一致。测试完成后删除临时对象:

kubectl delete pod security-negative-test -n security-test 
  --ignore-not-found

4. 镜像和审计验证

  • 用未签名或不在允许仓库中的镜像测试准入;
  • 用已签名且摘要固定的镜像测试正常发布;
  • 执行一次受控的 RBAC 变更,确认审计日志可检索;
  • 执行一次受控的 Secret 访问,确认主体、资源和结果被正确记录;
  • 检查审计日志中是否包含不必要的敏感响应内容;
  • 验证告警能够关联到命名空间、工作负载、身份和变更单。

五、回滚阶段:按控制项准备恢复路径

控制项常见故障回滚方式回滚注意事项
NetworkPolicyDNS、数据库或外部 API 不可达删除或恢复上一版策略先恢复关键依赖,再继续定位过宽或缺失规则
Pod Security新 Pod 无法创建或滚动更新卡住将命名空间恢复到上一阶段模式回滚只应是临时措施,仍需修复不合规工作负载
RBAC发布、控制器或运维命令权限不足恢复上一版 RoleBinding只恢复明确的绑定,不要直接授予 cluster-admin
镜像准入已知业务镜像无法发布使用上一版已验证镜像或临时例外例外必须限定命名空间、镜像和有效期
Secret 加密API Server 或恢复流程异常按发行版的备份配置恢复先确认加密密钥和 etcd 备份可用
审计策略日志量过大或控制面压力升高降低记录级别或恢复旧策略保留高风险操作的最小审计覆盖

回滚前应先保存失败现场,包括事件、控制器日志、审计记录和发布系统状态:

kubectl get events -A --sort-by=.lastTimestamp
kubectl describe pod <pod-name> -n <namespace>
kubectl rollout status deployment/<name> -n <namespace>
kubectl rollout history deployment/<name> -n <namespace>

对 Deployment,只有在上一版本仍然可用且镜像、配置和 Secret 均未失效时,才适合执行:

kubectl rollout undo deployment/<name> -n <namespace>
kubectl rollout status deployment/<name> -n <namespace>

网络策略、RBAC 和命名空间标签的回滚应使用版本化清单,而不是依靠人工逐条删除。对于控制平面配置和 etcd 加密变更,必须使用与集群发行版和托管平台匹配的恢复流程。

六、持续复核清单

完成一次加固不等于风险消失,建议将以下任务纳入周期性复核:

  • [ ] 每次 Kubernetes、CNI、Ingress 或策略组件升级后重新验证;
  • [ ] 定期审查 ClusterRoleBinding、Secret 读取权限和高权限 ServiceAccount;
  • [ ] 定期扫描工作负载是否仍使用 root、特权模式或可变镜像标签;
  • [ ] 定期检查 NetworkPolicy 例外是否仍有业务必要;
  • [ ] 对镜像签名密钥、云平台凭证和应用 Secret 执行轮换演练;
  • [ ] 定期验证审计日志留存、检索和告警;
  • [ ] 至少演练一次 etcd 或集群配置恢复;
  • [ ] 对所有临时例外设置负责人、审批记录和到期时间;
  • [ ] 将安全验证接入 CI/CD,而不是只在生产发布前人工执行。

官方参考资料:

这套流程的重点不是一次性勾完所有项目,而是把风险定位、最小权限、分阶段实施、可观测验证和可控回滚连接起来。对于 Kubernetes 安全加固,任何默认拒绝、全局准入或凭证轮换措施都应先验证业务边界,再逐步扩大到生产范围。

 
枫少@KillBoy
    • 猴智机灵
      猴智机灵 1

      默认拒绝网络策略最怕漏掉DNS

    匿名

    发表评论

    匿名网友

    拖动滑块以完成验证