Kubernetes 安全加固实战:RBAC 权限与集群防护配置

Kubernetes 安全加固是云原生环境防护的核心内容,本文从 RBAC 权限控制、ServiceAccount 管理、Pod 安全标准、网络策略隔离与 etcd 加密五个层面,提供一套可直接落地的 Kubernetes 集群安全加固配置方案,并附上每条加固项的验证命令,帮助团队降低集群被攻陷与横向扩散的风险。

适用场景

  • Kubernetes 集群上线前或等保整改时的安全基线配置
  • 多团队共享集群,需要隔离权限与资源边界
  • 审计发现存在 cluster-admin 滥用、特权容器等风险
  • 容器化业务需要满足 Pod 安全标准与网络策略合规要求

前置条件

  • 已部署 Kubernetes 集群(本教程以 Kubernetes 1.28+ 为例)
  • 具备集群管理员权限(kubeconfig 指向 admin 上下文)
  • 已安装 kubectl 命令行工具

原理说明

Kubernetes 的安全纵深可分为四层:认证与授权(谁有权限调用 API)、Pod 运行安全(容器以什么身份、什么能力运行)、网络隔离(工作负载之间能否互访)、数据加密(etcd 中存储的敏感信息是否落盘加密)。多数真实入侵事件中,攻击者通过供应链或应用漏洞进入 Pod 后,利用过度授权的 ServiceAccount 调用 kubelet/API Server 实现集群级接管。因此 RBAC 最小权限与禁止特权容器是最优先的两项加固。

操作步骤

1. 审计并收敛 RBAC 权限

# 查看所有绑定 cluster-admin 的账号(应立即收敛)
kubectl get clusterrolebindings -o custom-columns=NAME:.metadata.name,SUBJECTS:.subjects[*].name | grep -B1 -i admin

# 查看默认 ServiceAccount 是否有高危权限
kubectl get clusterrolebindings -o json | jq '.items[] | select(.subjects[]?.kind=="Group" and .subjects[]?.name=="system:serviceaccounts")'

为业务创建最小权限的 Role 与 RoleBinding(限定命名空间):

# 创建只读角色
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: app-dev
  name: app-readonly
rules:
- apiGroups: [""]
  resources: ["pods", "services", "configmaps"]
  verbs: ["get", "list", "watch"]
EOF

# 绑定到指定用户
kubectl create rolebinding app-readonly-binding   --role=app-readonly   --user=alice@example.com   --namespace=app-dev

2. 收紧 ServiceAccount 与自动挂载

# 禁止默认 ServiceAccount 自动挂载 API 凭证
kubectl patch serviceaccount default -n app-dev -p '{"automountServiceAccountToken": false}'

# 每个工作负载显式指定专用 SA
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-sa
  namespace: app-dev
automountServiceAccountToken: false
EOF

在 Deployment 的 spec 中指定 serviceAccountName: app-sa,只有真正需要调用 Kubernetes API 的组件(如 Operator)才单独授权并挂载凭证。

3. 启用 Pod Security 标准

使用 Pod Security Admission(PSA)强制 Pod 遵循基线/受限标准:

# 对 app-dev 命名空间启用 restricted(最严格)标准,先 warn 观察
kubectl label --overwrite ns app-dev pod-security.kubernetes.io/enforce=restricted
kubectl label --overwrite ns app-dev pod-security.kubernetes.io/audit=restricted
kubectl label --overwrite ns app-dev pod-security.kubernetes.io/warn=restricted

工作负载补充安全上下文(restricted 要求):

securityContext:
  runAsNonRoot: true
  runAsUser: 10001
  seccompProfile:
    type: RuntimeDefault
  capabilities:
    drop: ["ALL"]
  allowPrivilegeEscalation: false

4. 配置 NetworkPolicy 默认拒绝

# 默认拒绝所有入站/出站流量
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
  namespace: app-dev
spec:
  podSelector: {}
  policyTypes: ["Ingress", "Egress"]
EOF

# 只允许前端访问后端 8080 端口
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-backend
  namespace: app-dev
spec:
  podSelector:
    matchLabels: { app: backend }
  policyTypes: ["Ingress"]
  ingress:
  - from:
    - podSelector: { matchLabels: { app: frontend } }
    ports:
    - protocol: TCP
      port: 8080
EOF

前提:集群必须安装支持 NetworkPolicy 的 CNI 插件(Calico、Cilium、Weave 等),否则策略不会生效。

5. 开启 etcd 静态加密

在 API Server 启动参数中启用 --encryption-provider-config

# 生成加密密钥(生产环境建议使用 KMS 提供方)
head -c 32 /dev/urandom | base64

# 创建加密配置文件 encryption-config.yaml
cat > /etc/kubernetes/encryption-config.yaml <<EOF
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources: ["secrets"]
    providers:
      - aescbc:
          keys:
            - name: key1
              secret: 上一步生成的base64密钥
      - identity: {}
EOF

在 kube-apiserver 的 --encryption-provider-config=/etc/kubernetes/encryption-config.yaml 参数后重启 API Server,并执行全量重加密:

kubectl get secrets --all-namespaces -o json | kubectl replace -f -

6. 审计 API Server 关键参数

# 确认已禁用匿名请求、启用 RBAC 鉴权
kubectl get --raw /api/v1/namespaces/kube-system/configmaps/kube-apiserver-leader-elect 2>/dev/null
# 推荐参数(管理平面部署时设置)
# --authorization-mode=RBAC
# --anonymous-auth=false
# --enable-admission-plugins=NodeRestriction,PodSecurity,ServiceAccount

配置验证

# 1. RBAC 生效验证:用只读账号尝试删除 Pod(应被拒绝)
kubectl --as=alice@example.com -n app-dev delete pod nginx-demo
# 输出: Error from server (Forbidden): ... 表示授权生效

# 2. 检查 Pod 实际安全上下文
kubectl get pod -n app-dev -o jsonpath='{.items[*].spec.containers[*].securityContext}'

# 3. 验证 etcd 加密
ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379   --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt   --key=/etc/kubernetes/pki/etcd/server.key get /registry/secrets/app-dev/mysecret | head -c 200

# 4. NetworkPolicy 生效:从非白名单 Pod 访问后端应超时
kubectl exec -n app-dev frontend-pod -- curl -m 3 http://backend-svc:8080

etcd 中 secret 值以 k8s:enc:aescbc:v1:key1: 前缀开头即说明加密生效。

常见问题

FAQ 1:开启 restricted 标准后现有 Pod 无法调度/报错?

Pod Security 是准入控制,不满足 restricted 的 Pod 会被拒绝。处理步骤:先查看拒绝原因 kubectl describe pod xxx -n app-dev(或 kubectl get events);对照 restricted 要求补齐 securityContext(runAsNonRoot、capabilities drop ALL、seccompProfile、allowPrivilegeEscalation: false);确有特殊需求的 Pod(如需要 NET_ADMIN 的网络插件 DaemonSet)可将其所在命名空间降级为 baseline 或为 Pod 添加 pod-security.kubernetes.io/audit=baseline 注解并评估风险。建议先在 warn/audit 模式下灰度,再切 enforce。

FAQ 2:配置 NetworkPolicy 后服务间访问不通?

NetworkPolicy 默认拒绝策略会阻断所有未显式放行的流量。排查顺序:一是确认 CNI 支持 NetworkPolicy(kubectl get networkpolicies 能列出即基本正常);二是检查 policyTypes 是否只声明了需要的方向(只拦 Ingress 就不要写 Egress);三是确认 selector 标签与实际 Pod 标签完全匹配(kubectl get pods --show-labels 核对);四是跨命名空间访问需用 namespaceSelector 放行,并确认目标端口声明与实际端口一致。加白名单策略时注意策略之间是 OR 关系,新增策略不会覆盖已有放行。

总结

Kubernetes 安全加固遵循最小权限与纵深防御原则:RBAC 收敛管理权限、ServiceAccount 禁用自动挂载、Pod Security 禁止特权容器、NetworkPolicy 默认拒绝、etcd 静态加密。五层措施相互独立又彼此补充,即使某一层被突破,其余层级仍可限制攻击者的横向移动范围。建议将以上配置固化为基础镜像与 Helm 模板,纳入 CI 流水线做策略校验,并定期用 kube-bench 等工具对集群做基线复查,确保持续符合安全要求。