Skip to content

安全与多租户

Kubernetes 安全不是单一开关,而是身份、权限、工作负载隔离、网络、Secret、镜像供应链和审计共同形成的边界。

认证、鉴权和准入

API 请求依次经过三个阶段:

阶段回答的问题常见机制
Authentication请求者是谁客户端证书、OIDC、ServiceAccount Token
Authorization是否允许该操作RBAC、Webhook Authorizer
Admission Control对象是否允许进入集群Pod Security Admission、ValidatingAdmissionPolicy、Webhook

认证成功不代表拥有操作权限,RBAC 通过 Role/ClusterRole 描述权限,通过 RoleBinding/ClusterRoleBinding 绑定主体。

RBAC 最小权限

Role 只在命名空间内生效:

yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: app
rules:
  - apiGroups: [""]
    resources: ["pods", "pods/log"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-reader
  namespace: app
subjects:
  - kind: Group
    name: app-readers
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

检查权限:

bash
kubectl auth can-i get pods -n app
kubectl auth can-i --list -n app
kubectl auth can-i get secrets --as=system:serviceaccount:app:web -n app

避免给业务 ServiceAccount 绑定 cluster-admin,也不要随意授予对 Secret、Pod exec、节点代理或 RBAC 对象的写权限。

ServiceAccount

每个 Pod 都关联一个 ServiceAccount。业务不访问 Kubernetes API 时,应禁用自动挂载 Token:

yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: web
automountServiceAccountToken: false

需要访问 API 时使用专用 ServiceAccount 和最小 RBAC。Kubernetes 1.24 起不再默认创建长期 Secret Token;交互调试可创建短期 Token:

bash
kubectl create token web -n app --duration=10m

Pod Security Admission

Pod Security Admission 根据命名空间标签应用 Pod Security Standards:

bash
kubectl label namespace app \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/enforce-version=latest \
  pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/warn=restricted

现有命名空间不应直接从无策略切换到 restricted。先使用 warnaudit 观察,再逐步启用 enforce

SecurityContext

一个较严格的 Pod 基线:

yaml
apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  automountServiceAccountToken: false
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  containers:
    - name: web
      image: nginx:1.27
      securityContext:
        allowPrivilegeEscalation: false
        readOnlyRootFilesystem: true
        capabilities:
          drop: ["ALL"]
      volumeMounts:
        - name: cache
          mountPath: /var/cache/nginx
  volumes:
    - name: cache
      emptyDir: {}

具体镜像可能还需要可写的临时目录和指定 UID,应在镜像构建阶段验证,不能机械复制字段。

Secret 安全

Base64 不是加密。Secret 的保护至少包含:

  • API Server 启用 encryption at rest,并制定密钥轮换流程。
  • RBAC 限制 get/list/watch secrets
  • 优先通过 Volume 使用 Secret,谨慎使用可能进入日志和进程环境的环境变量。
  • 使用短期凭据,并接入外部密钥管理和轮换系统。
  • etcd 备份按敏感数据保护,限制访问并加密存储。

网络隔离

NetworkPolicy 只有在 CNI 实现支持时才生效。可先为命名空间设置默认拒绝,再按需开放:

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

启用默认拒绝后需要显式允许 DNS、依赖服务、监控和必要的外部访问,避免把业务全部阻断。

镜像与供应链

  • 使用不可变 tag 或 digest,避免 latest
  • 扫描镜像漏洞和错误配置,保留 SBOM。
  • 对镜像签名并在准入阶段验证来源。
  • 限制可用仓库、特权容器、hostPath、hostNetwork 和危险 capability。
  • 定期更新基础镜像和运行时,不只更新业务依赖。

审计与节点安全

  • 为 API Server 配置审计策略,并把日志发送到受保护的集中存储。
  • 限制 kubelet API、容器运行时 socket 和节点 SSH 权限。
  • 为控制平面和 etcd 使用独立网络边界。
  • 定期轮换证书和凭据,检查匿名访问与未授权端点。
  • 对高权限 debug、exec、port-forward 和临时容器操作保留审计记录。