Kubernetes安全体系:RBAC、PodSecurity与NetworkPolicy实战

系统讲解 Kubernetes 安全体系:RBAC 权限模型、Pod 安全标准(PSS/PSA)、NetworkPolicy 网络隔离、Admission Controller 准入控制、Secret 加密与审计日志。

Kubernetes 安全涉及多个层面:API 访问控制、工作负载安全、网络隔离、密钥管理和审计追溯。构建纵深防御体系,是保障集群免受攻击和数据泄露的核心。


目录


1. API 访问控制链路

当用户或 Pod 访问 Kubernetes API 时,请求经过以下安全检查:

请求 → 认证(Authentication)→ 授权(Authorization)→ 准入控制(Admission)→ 执行
       │                        │                    │
       │ 验证你是谁              │ 验证你能做什么       │ 验证请求内容合法
       │                        │                    │
       X.509 证书               RBAC/ABAC/Node       PodSecurity
       Bearer Token             Webhook              ResourceQuota
       OIDC (SSO)               AlwaysAllow          Mutating Webhook
       ServiceAccount Token     AlwaysDeny           Validating Webhook

认证方式优先级(同时提供多种凭据时):

  1. X.509 客户端证书
  2. Bearer Token(或 OIDC JWT)
  3. HTTP Basic Auth(已弃用)

2. RBAC:基于角色的访问控制

核心对象

RBAC 通过四个对象定义权限:

# Role:Namespace 级别的权限规则
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: production
  name: pod-reader
rules:
  - apiGroups: [""]           # "" 表示核心 API 组
    resources: ["pods"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get", "list"]

---
# RoleBinding:将 Role 绑定到用户/组/ServiceAccount
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-reader-binding
  namespace: production
subjects:
  - kind: User
    name: alice
    apiGroup: rbac.authorization.k8s.io
  - kind: ServiceAccount
    name: ci-bot
    namespace: ci-system
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

Role vs ClusterRole

对象作用域适用场景
Role单个 Namespace应用团队权限、CI/CD 权限
ClusterRole整个集群节点管理、跨 Namespace 资源、非命名空间资源(Node、PV、Namespace)

常用权限模板

只读权限(适合开发)

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: developer-readonly
rules:
  - apiGroups: ["", "apps", "batch"]
    resources: ["pods", "services", "deployments", "configmaps", "jobs"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["pods/log"]
    verbs: ["get", "list"]

部署权限(适合 CI/CD)

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: deployer
rules:
  - apiGroups: ["", "apps"]
    resources: ["pods", "services", "deployments", "configmaps", "secrets"]
    verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
  - apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get", "list", "watch", "create", "update", "patch", "delete", "rollback"]

集群管理员(谨慎授予)

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: restricted-admin
rules:
  - apiGroups: ["*"]
    resources: ["*"]
    verbs: ["get", "list", "watch"]   # 仅只读
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get", "list", "watch", "patch"]  # 允许 Cordon/Drain

权限最小化原则

# 查询用户/SA 的权限
kubectl auth can-i create pods --as=alice -n production
# 检查 ServiceAccount 权限
kubectl auth can-i '*' '*' --as=system:serviceaccount:default:default

# 列出某 Role 的所有规则
kubectl describe role pod-reader -n production

3. ServiceAccount 与 Token

ServiceAccount 机制

每个 Pod 默认挂载关联 ServiceAccount 的 Token,用于访问 K8s API:

# 查看 Pod 挂载的 ServiceAccount
kubectl get pod <pod> -o jsonpath='{.spec.serviceAccountName}'

# 查看 Secret 中的 Token
kubectl get secret <sa-token> -o jsonpath='{.data.token}' | base64 -d

Token 安全问题

旧版 Token(K8s <1.24):ServiceAccount 自动生成永不过期的 Secret Token,泄露后风险无限期存在。

新版 Token(K8s 1.24+):

  • ServiceAccount 不再自动生成 Secret
  • Token 通过 TokenRequest API 按需生成短期 Token(默认 1 小时)
  • 可创建手动管理的长期 Token(但不推荐)
# 启用新的短期 Token
apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-sa
automountServiceAccountToken: true   # Pod 自动挂载 Token

---
# 或禁用自动挂载(不需要 K8s API 访问时)
apiVersion: v1
kind: ServiceAccount
metadata:
  name: public-app
automountServiceAccountToken: false

Token 过期配置

apiVersion: v1
kind: ServiceAccount
metadata:
  name: short-lived
secrets: []  # K8s 1.24+ 不再自动生成

---
# 手动创建短期 Token(1小时)
kubectl create token short-lived --duration=1h

Pod 级别禁用 Token 挂载

apiVersion: v1
kind: Pod
spec:
  automountServiceAccountToken: false   # 不挂载任何 Token
  containers:
    - name: app
      image: myapp:v1

推荐:绝大多数业务 Pod 不需要访问 K8s API,应禁用 automountServiceAccountToken


4. Pod 安全标准(PSS/PSA)

Pod Security Standards(PSS)

K8s 1.25+ 内置三个安全级别:

级别策略说明
Privileged无限制适用于系统管理员、需要完整权限的工作负载
Baseline最小限制禁止已知的高危配置(特权容器、主机命名空间等)
Restricted严格限制遵循 Pod 加固最佳实践(非 root、只读根文件系统等)

Pod Security Admission(PSA)

PSA 是 K8s 1.25+ 内置的准入控制器,替代已弃用的 PodSecurityPolicy(PSP)。

在 Namespace 级别生效:

apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    # 实施级别
    pod-security.kubernetes.io/enforce: restricted       # 违规 Pod 被拒绝
    pod-security.kubernetes.io/audit: restricted         # 违规记录审计日志
    pod-security.kubernetes.io/warn: baseline            # 违规返回用户警告(但不阻止)

三种模式

模式行为用途
enforce阻止不符合策略的 Pod 创建生产环境强制安全
audit允许创建,但记录审计日志过渡期评估影响
warn允许创建,返回警告给用户开发环境提醒

Restricted 策略要求

要满足 restricted 级别,Pod 必须:

spec:
  securityContext:
    runAsNonRoot: true                 # 禁止 root 用户
    seccompProfile:
      type: RuntimeDefault             # 使用默认 seccomp 配置
  containers:
    - name: app
      securityContext:
        allowPrivilegeEscalation: false    # 禁止特权提升
        readOnlyRootFilesystem: true        # 根文件系统只读
        capabilities:
          drop: ["ALL"]                     # 丢弃所有 capabilities
        runAsUser: 1000                      # 指定非 root UID

Restricted 禁止项

  • 特权容器(privileged: true
  • 主机命名空间共享(PID、IPC、Network)
  • 主机路径挂载(hostPath
  • 以 root 运行
  • 未限制 capabilities
  • Seccomp 未启用

5. NetworkPolicy 网络隔离

默认开放的网络

K8s 集群默认没有任何网络隔离:所有 Pod 之间、所有 Namespace 之间都可以自由通信。

默认拒绝 + 按需开放

第一步:创建默认拒绝所有入站流量

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: production
spec:
  podSelector: {}    # 选中所有 Pod
  policyTypes:
    - Ingress
  # ingress 规则为空 = 拒绝所有入站

第二步:按需开放特定流量

# 允许 ingress-nginx 访问 web 服务
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-ingress-nginx
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: web-server
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              name: ingress-nginx   # 只允许 ingress-nginx namespace
      ports:
        - protocol: TCP
          port: 8080

---
# 允许 frontend 访问 backend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-backend
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: backend
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend       # 同一 namespace 的 frontend
      ports:
        - protocol: TCP
          port: 8080

跨 Namespace 策略

# 允许 monitoring namespace 的 Prometheus 抓取 metrics
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-prometheus
  namespace: production
spec:
  podSelector:
    matchLabels:
      prometheus.io/scrape: "true"
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              name: monitoring    # monitoring namespace
        - podSelector:
            matchLabels:
              app: prometheus
      ports:
        - protocol: TCP
          port: 9090

Egress 策略(出站控制)

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: restrict-egress
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
    - Egress
  egress:
    # 允许访问数据库
    - to:
        - podSelector:
            matchLabels:
              app: postgres
      ports:
        - protocol: TCP
          port: 5432
    # 允许 DNS 查询
    - to:
        - namespaceSelector: {}
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53
    # 允许访问外部 API(特定 CIDR)
    - to:
        - ipBlock:
            cidr: 10.0.0.0/8
            except:
              - 10.0.1.0/24    # 排除敏感网段
      ports:
        - protocol: TCP
          port: 443

NetworkPolicy 限制

  • NetworkPolicy 只是声明,实际执行依赖 CNI 插件(Flannel 不支持,Calico/Cilium 支持)
  • 只能控制 Pod 级别的规则,不支持 FQDN(域名过滤)
  • 规则是白名单 + 默认拒绝模式
  • 不支持日志和审计(Cilium NetworkPolicy 支持)

6. Admission Controller 准入控制

两类 Admission Controller

Mutating(变形):修改请求内容后放行
Validating(验证):仅验证不修改

内置准入控制器

# kube-apiserver 启动参数
--enable-admission-plugins=\
  NamespaceLifecycle,\
  LimitRanger,\
  ServiceAccount,\
  ResourceQuota,\
  PodSecurity,\
  NodeRestriction
控制器类型作用
PodSecurityValidating执行 Pod Security Standards
ResourceQuotaValidating限制 Namespace 资源总量
LimitRangeMutating + Validating设置默认值和限制
NodeRestrictionValidating限制 Node 只能修改自己的资源
ServiceAccountMutating自动注入 ServiceAccount 和 Token

自定义 Admission Webhook

用动态准入控制实现自定义策略:

# MutatingWebhookConfiguration:修改请求
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
  name: pod-mutator
webhooks:
  - name: mutator.security.example.com
    rules:
      - operations: ["CREATE"]
        apiGroups: [""]
        apiVersions: ["v1"]
        resources: ["pods"]
    clientConfig:
      service:
        name: webhook-service
        namespace: security-system
        path: "/mutate"
      caBundle: <CA_BUNDLE>
    admissionReviewVersions: ["v1"]
    sideEffects: None

Mutating Webhook 常见用途

  • 自动注入 Sidecar(Istio、vault-agent)
  • 自动添加资源限制(若未指定则补充默认值)
  • 自动挂载 ConfigMap/Secret
  • 添加标准标签和注解

Validating Webhook 常见用途

  • 强制镜像来源白名单(只允许内部仓库)
  • 禁止 latest 标签
  • 强制安全配置(securityContext 必须设置)
  • 限制特权容器

OPA/Gatekeeper 策略即代码

OPA(Open Policy Agent)提供更灵活的策略定义:

# Gatekeeper ConstraintTemplate
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequiredprobes
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredProbes
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredprobes
        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          not container.livenessProbe
          not container.readinessProbe
          msg := sprintf("Container %s must have liveness or readiness probe", [container.name])
        }

7. Secret 与静态加密

etcd 加密配置

# /etc/kubernetes/encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
      - configmaps
      - ingresses.extensions
    providers:
      - aescbc:
          keys:
            - name: key1
              secret: <base64-encoded-32-byte-key>
      - identity: {}   # 未加密数据的回退读取

配置后重启 kube-apiserver。新写入的 Secret 自动加密,已有的 Secret 在下次更新时重加密。

外部密钥管理

方案原理适用场景
Vault + External SecretsVault 存储密钥,External Secrets Operator 同步到 K8s Secret企业级密钥管理
Sealed Secrets用集群公钥加密 Secret,安全存入 GitGitOps 工作流
SOPS用 Age/GPG 加密 YAML,Flux 部署时解密多环境配置管理
云厂商密钥管理服务AWS Secrets Manager / Azure KV / 阿里云 KMS云原生部署

8. 审计日志

审计策略配置

# /etc/kubernetes/audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  # 记录所有变更操作
  - level: RequestResponse
    verbs: ["create", "update", "patch", "delete"]
    resources:
      - group: ""
        resources: ["pods", "secrets", "configmaps"]

  # 记录 auth 相关的只读操作
  - level: Metadata
    resources:
      - group: "rbac.authorization.k8s.io"

  # 忽略健康检查(减少噪音)
  - level: None
    users: ["system:kube-proxy"]
    verbs: ["watch"]
    resources:
      - group: ""
        resources: ["endpoints", "services"]

  # 默认记录元数据
  - level: Metadata
    omitStages:
      - RequestReceived

kube-apiserver 审计参数

--audit-log-path=/var/log/kubernetes/audit.log
--audit-log-maxage=30
--audit-log-maxbackup=10
--audit-log-maxsize=100
--audit-policy-file=/etc/kubernetes/audit-policy.yaml

审计日志分析

# 查找某用户的操作
jq '. | select(.user.username=="alice")' /var/log/kubernetes/audit.log

# 查找失败的认证尝试
jq '. | select(.responseStatus.code>=400)' /var/log/kubernetes/audit.log

9. 安全加固 Checklist

集群层面

  • API Server 禁用匿名认证(–anonymous-auth=false)
  • kubelet 启用认证和授权(–authentication-token-webhook –authorization-mode=Webhook)
  • etcd 启用 TLS(peer/client 双向认证)
  • etcd 数据加密(EncryptionConfiguration)
  • 启用审计日志
  • 定期轮换证书(使用 kubeadm 的 cert renew)

RBAC 层面

  • 遵循最小权限原则
  • 禁用默认 SA 的自动 Token 挂载
  • 定期审计 Role/ClusterRole 权限
  • 使用 impersonation 进行权限测试

工作负载层面

  • Namespace 启用 restricted Pod Security Standard
  • 容器以非 root 用户运行
  • 启用 readOnlyRootFilesystem
  • 丢弃所有 capabilities
  • 使用 distroless/Alpine 最小镜像
  • 镜像签名验证(Sigstore/cosign)

网络层面

  • 所有 Namespace 默认拒绝 NetworkPolicy
  • 按需开放白名单
  • 敏感服务不暴露 NodePort/LoadBalancer

总结

层面安全机制核心要点
API 访问认证 + RBACTLS/Token/OIDC 认证,最小权限原则
工作负载PSS/PSARestricted 级别,非 root、只读根文件系统
网络NetworkPolicy默认拒绝,白名单开放,CNI 必须支持
密钥Secret 加密etcd 静态加密 + 外部密钥管理
审计Audit Log全量记录变更操作,定期分析
准入Admission Controller内置 + Webhook + OPA/Gatekeeper

安全是持续的过程,而非一次性配置。定期审计、最小权限、纵深防御——这三个原则贯穿 K8s 安全体系的始终。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「云原生」更多文章

  1. Kubernetes多集群联邦:Karmada、Crossplane与Istio多集群实战
  2. CNCF云原生技术全景图:从毕业项目到前沿方向
  3. 容器运行时深度解析:从runc到containerd到安全容器