找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4072

积分

0

好友

536

主题
发表于 2 小时前 | 查看: 5| 回复: 0

告别权限混乱:Kubernetes RBAC 设计规范与落地指南

一、概述

1.1 背景介绍

多团队共用一个 Kubernetes 集群 时,权限管理是绕不开的问题。开发人员误删了生产 namespace 的 Deployment、实习生用 kubectl delete 把整个 namespace 干掉了、CI/CD 的 ServiceAccount 权限过大导致安全审计不通过——这些都是没做好 RBAC 的后果。

Kubernetes 的 RBAC(Role-Based Access Control)基于角色的访问控制,通过 Role/ClusterRole 定义权限,通过 RoleBinding/ClusterRoleBinding 把权限绑定到用户、组或 ServiceAccount。RBAC 从 1.8 版本 GA,是 K8s 默认的授权模式。

本文覆盖 RBAC 的完整配置方案,包括用户认证、角色设计、权限分配、审计日志,基于 Kubernetes 1.28.x 版本。

1.2 技术特点

  • 最小权限原则:只授予完成工作所需的最小权限,不给多余权限
  • 命名空间隔离:Role 作用于单个 namespace,ClusterRole 作用于整个集群,两个层级的权限控制
  • 灵活绑定:一个 Role 可以绑定给多个用户,一个用户可以绑定多个 Role,多对多关系
  • 内置角色:K8s 预置了 view、edit、admin、cluster-admin 等 ClusterRole,覆盖常见场景

1.3 适用场景

  • 场景一:多团队共用集群,每个团队只能操作自己 namespace 中的资源
  • 场景二:CI/CD 流水线的 ServiceAccount,只授予部署所需的最小权限
  • 场景三:运维人员分级管理,初级运维只读权限,高级运维有写权限,管理员有集群级权限
  • 场景四:安全合规要求,审计谁在什么时间做了什么操作

1.4 环境要求

组件 版本要求 说明
Kubernetes 1.24+ RBAC 从 1.8 GA,本文使用 1.28
kubectl 与集群版本匹配 用于管理 RBAC 资源
认证方式 X.509 证书/OIDC/ServiceAccount 至少配置一种用户认证方式
审计日志 apiserver 开启 audit-log 记录所有 API 操作

二、详细步骤

2.1 准备工作

2.1.1 RBAC 核心概念

RBAC 由四个资源对象组成:

Role(命名空间级别权限)          ClusterRole(集群级别权限)
    ↓ 绑定                              ↓ 绑定
RoleBinding(命名空间级别绑定)    ClusterRoleBinding(集群级别绑定)
    ↓ 绑定到                            ↓ 绑定到
User / Group / ServiceAccount     User / Group / ServiceAccount

查看集群当前的 RBAC 配置:

# 查看集群当前的RBAC配置
kubectl get roles -A
kubectl get clusterroles
kubectl get rolebindings -A
kubectl get clusterrolebindings

# 查看内置的ClusterRole
kubectl get clusterrole view -o yaml
kubectl get clusterrole edit -o yaml
kubectl get clusterrole admin -o yaml
kubectl get clusterrole cluster-admin -o yaml

2.1.2 认证方式选择

K8s 本身不管理用户,用户认证由外部系统负责:

认证方式 适用场景 复杂度 说明
X.509 客户端证书 小团队、运维人员 用 kubeadm 签发证书,CN 作为用户名,O 作为组名
OIDC(OpenID Connect) 大团队、企业 SSO 对接 Keycloak/Dex 等身份提供商
ServiceAccount Token CI/CD、应用内访问 K8s 原生支持,每个 namespace 自动创建 default SA
Webhook Token 自定义认证 对接企业内部认证系统

2.1.3 权限规划

生产环境建议的角色体系:

角色 权限范围 适用人员
cluster-admin 集群所有资源的所有操作 K8s 管理员(1-2人)
namespace-admin 指定 namespace 的所有操作 团队负责人
developer 指定 namespace 的 Deployment/Pod/Service/ConfigMap 读写 开发人员
viewer 指定 namespace 的只读权限 测试人员、实习生
ci-deployer 指定 namespace 的 Deployment/Service 更新权限 CI/CD ServiceAccount
log-reader 指定 namespace 的 Pod 日志读取权限 日志排查人员

2.2 核心配置

2.2.1 创建用户证书(X.509 方式)

为开发人员创建 K8s 访问证书:

# 1. 生成私钥
openssl genrsa -out developer-zhangsan.key 2048

# 2. 生成证书签名请求(CSR)
# CN=zhangsan 作为用户名,O=dev-team 作为组名
openssl req -new -key developer-zhangsan.key \
  -out developer-zhangsan.csr \
  -subj "/CN=zhangsan/O=dev-team"

# 3. 用K8s CA签发证书(有效期365天)
# 方式一:直接用CA证书签发
openssl x509 -req -in developer-zhangsan.csr \
  -CA /etc/kubernetes/pki/ca.crt \
  -CAkey /etc/kubernetes/pki/ca.key \
  -CAcreateserial \
  -out developer-zhangsan.crt \
  -days 365

# 方式二:通过K8s CertificateSigningRequest API签发(推荐)
cat << EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: zhangsan-csr
spec:
  request: $(cat developer-zhangsan.csr | base64 | tr -d '\n')
  signerName: kubernetes.io/kube-apiserver-client
  usages:
    - client auth
  expirationSeconds: 31536000
EOF

# 审批CSR
kubectl certificate approve zhangsan-csr

# 获取签发的证书
kubectl get csr zhangsan-csr -o jsonpath='{.status.certificate}' | base64 -d > developer-zhangsan.crt

2.2.2 创建 kubeconfig 文件

# 为zhangsan创建kubeconfig
CLUSTER_NAME="prod-cluster"
API_SERVER="https://k8s-api-lb:8443"
CA_CERT="/etc/kubernetes/pki/ca.crt"

# 设置集群信息
kubectl config set-cluster ${CLUSTER_NAME} \
  --certificate-authority=${CA_CERT} \
  --embed-certs=true \
  --server=${API_SERVER} \
  --kubeconfig=zhangsan-kubeconfig

# 设置用户凭证
kubectl config set-credentials zhangsan \
  --client-certificate=developer-zhangsan.crt \
  --client-key=developer-zhangsan.key \
  --embed-certs=true \
  --kubeconfig=zhangsan-kubeconfig

# 设置上下文
kubectl config set-context zhangsan-context \
  --cluster=${CLUSTER_NAME} \
  --namespace=team-backend \
  --user=zhangsan \
  --kubeconfig=zhangsan-kubeconfig

# 设置默认上下文
kubectl config use-context zhangsan-context \
  --kubeconfig=zhangsan-kubeconfig

# 验证(此时还没有绑定角色,会报权限不足)
kubectl get pods --kubeconfig=zhangsan-kubeconfig
# Error: forbidden

2.2.3 定义 Role 和 ClusterRole

# 文件:rbac-roles.yaml
# 1. 开发人员角色(namespace级别)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: developer
  namespace: team-backend
rules:
# Deployment管理
- apiGroups: ["apps"]
  resources: ["deployments", "replicasets", "statefulsets"]
  verbs: ["get", "list", "watch", "create", "update", "patch"]
# Pod操作(不给delete,防止误删)
- apiGroups: [""]
  resources: ["pods", "pods/log", "pods/exec"]
  verbs: ["get", "list", "watch"]
# Service和Ingress
- apiGroups: [""]
  resources: ["services", "endpoints"]
  verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: ["networking.k8s.io"]
  resources: ["ingresses"]
  verbs: ["get", "list", "watch", "create", "update", "patch"]
# ConfigMap和Secret(只读Secret,防止泄露)
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "list", "watch"]
# HPA
- apiGroups: ["autoscaling"]
  resources: ["horizontalpodautoscalers"]
  verbs: ["get", "list", "watch", "create", "update", "patch"]
# Events(只读)
- apiGroups: [""]
  resources: ["events"]
  verbs: ["get", "list", "watch"]
---
# 2. 只读角色
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: viewer
  namespace: team-backend
rules:
- apiGroups: ["", "apps", "batch", "networking.k8s.io", "autoscaling"]
  resources: ["*"]
  verbs: ["get", "list", "watch"]
# 明确排除Secret的data字段(只能看到metadata)
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["list"]
---
# 3. CI/CD部署角色
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: ci-deployer
  namespace: team-backend
rules:
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "watch", "update", "patch"]
- apiGroups: [""]
  resources: ["services"]
  verbs: ["get", "list", "watch", "update", "patch"]
- apiGroups: [""]
  resources: ["configmaps", "secrets"]
  verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: ["networking.k8s.io"]
  resources: ["ingresses"]
  verbs: ["get", "list", "watch", "update", "patch"]
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch"]
---
# 4. 命名空间管理员(ClusterRole,可绑定到不同namespace)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: namespace-admin
rules:
- apiGroups: ["", "apps", "batch", "networking.k8s.io", "autoscaling", "policy"]
  resources: ["*"]
  verbs: ["*"]
# 不给namespace和node的操作权限
- apiGroups: ["rbac.authorization.k8s.io"]
  resources: ["roles", "rolebindings"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

注意:developer 角色没有给 Pod 的 delete 权限,也没有给 pods/execcreate 权限(exec 进入容器需要 create 权限)。生产环境不建议给开发人员 exec 权限,需要排查问题时由运维人员操作。

2.2.4 创建 RoleBinding 和 ClusterRoleBinding

# 文件:rbac-bindings.yaml
# 1. 绑定developer角色给zhangsan用户
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: zhangsan-developer
  namespace: team-backend
subjects:
- kind: User
  name: zhangsan
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: developer
  apiGroup: rbac.authorization.k8s.io
---
# 2. 绑定developer角色给dev-team组(组内所有用户都有权限)
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: dev-team-developer
  namespace: team-backend
subjects:
- kind: Group
  name: dev-team
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: developer
  apiGroup: rbac.authorization.k8s.io
---
# 3. 绑定viewer角色给测试人员
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: qa-team-viewer
  namespace: team-backend
subjects:
- kind: Group
  name: qa-team
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: viewer
  apiGroup: rbac.authorization.k8s.io
---
# 4. CI/CD ServiceAccount绑定
apiVersion: v1
kind: ServiceAccount
metadata:
  name: ci-deployer
  namespace: team-backend
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ci-deployer-binding
  namespace: team-backend
subjects:
- kind: ServiceAccount
  name: ci-deployer
  namespace: team-backend
roleRef:
  kind: Role
  name: ci-deployer
  apiGroup: rbac.authorization.k8s.io
---
# 5. namespace-admin绑定给团队负责人(ClusterRole绑定到特定namespace)
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: team-lead-admin
  namespace: team-backend
subjects:
- kind: User
  name: lisi
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: namespace-admin
  apiGroup: rbac.authorization.k8s.io

应用并验证:

kubectl apply -f rbac-roles.yaml
kubectl apply -f rbac-bindings.yaml

# 验证zhangsan的权限
kubectl auth can-i get pods --namespace=team-backend --as=zhangsan
# yes
kubectl auth can-i delete pods --namespace=team-backend --as=zhangsan
# no
kubectl auth can-i get pods --namespace=kube-system --as=zhangsan
# no

2.2.5 ServiceAccount Token 管理

# K8s 1.24+不再自动为ServiceAccount创建永久Token
# 需要手动创建Token(有时效)

# 创建短期Token(1小时有效)
kubectl create token ci-deployer -n team-backend --duration=1h

# 创建长期Token Secret(不推荐,但CI/CD有时需要)
cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: ci-deployer-token
  namespace: team-backend
  annotations:
    kubernetes.io/service-account.name: ci-deployer
type: kubernetes.io/service-account-token
EOF

# 获取Token
kubectl get secret ci-deployer-token -n team-backend -o jsonpath='{.data.token}' | base64 -d

# 用Token创建kubeconfig
TOKEN=$(kubectl get secret ci-deployer-token -n team-backend -o jsonpath='{.data.token}' | base64 -d)

kubectl config set-cluster prod-cluster \
  --certificate-authority=/etc/kubernetes/pki/ca.crt \
  --embed-certs=true \
  --server=https://k8s-api-lb:8443 \
  --kubeconfig=ci-deployer-kubeconfig

kubectl config set-credentials ci-deployer \
  --token=${TOKEN} \
  --kubeconfig=ci-deployer-kubeconfig

kubectl config set-context ci-context \
  --cluster=prod-cluster \
  --namespace=team-backend \
  --user=ci-deployer \
  --kubeconfig=ci-deployer-kubeconfig

kubectl config use-context ci-context \
  --kubeconfig=ci-deployer-kubeconfig

警告:长期 Token Secret 没有过期时间,泄露后攻击者可以一直使用。生产环境建议用短期 Token 配合 Token 刷新机制,或者用 OIDC 方式认证。

2.3 启动和验证

2.3.1 权限验证

# 使用kubectl auth can-i验证权限
# 检查当前用户权限
kubectl auth can-i --list --namespace=team-backend

# 模拟特定用户检查权限
kubectl auth can-i create deployments --namespace=team-backend --as=zhangsan
kubectl auth can-i delete pods --namespace=team-backend --as=zhangsan
kubectl auth can-i get secrets --namespace=team-backend --as=zhangsan
kubectl auth can-i get nodes --as=zhangsan

# 模拟ServiceAccount检查权限
kubectl auth can-i update deployments --namespace=team-backend \
  --as=system:serviceaccount:team-backend:ci-deployer

# 查看用户的所有权限
kubectl auth can-i --list --namespace=team-backend --as=zhangsan

2.3.2 实际操作验证

# 用zhangsan的kubeconfig操作
export KUBECONFIG=zhangsan-kubeconfig

# 应该成功的操作
kubectl get pods -n team-backend
kubectl get deployments -n team-backend
kubectl get services -n team-backend

# 应该失败的操作
kubectl delete pod <pod-name> -n team-backend
# Error: forbidden

kubectl get pods -n kube-system
# Error: forbidden

kubectl get nodes
# Error: forbidden

# 恢复管理员kubeconfig
unset KUBECONFIG

2.3.3 审计日志验证

# 查看审计日志中zhangsan的操作记录
grep '"user":{"username":"zhangsan"' /var/log/kubernetes/audit.log | \
  jq '{timestamp: .requestReceivedTimestamp, user: .user.username, verb: .verb, resource: .objectRef.resource, namespace: .objectRef.namespace}' | \
  tail -20

三、示例代码和配置

3.1 完整配置示例

3.1.1 多团队 RBAC 完整方案

# 文件:multi-team-rbac.yaml
# ===== Namespace创建 =====
apiVersion: v1
kind: Namespace
metadata:
  name: team-backend
  labels:
    team: backend
---
apiVersion: v1
kind: Namespace
metadata:
  name: team-frontend
  labels:
    team: frontend
---
apiVersion: v1
kind: Namespace
metadata:
  name: team-data
  labels:
    team: data
---
# ===== 通用ClusterRole定义 =====
# 跨namespace的只读权限(查看节点状态等)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cluster-viewer
rules:
- apiGroups: [""]
  resources: ["nodes", "namespaces"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["storage.k8s.io"]
  resources: ["storageclasses"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["metrics.k8s.io"]
  resources: ["nodes", "pods"]
  verbs: ["get", "list"]
---
# 所有开发人员都能查看集群基本信息
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: all-developers-cluster-view
subjects:
- kind: Group
  name: dev-team
  apiGroup: rbac.authorization.k8s.io
- kind: Group
  name: frontend-team
  apiGroup: rbac.authorization.k8s.io
- kind: Group
  name: data-team
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: cluster-viewer
  apiGroup: rbac.authorization.k8s.io

为 backend 团队创建 namespace 级别绑定:

# 文件:team-backend-rbac.yaml
# backend团队的namespace级别权限
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: backend-developers
  namespace: team-backend
subjects:
- kind: Group
  name: dev-team
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: developer
  apiGroup: rbac.authorization.k8s.io
---
# backend团队负责人有namespace-admin权限
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: backend-lead-admin
  namespace: team-backend
subjects:
- kind: User
  name: lisi
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: namespace-admin
  apiGroup: rbac.authorization.k8s.io

3.1.2 用户证书批量创建脚本

#!/bin/bash
# 文件:/opt/scripts/create-k8s-user.sh
# 批量创建K8s用户证书和kubeconfig

set -euo pipefail

USERNAME="${1:?Usage: create-k8s-user.sh <username> <group> <namespace>}"
GROUP="${2:?}"
NAMESPACE="${3:?}"
DAYS=365
CLUSTER_NAME="prod-cluster"
API_SERVER="https://k8s-api-lb:8443"
CA_CERT="/etc/kubernetes/pki/ca.crt"
CA_KEY="/etc/kubernetes/pki/ca.key"
OUTPUT_DIR="/data/k8s-users/${USERNAME}"

mkdir -p "${OUTPUT_DIR}"

echo "Creating K8s user: ${USERNAME}, Group: ${GROUP}, Namespace: ${NAMESPACE}"

# 生成私钥
openssl genrsa -out "${OUTPUT_DIR}/${USERNAME}.key" 2048

# 生成CSR
openssl req -new \
  -key "${OUTPUT_DIR}/${USERNAME}.key" \
  -out "${OUTPUT_DIR}/${USERNAME}.csr" \
  -subj "/CN=${USERNAME}/O=${GROUP}"

# 签发证书
openssl x509 -req \
  -in "${OUTPUT_DIR}/${USERNAME}.csr" \
  -CA "${CA_CERT}" \
  -CAkey "${CA_KEY}" \
  -CAcreateserial \
  -out "${OUTPUT_DIR}/${USERNAME}.crt" \
  -days ${DAYS}

# 创建kubeconfig
kubectl config set-cluster ${CLUSTER_NAME} \
  --certificate-authority=${CA_CERT} \
  --embed-certs=true \
  --server=${API_SERVER} \
  --kubeconfig="${OUTPUT_DIR}/${USERNAME}-kubeconfig"

kubectl config set-credentials ${USERNAME} \
  --client-certificate="${OUTPUT_DIR}/${USERNAME}.crt" \
  --client-key="${OUTPUT_DIR}/${USERNAME}.key" \
  --embed-certs=true \
  --kubeconfig="${OUTPUT_DIR}/${USERNAME}-kubeconfig"

kubectl config set-context ${USERNAME}-context \
  --cluster=${CLUSTER_NAME} \
  --namespace=${NAMESPACE} \
  --user=${USERNAME} \
  --kubeconfig="${OUTPUT_DIR}/${USERNAME}-kubeconfig"

kubectl config use-context ${USERNAME}-context \
  --kubeconfig="${OUTPUT_DIR}/${USERNAME}-kubeconfig"

# 清理CSR文件
rm -f "${OUTPUT_DIR}/${USERNAME}.csr"

echo "Kubeconfig created: ${OUTPUT_DIR}/${USERNAME}-kubeconfig"
echo "Certificate expires: $(openssl x509 -in ${OUTPUT_DIR}/${USERNAME}.crt -noout -enddate)"
echo ""
echo "Next step: Create RoleBinding for ${USERNAME} in namespace ${NAMESPACE}"

3.2 实际应用案例

案例一:CI/CD 流水线最小权限配置

场景描述:GitLab CI 流水线需要部署应用到 K8s 集群,要求只能更新指定 namespace 中的 Deployment 镜像版本,不能删除资源,不能访问其他 namespace。

实现代码

# 文件:ci-cd-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: gitlab-ci-deployer
  namespace: production
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: ci-deploy-role
  namespace: production
rules:
# 只能更新Deployment(不能创建和删除)
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "watch", "update", "patch"]
# 只能查看Pod状态(验证部署结果)
- apiGroups: [""]
  resources: ["pods", "pods/log"]
  verbs: ["get", "list", "watch"]
# 可以管理ConfigMap和Secret(部署时可能需要更新配置)
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "list", "watch", "create", "update", "patch"]
# 查看Service和Ingress
- apiGroups: [""]
  resources: ["services"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["networking.k8s.io"]
  resources: ["ingresses"]
  verbs: ["get", "list", "watch"]
# 查看事件(排查部署问题)
- apiGroups: [""]
  resources: ["events"]
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: gitlab-ci-deployer-binding
  namespace: production
subjects:
- kind: ServiceAccount
  name: gitlab-ci-deployer
  namespace: production
roleRef:
  kind: Role
  name: ci-deploy-role
  apiGroup: rbac.authorization.k8s.io

GitLab CI 中使用:

# .gitlab-ci.yml
deploy:
  stage: deploy
  image: bitnami/kubectl:1.28
  script:
    - kubectl config set-cluster prod --server=$K8S_API_SERVER --certificate-authority=$K8S_CA_CERT
    - kubectl config set-credentials deployer --token=$K8S_TOKEN
    - kubectl config set-context deploy-ctx --cluster=prod --user=deployer --namespace=production
    - kubectl config use-context deploy-ctx
    - kubectl set image deployment/myapp myapp=registry.company.com/myapp:$CI_COMMIT_SHORT_SHA -n production
    - kubectl rollout status deployment/myapp -n production --timeout=300s

案例二:RBAC 权限审计报告

场景描述:安全审计要求定期检查集群中的 RBAC 配置,找出权限过大的用户和 ServiceAccount。

实现脚本

#!/bin/bash
# 文件:/opt/scripts/rbac-audit.sh
# RBAC权限审计脚本

set -euo pipefail

REPORT_FILE="/data/reports/rbac-audit-$(date +%Y%m%d).txt"
mkdir -p /data/reports

{
echo "=========================================="
echo "  RBAC Audit Report - $(date)"
echo "=========================================="

echo ""
echo "=== 1. cluster-admin权限持有者 ==="
echo "(这些用户/SA拥有集群最高权限,数量应该尽可能少)"
kubectl get clusterrolebindings -o json | \
  jq -r '.items[] | select(.roleRef.name=="cluster-admin") | .subjects[]? | "\(.kind): \(.name) (namespace: \(.namespace // "cluster-wide"))"'

echo ""
echo "=== 2. 拥有Secret读取权限的非系统ServiceAccount ==="
for ns in $(kubectl get ns -o jsonpath='{.items
  • .metadata.name}'); do   for sa in $(kubectl get sa -n "$ns" -o jsonpath='{.items
  • .metadata.name}' 2>/dev/null); do     if [[ "$sa" != "default" ]] && kubectl auth can-i get secrets -n "$ns" --as="system:serviceaccount:${ns}:${sa}" 2>/dev/null | grep -q "yes"; then       echo "  ${ns}/${sa} - can read secrets"     fi   done done echo "" echo "=== 3. 拥有wildcard权限的Role/ClusterRole ===" echo "(使用*通配符的角色权限过于宽泛)" kubectl get roles -A -o json | \   jq -r '.items[] | select(.rules[]? | .verbs[]? == "*" or .resources[]? == "*") | "\(.metadata.namespace)/\(.metadata.name)"' kubectl get clusterroles -o json | \   jq -r '.items[] | select(.metadata.name | startswith("system:") | not) | select(.rules[]? | .verbs[]? == "*" or .resources[]? == "*") | .metadata.name' echo "" echo "=== 4. 未绑定任何角色的ServiceAccount ===" for ns in $(kubectl get ns -o jsonpath='{.items
  • .metadata.name}'); do   for sa in $(kubectl get sa -n "$ns" -o jsonpath='{.items
  • .metadata.name}' 2>/dev/null); do     if [[ "$sa" != "default" ]]; then       bindings=$(kubectl get rolebindings,clusterrolebindings -A -o json | \         jq -r ".items[] | select(.subjects[]? | .kind==\"ServiceAccount\" and .name==\"${sa}\" and .namespace==\"${ns}\") | .metadata.name" 2>/dev/null)       if [[ -z "$bindings" ]]; then         echo "  ${ns}/${sa} - no role bindings"       fi     fi   done done echo "" echo "=== 5. 长期Token Secret统计 ===" kubectl get secrets -A -o json | \   jq -r '.items[] | select(.type=="kubernetes.io/service-account-token") | "\(.metadata.namespace)/\(.metadata.name) -> SA: \(.metadata.annotations["kubernetes.io/service-account.name"])"' echo "" echo "==========================================" echo "  Audit completed at $(date)" echo "==========================================" } > "${REPORT_FILE}" echo "Report saved to: ${REPORT_FILE}"

  • 四、最佳实践和注意事项

    4.1 最佳实践

    4.1.1 性能优化

    • 减少 ClusterRoleBinding 数量:每个 ClusterRoleBinding 都会被 apiserver 在每次请求时评估。100+ 个 ClusterRoleBinding 会增加 apiserver 的授权延迟。尽量用 Group 绑定替代逐个 User 绑定。

      # 不推荐:每个用户单独绑定
      # 10个用户 = 10个RoleBinding
      
      # 推荐:用Group统一绑定
      # 10个用户属于同一个Group = 1个RoleBinding
      subjects:
      - kind: Group
      name: dev-team
      apiGroup: rbac.authorization.k8s.io
    • 避免在 Role 中使用通配符resources: ["*"]verbs: ["*"] 会匹配所有资源和操作,不仅权限过大,apiserver 在评估时也需要展开通配符,增加计算开销。明确列出需要的资源和操作。

    • 合理使用 aggregated ClusterRole:K8s 内置的 view、edit、admin 角色支持聚合,自定义 CRD 的权限可以通过 label 自动聚合到这些角色中,不需要单独创建绑定。

      apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRole
      metadata:
      name: myapp-crd-viewer
      labels:
        # 自动聚合到内置的view角色
        rbac.authorization.k8s.io/aggregate-to-view: "true"
      rules:
      - apiGroups: ["myapp.company.com"]
      resources: ["myresources"]
      verbs: ["get", "list", "watch"]

    4.1.2 安全加固

    • 禁止 default ServiceAccount 自动挂载 Token:每个 namespace 的 default SA 默认会把 Token 挂载到所有 Pod 中,如果 Pod 被入侵,攻击者可以用这个 Token 访问 API。

      # 方式一:在ServiceAccount上禁用
      apiVersion: v1
      kind: ServiceAccount
      metadata:
      name: default
      namespace: production
      automountServiceAccountToken: false
      
      # 方式二:在Pod上禁用
      spec:
      automountServiceAccountToken: false
      containers:
      - name: app
        image: myapp:v1.0
    • 定期轮换证书和 Token:用户证书设置合理的有效期(建议 90 天),ServiceAccount Token 使用短期 Token(1-24 小时),配合 Token 刷新机制。

      # 检查所有用户证书的过期时间
      for crt in /data/k8s-users/*//*.crt; do
      echo "${crt}: $(openssl x509 -in ${crt} -noout -enddate)"
      done
    • 限制 ServiceAccount 的 Token 受众:K8s 1.21+ 支持 Bound Service Account Token,限制 Token 只能用于特定的 API Server。

      # 创建限定受众的Token
      kubectl create token ci-deployer -n production \
      --audience=https://k8s-api-lb:8443 \
      --duration=1h

    4.1.3 高可用配置

    • HA 方案一:RBAC 配置纳入 GitOps 管理,所有 Role/RoleBinding/ClusterRole/ClusterRoleBinding 存储在 Git 仓库,通过 ArgoCD 自动同步
    • HA 方案二:OIDC 认证对接企业 SSO(Keycloak/Azure AD),用户管理在 SSO 侧完成,K8s 只做授权
    • 备份策略:每天导出所有 RBAC 资源的 YAML,保留 30 天历史

    4.2 注意事项

    4.2.1 配置注意事项

    警告:RBAC 配置错误可能导致用户无法访问集群或权限过大,修改前务必用 kubectl auth can-i 验证。

    • 注意 RoleBinding 只能引用同 namespace 的 Role,但可以引用 ClusterRole(此时 ClusterRole 的权限被限制在 RoleBinding 所在的 namespace 内)。这是一个常用技巧:定义一次 ClusterRole,在多个 namespace 中通过 RoleBinding 复用。
    • 注意 删除 namespace 会同时删除该 namespace 下的所有 Role 和 RoleBinding,但不会删除 ClusterRole 和 ClusterRoleBinding。重建 namespace 后需要重新创建 RoleBinding。
    • 注意 kubectl auth can-i--as 参数模拟的是用户身份,不会检查用户是否真实存在。即使用户不存在,只要有对应的 RoleBinding 就会返回 yes。

    4.2.2 常见错误

    错误现象 原因分析 解决方案
    forbidden: User "xxx" cannot get resource "pods" 用户没有对应 namespace 的 pods 读取权限 创建 Role 和 RoleBinding 授予权限
    RoleBinding 创建成功但权限不生效 RoleBinding 的 subjects 中用户名或 SA 名拼写错误 kubectl get rolebinding -o yaml 检查 subjects
    ServiceAccount Token 无法认证 Token 过期或 SA 被删除重建(Token 失效) 重新创建 Token
    cannot create resource "roles" in API group 用户没有管理 RBAC 资源的权限 需要 cluster-admin 或有 rbac 管理权限的角色
    用户能访问不应该访问的 namespace 使用了 ClusterRoleBinding 而非 RoleBinding 改用 RoleBinding 限制到特定 namespace
    Pod 内无法访问 API automountServiceAccountToken 设为 false 确认 Pod 需要 API 访问,手动挂载 Token

    4.2.3 兼容性问题

    • 版本兼容:RBAC API rbac.authorization.k8s.io/v1 从 1.8 GA,所有现代 K8s 版本都支持
    • 平台兼容:云厂商托管 K8s 通常有额外的 IAM 集成,需要同时配置云 IAM 和 K8s RBAC
    • 组件依赖:OIDC 认证需要 apiserver 配置 --oidc-issuer-url 等参数,kubeadm 集群需要修改 apiserver manifest

    五、故障排查和监控

    5.1 故障排查

    5.1.1 日志查看

    # 查看apiserver审计日志中的授权失败记录
    grep '"code":403' /var/log/kubernetes/audit.log | \
      jq '{time: .requestReceivedTimestamp, user: .user.username, verb: .verb, resource: .objectRef.resource, ns: .objectRef.namespace}' | \
      tail -20
    
    # 查看apiserver日志中的认证失败
    journalctl -u kubelet | grep "Unable to authenticate"
    
    # 查看特定用户的操作记录
    grep '"username":"zhangsan"' /var/log/kubernetes/audit.log | \
      jq '{time: .requestReceivedTimestamp, verb: .verb, resource: .objectRef.resource, code: .responseStatus.code}' | \
      tail -30

    5.1.2 常见问题排查

    问题一:用户报 403 Forbidden

    # 诊断命令
    kubectl auth can-i <verb> <resource> -n <namespace> --as=<username>
    kubectl get rolebindings -n <namespace> -o json | \
      jq '.items[] | select(.subjects[]?.name=="<username>") | .metadata.name'

    解决方案

    1. 确认用户名是否正确(证书的 CN 字段)
    2. 确认 RoleBinding 是否在正确的 namespace
    3. 确认 Role 中是否包含所需的 apiGroups、resources 和 verbs
    4. kubectl auth can-i --list --as=<username> -n <namespace> 查看用户的完整权限列表

    问题二:ServiceAccount Token 认证失败

    # 诊断命令
    kubectl get sa <sa-name> -n <namespace>
    kubectl get secret -n <namespace> | grep <sa-name>
    
    # 验证Token是否有效
    TOKEN=$(kubectl create token <sa-name> -n <namespace>)
    curl -k -H "Authorization: Bearer ${TOKEN}" https://k8s-api-lb:8443/api/v1/namespaces/<namespace>/pods

    解决方案

    • SA 不存在:重新创建 ServiceAccount
    • Token 过期:K8s 1.24+ 的 Token 有时效,重新创建
    • SA 被删除重建:旧 Token 失效,需要重新获取 Token

    问题三:OIDC 认证配置后用户无法登录

    • 症状:kubectl 报 Unauthorized
    • 排查

      # 检查apiserver的OIDC配置
      ps aux | grep kube-apiserver | grep oidc
      
      # 验证OIDC Token
      curl -s https://keycloak.company.com/realms/k8s/.well-known/openid-configuration
      
      # 检查apiserver日志
      crictl logs $(crictl ps --name kube-apiserver -q) 2>&1 | grep -i oidc
    • 解决:确认 apiserver 的 --oidc-issuer-url--oidc-client-id--oidc-username-claim 配置正确

    5.1.3 调试模式

    # 查看用户的完整权限
    kubectl auth can-i --list --as=zhangsan -n team-backend
    
    # 查看ServiceAccount的权限
    kubectl auth can-i --list --as=system:serviceaccount:team-backend:ci-deployer -n team-backend
    
    # 查看Role的详细规则
    kubectl get role developer -n team-backend -o yaml
    
    # 查看谁绑定了某个ClusterRole
    kubectl get clusterrolebindings -o json | \
      jq -r '.items[] | select(.roleRef.name=="cluster-admin") | {name: .metadata.name, subjects: .subjects}'
    
    # 模拟请求测试
    kubectl auth can-i create deployments -n team-backend --as=zhangsan --as-group=dev-team

    5.2 性能监控

    5.2.1 关键指标监控

    # 查看apiserver的授权延迟
    kubectl get --raw /metrics | grep apiserver_authorization_duration
    
    # 查看认证失败次数
    kubectl get --raw /metrics | grep apiserver_authentication_attempts
    
    # 查看RBAC评估次数
    kubectl get --raw /metrics | grep apiserver_authorization_decisions_total

    5.2.2 监控指标说明

    指标名称 正常范围 告警阈值 说明
    授权延迟(P99) <1ms >10ms RBAC 规则过多会增加延迟
    认证失败次数 <10次/小时 >50次/小时 频繁失败可能是暴力破解
    403 响应比例 <5% >10% 高比例说明权限配置有问题或有异常访问
    cluster-admin 绑定数 <5 >10 cluster-admin 权限应严格控制
    长期 Token 数量 按需 增长异常 长期 Token 应定期清理

    5.2.3 Prometheus 监控规则

    # 文件:rbac-alerts.yaml
    apiVersion: monitoring.coreos.com/v1
    kind: PrometheusRule
    metadata:
      name: rbac-alerts
      namespace: monitoring
    spec:
      groups:
      - name: rbac-security
        rules:
        - alert: HighAuthenticationFailureRate
          expr: |
            increase(apiserver_authentication_attempts{result="failure"}[1h]) > 50
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: "High authentication failure rate detected"
            description: "More than 50 auth failures in the last hour"
    
        - alert: UnauthorizedAccessAttempts
          expr: |
            increase(apiserver_authorization_decisions_total{decision="forbid"}[1h]) > 100
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: "High number of unauthorized access attempts"
    
        - alert: NewClusterAdminBinding
          expr: |
            changes(kube_clusterrolebinding_info{clusterrolebinding=~".*admin.*"}[1h]) > 0
          for: 1m
          labels:
            severity: critical
          annotations:
            summary: "New cluster-admin binding detected"
    
        - alert: ServiceAccountTokenLeakSuspicion
          expr: |
            increase(apiserver_authentication_attempts{result="success"}[5m]) > 1000
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: "Unusually high API authentication rate, possible token leak"

    5.3 备份与恢复

    5.3.1 备份策略

    #!/bin/bash
    # RBAC配置备份脚本
    # 文件:/opt/scripts/rbac-backup.sh
    
    set -euo pipefail
    
    BACKUP_DIR="/data/rbac-backup/$(date +%Y%m%d)"
    mkdir -p "${BACKUP_DIR}"
    
    # 备份所有RBAC资源
    kubectl get roles -A -o yaml > "${BACKUP_DIR}/roles.yaml"
    kubectl get clusterroles -o yaml > "${BACKUP_DIR}/clusterroles.yaml"
    kubectl get rolebindings -A -o yaml > "${BACKUP_DIR}/rolebindings.yaml"
    kubectl get clusterrolebindings -o yaml > "${BACKUP_DIR}/clusterrolebindings.yaml"
    kubectl get serviceaccounts -A -o yaml > "${BACKUP_DIR}/serviceaccounts.yaml"
    
    # 压缩
    tar czf "/data/rbac-backup/rbac-$(date +%Y%m%d).tar.gz" -C "/data/rbac-backup" "$(date +%Y%m%d)"
    rm -rf "${BACKUP_DIR}"
    
    # 清理30天前的备份
    find /data/rbac-backup -name "rbac-*.tar.gz" -mtime +30 -delete
    
    echo "[$(date)] RBAC backup completed"

    5.3.2 恢复流程

    1. 停止服务:通知所有用户暂停操作
    2. 恢复数据kubectl apply -f ${BACKUP_DIR}/clusterroles.yaml && kubectl apply -f ${BACKUP_DIR}/roles.yaml
    3. 验证完整性kubectl get roles -Akubectl get rolebindings -A 确认恢复
    4. 重启服务:通知用户恢复操作,验证权限是否正常

    六、总结

    6.1 技术要点回顾

    • 要点一:RBAC 的核心是四个资源对象——Role 定义 namespace 级别权限,ClusterRole 定义集群级别权限,RoleBinding 和 ClusterRoleBinding 把权限绑定到用户/组/ServiceAccount。理解这四个对象的关系是配置 RBAC 的基础
    • 要点二:最小权限原则是 RBAC 配置的第一准则。开发人员不给 Pod 的 delete 权限,CI/CD 的 ServiceAccount 只给 Deployment 的 update 权限,测试人员只给只读权限。宁可权限不够再加,不要一开始就给大权限
    • 要点三:用 Group 绑定替代逐个 User 绑定,一个 RoleBinding 绑定一个 Group 就覆盖了组内所有用户。证书的 O 字段作为组名,OIDC 的 groups claim 作为组名,统一管理效率高
    • 要点四:K8s 1.24+ 不再自动为 ServiceAccount 创建永久 Token,生产环境用短期 Token(kubectl create token)配合 Token 刷新机制,避免长期 Token 泄露的安全风险
    • 要点五:RBAC 配置纳入 GitOps 管理,所有 Role/ClusterRole/RoleBinding/ClusterRoleBinding 存储在 Git 仓库,通过 ArgoCD 自动同步。配合审计日志定期审查权限,确保没有权限膨胀

    6.2 进阶学习方向

    1. OIDC 集成企业 SSO:对接 Keycloak/Dex/Azure AD 实现统一身份认证,用户在 SSO 侧管理,K8s 只做授权。大团队必备方案
      • 学习资源:Kubernetes OIDC 认证
      • 实践建议:先在测试集群对接 Dex,理解 OIDC Token 的签发和验证流程,再对接企业 SSO
    2. OPA/Gatekeeper 策略引擎:RBAC 控制的是“谁能做什么操作”,OPA 控制的是“操作的内容是否合规”。两者配合实现完整的安全策略
      • 学习资源:Gatekeeper 项目
      • 实践建议:从简单的策略开始,如禁止使用 latest 镜像标签、强制设置 resource limits
    3. Kubernetes 审计日志深度分析:配置 apiserver 的 audit-policy,按资源类型和操作分级记录,对接 ELK 或 Loki 做日志分析和告警

    6.3 参考资料

    • Kubernetes RBAC 官方文档 - RBAC 完整配置说明
    • Kubernetes 认证机制 - 各种认证方式详解
    • kubectl auth can-i - 权限检查工具
    • Kubernetes 审计日志 - 审计日志配置指南

    附录

    A. 命令速查表

    # 角色管理
    kubectl get roles -A                                    # 查看所有namespace的Role
    kubectl get clusterroles                                # 查看ClusterRole
    kubectl get role <name> -n <ns> -o yaml                 # 查看Role详细规则
    kubectl create role <name> --verb=get,list --resource=pods -n <ns>  # 命令行创建Role
    kubectl create clusterrole <name> --verb=get,list --resource=nodes  # 创建ClusterRole
    
    # 绑定管理
    kubectl get rolebindings -A                             # 查看所有RoleBinding
    kubectl get clusterrolebindings                         # 查看ClusterRoleBinding
    kubectl create rolebinding <name> --role=<role> --user=<user> -n <ns>  # 创建RoleBinding
    kubectl create clusterrolebinding <name> --clusterrole=<role> --user=<user>  # 创建ClusterRoleBinding
    
    # 权限检查
    kubectl auth can-i <verb> <resource> -n <ns>            # 检查当前用户权限
    kubectl auth can-i <verb> <resource> -n <ns> --as=<user>  # 模拟用户检查
    kubectl auth can-i --list -n <ns> --as=<user>           # 查看用户完整权限列表
    kubectl auth can-i <verb> <resource> --as=system:serviceaccount:<ns>:<sa>  # 检查SA权限
    
    # ServiceAccount管理
    kubectl get sa -A                                       # 查看所有ServiceAccount
    kubectl create sa <name> -n <ns>                        # 创建ServiceAccount
    kubectl create token <sa-name> -n <ns> --duration=1h    # 创建短期Token
    
    # 证书管理
    kubectl get csr                                         # 查看证书签名请求
    kubectl certificate approve <csr-name>                  # 审批CSR
    kubectl certificate deny <csr-name>                     # 拒绝CSR
    
    # 审计排查
    kubectl get events -A --field-selector reason=Forbidden  # 查看权限拒绝事件
    kubectl describe rolebinding <name> -n <ns>             # 查看绑定详情

    B. 配置参数详解

    Role/ClusterRole rules 字段

    字段 说明 示例
    apiGroups API 组,空字符串 "" 表示 core API [""] = Pod/Service,["apps"] = Deployment
    resources 资源类型 ["pods", "pods/log", "pods/exec"]
    verbs 操作动词 ["get", "list", "watch", "create", "update", "patch", "delete"]
    resourceNames 限定具体资源名称(可选) ["my-configmap"] 只能操作这个 ConfigMap

    常用 apiGroups 对照表

    apiGroup 包含的资源
    "" (core) pods, services, configmaps, secrets, namespaces, nodes, endpoints, events, persistentvolumeclaims
    apps deployments, replicasets, statefulsets, daemonsets
    batch jobs, cronjobs
    networking.k8s.io ingresses, networkpolicies
    rbac.authorization.k8s.io roles, rolebindings, clusterroles, clusterrolebindings
    autoscaling horizontalpodautoscalers
    policy poddisruptionbudgets
    storage.k8s.io storageclasses, volumeattachments
    certificates.k8s.io certificatesigningrequests

    内置 ClusterRole 说明

    ClusterRole 权限范围 适用场景
    cluster-admin 集群所有资源的所有操作 K8s 管理员,数量严格控制
    admin namespace 内所有资源(不含 ResourceQuota 和 namespace 本身) 团队负责人
    edit namespace 内大部分资源的读写(不含 Role/RoleBinding) 开发人员
    view namespace 内大部分资源的只读(不含 Secret) 测试人员、只读用户
    system:node kubelet 需要的权限 节点自动绑定,不要手动修改

    RoleBinding subjects 字段

    Kind 说明 name 格式
    User 用户,对应证书 CN 字段或 OIDC username claim zhangsan
    Group 用户组,对应证书 O 字段或 OIDC groups claim dev-team
    ServiceAccount 服务账号,需要指定 namespace ci-deployer(需同时指定 namespace 字段)

    C. 术语表

    术语 英文 解释
    RBAC Role-Based Access Control 基于角色的访问控制,K8s 默认的授权模式
    Role 角色 namespace 级别的权限定义,包含一组 API 操作规则
    ClusterRole 集群角色 集群级别的权限定义,可作用于所有 namespace 或集群资源
    RoleBinding 角色绑定 将 Role 或 ClusterRole 绑定到用户/组/SA,作用于特定 namespace
    ClusterRoleBinding 集群角色绑定 将 ClusterRole 绑定到用户/组/SA,作用于整个集群
    ServiceAccount 服务账号 K8s 原生的身份标识,用于 Pod 内访问 API 或 CI/CD 认证
    CSR Certificate Signing Request 证书签名请求,用于通过 K8s API 签发用户证书
    OIDC OpenID Connect 基于 OAuth 2.0 的身份认证协议,用于对接企业 SSO
    CN Common Name X.509 证书的通用名称字段,K8s 用作用户名
    O Organization X.509 证书的组织字段,K8s 用作用户组名
    Audit Log 审计日志 apiserver 记录的所有 API 操作日志,用于安全审计和问题排查
    Token 令牌 ServiceAccount 的认证凭证,K8s 1.24+ 默认使用短期 Token
    Aggregated ClusterRole 聚合集群角色 通过标签自动合并多个 ClusterRole 的权限,内置 view/edit/admin 支持聚合



    上一篇:AI Agent 测评体系搭建实战:从框架设计到TPerf落地全解
    下一篇:CVE-2025-7771 漏洞分析:ThrottleStop.sys 驱动 BYOVD 攻击与 Ring 0 提权
    您需要登录后才可以回帖 登录 | 立即注册

    手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

    GMT+8, 2026-6-17 04:06 , Processed in 0.623620 second(s), 39 queries , Gzip On.

    Powered by Discuz! X3.5

    © 2025-2026 云栈社区.

    快速回复 返回顶部 返回列表