# k8s 安全与认证授权


## 导读

Kubernetes 的安全模型由认证、授权、准入控制三道关卡串联组成，任何一个 API 请求都要依次通过这三层校验才能写入 etcd。ServiceAccount 是 Pod 在集群中的身份凭证，RBAC 则定义了这个身份能操作哪些资源。掌握这套链路，才能在多租户和生产环境中精准控制权限边界。

## 核心概念

每个发往 kube-apiserver 的请求都会经历三个阶段。第一阶段是认证（Authentication），确认"你是谁"，支持客户端证书、Bearer Token、ServiceAccount Token 等多种方式。第二阶段是授权（Authorization），判断"你能做什么"，Kubernetes 默认启用 RBAC 模式。第三阶段是准入控制（Admission Control），在对象持久化前做最后的校验或修改，分为 Mutating 和 Validating 两类 Webhook。三道关卡顺序固定，前一道不通过则请求直接被拒绝，不会进入下一阶段。

ServiceAccount 是命名空间级别的资源，为 Pod 提供访问 API Server 的身份。每个 Pod 创建时会自动挂载该 ServiceAccount 的 Token 到 `/var/run/secrets/kubernetes.io/serviceaccount/token`，应用程序通过读取该文件完成 API 调用时的身份标识。从 1.24 版本开始，ServiceAccount 不再自动生成 Secret 形式的长效 Token，改为按需通过 TokenRequest API 签发短期 Token，有效降低了凭证泄露后的风险窗口。

```mermaid
graph LR
    A[API 请求] --> B[认证 AuthN]
    B --> B1[证书 / Token / SA]
    B1 --> C{身份验证通过?}
    C -->|否| Z1[401 Unauthorized]
    C -->|是| D[授权 AuthZ]
    D --> D1[RBAC 策略检查]
    D1 --> E{权限校验通过?}
    E -->|否| Z2[403 Forbidden]
    E -->|是| F[准入控制 Admission]
    F --> G[Mutating Webhook]
    G --> H[Validating Webhook]
    H --> I{准入校验通过?}
    I -->|否| Z3[请求拒绝]
    I -->|是| J[写入 etcd]
```

图 1：API 请求穿越认证、授权、准入三阶段链路的完整流程。认证阶段失败返回 401，授权阶段失败返回 403，准入阶段可以拒绝请求或修改对象内容。Mutating Webhook 在 Validating 之前执行，允许在对象写入前注入默认值或补充字段，而 Validating Webhook 只做校验不改数据，二者共同构成准入控制的最后一道屏障。

## 图解原理

RBAC 模型由四种核心资源构成。Role 定义命名空间内的权限集合，ClusterRole 定义集群范围的权限集合，二者的区别仅在于作用域，Role 受命名空间限制而 ClusterRole 可在全集群生效。RoleBinding 把 Role 绑定到具体主体，ClusterRoleBinding 把 ClusterRole 绑定到集群级主体。主体（Subject）可以是 User、Group 或 ServiceAccount，绑定关系决定了谁能获得对应角色所授予的权限，一条绑定规则可以同时关联多个主体。

一个 Role 通过 verbs 和 resources 的组合精确描述权限。verbs 包括 get、list、watch、create、update、patch、delete 等操作，resources 对应 pods、services、deployments 等 API 资源，也可以通过 resourceNames 限定到具体资源实例。可以用 `*` 表示通配，但生产环境应避免这种宽松写法。Pod Security Standards 提供了三种预设策略：privileged（无限制）、baseline（最小限制）、restricted（严格限制），通过 PodSecurity Admission Controller 在命名空间级别强制执行，替代了已废弃的 PodSecurityPolicy。三种模式可以分别配置 enforce（拒绝）、audit（审计日志）、warn（告警）三个维度，便于灰度过渡。

```mermaid
graph LR
    S1[User] --> B
    S2[Group] --> B
    S3[ServiceAccount] --> B
    B[RoleBinding / ClusterRoleBinding] --> R[Role / ClusterRole]
    R --> P1["权限项: verbs + resources"]
    R --> P2["示例: get, list pods"]
    R --> P3["示例: create deployments"]
    B -.->|命名空间级别| NS["Role + RoleBinding"]
    B -.->|集群级别| CL["ClusterRole + ClusterRoleBinding"]
```

图 2：RBAC 中主体到权限的映射链路。左侧三种 Subject 类型通过 Binding 关联到 Role 或 ClusterRole，Role 再展开为具体的 verbs 和 resources 组合。虚线标注了作用域差异：RoleBinding 只在单个命名空间内生效，ClusterRoleBinding 则授予集群范围的权限。设计 Role 时应遵循最小权限原则，只授予业务运行所需的 verbs 集合，能用 RoleBinding 解决就不要使用 ClusterRoleBinding。

## 动手实操

先创建一个专用的命名空间和 ServiceAccount，模拟一个只读应用身份。以下命令创建 dev-team 命名空间，并在其中创建 pod-reader 这个 ServiceAccount。后续所有权限测试和 Pod 部署都围绕该身份展开，构建一个完整的权限隔离示例。

```bash
kubectl create namespace dev-team
kubectl create serviceaccount pod-reader -n dev-team
```

定义一个只允许在 dev-team 命名空间内 get、list、watch pods 及 pods/log 的 Role。这个 Role 仅授予只读权限，不包含 create、delete 等写操作，符合最小权限原则。rules 中的 apiGroups 设为空字符串表示核心 API 组，resources 和 verbs 精确限定到所需的资源类型和操作。

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: dev-team
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  verbs: ["get", "list", "watch"]
```

将这个 Role 绑定到前面创建的 ServiceAccount。RoleBinding 中的 subjects 字段声明主体，roleRef 字段声明目标角色，二者共同完成授权绑定。注意 roleRef 一旦创建便不可修改，需要更换角色时必须删除重建 RoleBinding。

```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-reader-binding
  namespace: dev-team
subjects:
- kind: ServiceAccount
  name: pod-reader
  namespace: dev-team
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io
```

应用上述配置后，用该 ServiceAccount 的身份验证权限边界。以下命令先部署 YAML 文件，再通过 `kubectl auth can-i` 测试具体操作是否被允许。最后尝试删除操作以验证越权访问会被拒绝，从而确认权限隔离生效。

```bash
kubectl apply -f role.yaml -f rolebinding.yaml

# 检查是否有读取 Pod 的权限，应返回 yes
kubectl auth can-i get pods \
  --as=system:serviceaccount:dev-team:pod-reader -n dev-team

# 尝试删除 Pod，应返回 no
kubectl auth can-i delete pods \
  --as=system:serviceaccount:dev-team:pod-reader -n dev-team

# 生成短期 Token 用于应用配置
kubectl create token pod-reader -n dev-team
```

配置 PodSecurity 准入控制，在命名空间级别强制 restricted 策略。enforce 标签会拒绝不合规 Pod 的创建，audit 和 warn 标签则在不阻断的情况下记录和提示。三个标签可以独立配置不同的策略级别，便于灰度迁移已有工作负载。

```bash
kubectl label namespace dev-team \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/warn=restricted
```

此后该命名空间中创建的 Pod 如果不符合 restricted 标准（如使用特权容器、以 root 运行、未设置 runAsNonRoot），将被拒绝创建。创建一个 Secret 并通过环境变量注入 Pod，避免在镜像或配置文件中硬编码敏感信息。同时设置符合 restricted 标准的 securityContext，包含 runAsNonRoot、runAsUser、allowPrivilegeEscalation 和 capability 限制。

```yaml
apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
  namespace: dev-team
type: Opaque
stringData:
  DB_PASSWORD: "S3cr3tV@lue"
---
apiVersion: v1
kind: Pod
metadata:
  name: app-pod
  namespace: dev-team
spec:
  serviceAccountName: pod-reader
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app
    image: nginx:1.25
    env:
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-credentials
          key: DB_PASSWORD
    securityContext:
      runAsNonRoot: true
      runAsUser: 1000
      allowPrivilegeEscalation: false
      capabilities:
        drop: ["ALL"]
```

使用 RBAC 诊断工具检查当前权限分配情况，排查权限过大的主体。`kubectl auth can-i --list` 会列出指定身份拥有的所有权限，方便审计。定期检查 ClusterRoleBinding 列表，及时发现异常授予的集群级权限。

```bash
# 查看某命名空间所有 RoleBinding
kubectl get rolebindings -n dev-team -o wide

# 列出某 ServiceAccount 的全部权限
kubectl auth can-i --list \
  --as=system:serviceaccount:dev-team:pod-reader -n dev-team

# 检查集群范围所有 ClusterRoleBinding
kubectl get clusterrolebindings -o wide
```

## 常见问题与避坑

**Token 轮换**：1.24 之前自动生成的 Secret Token 永不过期，泄露后只能手动删除重建。升级到 1.24+ 后应清理残留的 Secret 形式 Token，改用 TokenRequest 签发短期凭证，默认有效期 1 小时，可通过 `--duration` 参数自定义。残留的旧 Token 仍然有效，不会因升级而自动失效，需要显式删除对应的 Secret。

不要用 `verbs: ["*"]` 配合 `resources: ["*"]` 作为 Role 定义，这等同于授予集群管理员权限。生产环境应拆分细粒度 Role，按业务团队隔离，不同的应用使用不同的 ServiceAccount。共用同一个身份会导致权限蔓延，一旦该身份被攻破，影响范围将不可控。定期使用 `kubectl auth can-i --list` 审计各 ServiceAccount 的实际权限，及时回收不需要的 verbs。

**default ServiceAccount 误用**：Pod 默认挂载的 default ServiceAccount 在 1.6+ 已不自动绑定任何权限，但部分旧集群或第三方 Helm Chart 可能仍残留宽泛绑定。部署 Pod 时应显式指定 serviceAccountName，不要依赖默认行为，同时定期审计 default ServiceAccount 的绑定情况。

PodSecurity 的 enforce 标签一旦设置，已有违规 Pod 不会立即被驱逐，但更新操作会被拒绝。设置策略前先开启 audit 和 warn 模式观察一段时间，收集违规告警后再切换到 enforce，避免一刀切导致业务中断。restricted 模式对容器运行身份、权限提升、capability 等有多项硬性要求，迁移存量工作负载时需要逐项排查并修改 Pod spec。

Secret 在 etcd 中默认以 Base64 编码存储而非加密。生产环境应在 kube-apiserver 启动参数中配置 EncryptionConfiguration，对 etcd 中的 Secret 数据加密。对于更高安全要求的场景，应对接外部密钥管理系统如 Vault，通过 CSI Driver 将密钥挂载到 Pod 中，避免在 Kubernetes 集群内持久化敏感数据。

**ClusterRoleBinding 范围过大**：ClusterRoleBinding 授予的是集群级权限，一旦绑定到错误的 Subject 将影响所有命名空间。优先使用 RoleBinding，仅在需要跨命名空间权限（如节点管理、命名空间管理）时才使用 ClusterRoleBinding，并在代码评审中重点关注 ClusterRoleBinding 的变更。常见的误用场景是为某个命名空间内的 ServiceAccount 授予 cluster-admin，这会导致该 ServiceAccount 拥有对所有资源的完全控制权。

## 小结与进阶

认证、授权、准入三层链路构成了 Kubernetes 安全的骨架，RBAC 定义了权限的粒度，PodSecurity 收紧了工作负载的安全边界，Secret 管理则守护了敏感信息的存储与传递。下一篇将从安全视角转向性能视角，讲解资源调度与编排策略。

