发布于21小时前21小时 问题背景在一次已授权的集群测试中,当前账号可以查看某个命名空间的 Pod 和 ConfigMap。怎样确认它是否还能跨命名空间访问 Secret、执行 Pod 命令或修改 RBAC,同时避免直接读取业务数据、创建持久资源?另外,为什么 kubectl auth can-i 返回 yes,实际请求仍可能得到 403?这类问题建议分成身份、RBAC 授权、准入控制和实际对象四层排查。不要直接以读取 Secret 内容或进入业务 Pod 作为第一步,SelfSubjectAccessReview 和服务端 dry-run 通常足够完成低影响验证。一、先固定测试身份和上下文先记录当前集群、用户和命名空间,避免在错误环境执行命令。不要使用 kubectl config view --raw,因为输出可能包含客户端证书或令牌。kubectl config current-context kubectl config view --minify kubectl auth whoami -o yaml kubectl version --client较旧版本的 kubectl 可能不支持 auth whoami,此时可从非 raw 的 minify 输出确认 context 和 user 名称。测试报告中还应记录时间、来源地址和授权工单编号,便于后续对应审计日志。二、使用 can-i 建立权限基线先从授权范围内的命名空间开始,不要一上来枚举整个集群。下面几项比单纯检查 get pods 更有价值:# 查看 app-prod 命名空间内的有效权限 kubectl auth can-i --list -n app-prod # Secret 的 list 通常等同于批量读取,因为返回对象可能包含 data 字段 kubectl auth can-i get secrets -n app-prod kubectl auth can-i list secrets -n app-prod # 子资源需要单独检查 kubectl auth can-i create pods/exec -n app-prod kubectl auth can-i create pods/portforward -n app-prod kubectl auth can-i get pods/log -n app-prod # 检查是否能够修改授权关系 kubectl auth can-i create rolebindings.rbac.authorization.k8s.io -n app-prod kubectl auth can-i bind clusterroles.rbac.authorization.k8s.io kubectl auth can-i escalate roles.rbac.authorization.k8s.io -n app-prod kubectl auth can-i impersonate users其中 bind、escalate 和 impersonate 属于需要重点关注的权限。账号即使当前不能读取 Secret,也可能通过绑定高权限 ClusterRole、创建更高权限 Role,或模拟其他身份绕过原有边界。跨命名空间验证应逐个检查授权范围内的目标命名空间。例如:for ns in app-dev app-test app-prod; do printf '%-12s ' "$ns" kubectl auth can-i get secrets -n "$ns" done不要把 --all-namespaces 的结果直接当成完整结论。不同命名空间可能存在独立 RoleBinding,而且某些外部授权器对 SelfSubjectAccessReview 的返回并不完整。三、用 SelfSubjectAccessReview 精确验证单项权限kubectl auth can-i 本质上也是在请求授权审查。需要保留原始证据时,可以显式提交 SelfSubjectAccessReview。该对象不会作为普通业务资源持久保存,也不会读取目标 Secret 的内容。cat <<'EOF' | kubectl create -f - -o yaml apiVersion: authorization.k8s.io/v1 kind: SelfSubjectAccessReview spec: resourceAttributes: group: "" resource: secrets verb: get namespace: app-prod name: payment-api-token EOF重点查看返回结果中的 status.allowed、status.denied、status.reason 和 status.evaluationError。测试记录中建议保留完整输出,但不要记录真实令牌值或 Secret 数据。如果要检查非资源 URL,例如健康检查或 metrics 接口,应改用 nonResourceAttributes:cat <<'EOF' | kubectl create -f - -o yaml apiVersion: authorization.k8s.io/v1 kind: SelfSubjectAccessReview spec: nonResourceAttributes: path: /metrics verb: get EOF四、使用服务端 dry-run 验证写权限对于 create、patch 等写操作,可以选择无敏感内容的 ConfigMap 作为探针,并使用服务端 dry-run。这样请求会经过 API Server、授权器和大部分准入链路,但不会持久化对象。kubectl create configmap rbac-probe \ --from-literal=marker=authorized-test \ -n app-prod \ --dry-run=server \ -o yamldry-run 并不等同于绝对零影响。准入 Webhook 只有在声明 sideEffects 为 None 或 NoneOnDryRun 时才应处理 dry-run 请求,但错误实现的外部 Webhook 仍可能调用第三方系统。因此,生产环境执行前应确认测试窗口和准入链配置。不建议为了证明 create pods 权限而直接创建高权限 Pod。Pod 创建权限的风险应结合 Pod Security、准入策略、可挂载的 ServiceAccount、hostPath、hostNetwork 和 privileged 等配置评估。通常 RBAC 结果加准入 dry-run 已足够形成证据。五、定位权限来源如果当前身份有查看 RBAC 对象的权限,可以沿 Subject、RoleBinding、RoleRef 逐层确认来源:# 查看命名空间级绑定 kubectl get rolebinding -n app-prod -o yaml kubectl get role -n app-prod -o yaml # 仅在授权范围允许时查看集群级绑定 kubectl get clusterrolebinding -o yaml kubectl get clusterrole -o yaml排查时注意以下规则:RoleBinding 可以引用 ClusterRole,但权限只在该 RoleBinding 所在命名空间生效。ClusterRoleBinding 会把 ClusterRole 权限授予集群范围内的主体,影响通常更大。subjects 中的 ServiceAccount 必须同时核对 name 和 namespace;同名 ServiceAccount 并不是同一个主体。通配符 apiGroups、resources 或 verbs 容易在集群升级、安装 CRD 后自动扩大权限。resourceNames 不能可靠限制 create 和 deletecollection。对 list、watch 的限制还依赖客户端携带 metadata.name 字段选择器,不能把它当作通用隔离手段。聚合 ClusterRole 可能通过 rbac.authorization.k8s.io/aggregate-to-* 标签动态合并规则,不能只检查单个角色文件。六、can-i 显示 yes,但实际请求返回 403 的原因常见原因不是 RBAC 判断错误,而是测试的请求并不完全相同:命名空间不同:can-i 未指定 -n 时可能使用当前 context 的默认命名空间。资源与子资源不同:get pods 不代表可以 create pods/exec,也不代表可以 get pods/log。准入控制拒绝:RBAC 已允许,但 ValidatingAdmissionWebhook、Pod Security 或策略引擎仍可返回 Forbidden。资源名称不同:角色规则使用了 resourceNames,而实际请求访问的是另一个对象。外部授权器参与:Webhook authorizer 可能根据额外上下文作出不同判断,SelfSubjectAccessReview 结果也可能带 evaluationError。凭据发生变化:短期令牌刷新、ServiceAccount Token 轮换或切换 context 后,实际身份可能与基线记录不一致。此时应比较实际请求的 verb、API group、resource、subresource、namespace 和 name。可以临时提高 kubectl 客户端日志级别观察请求路径,但日志中仍需检查并脱敏 Authorization 等头部信息。kubectl -v=7 get pod example-pod -n app-prod 2>&1如果响应由准入 Webhook 拒绝,错误信息通常会包含 webhook 名称或策略名称。不要通过删除 Webhook、修改 failurePolicy 等方式绕过,应由集群管理员结合控制面日志定位。七、日志留痕建议API Server 审计策略至少应记录 Secret 访问、Pod 交互子资源和授权审查。对 Secret 建议使用 Metadata 级别,避免审计日志再次保存敏感数据。apiVersion: audit.k8s.io/v1 kind: Policy omitStages: - RequestReceived rules: - level: Metadata resources: - group: "" resources: - secrets - pods/exec - pods/portforward - pods/log - level: Request resources: - group: authorization.k8s.io resources: - selfsubjectaccessreviews - level: Metadata自建控制面需要通过 kube-apiserver 的 --audit-policy-file 和 --audit-log-path 等参数启用;托管集群通常需要在云平台控制面日志选项中开启。修改前应评估日志量、保存周期和敏感字段。审计日志中重点关联 user.username、user.groups、sourceIPs、verb、objectRef、responseStatus.code 和 requestReceivedTimestamp:jq -c ' select( .objectRef.namespace == "app-prod" and (.objectRef.resource == "secrets" or .objectRef.subresource == "exec" or .objectRef.subresource == "portforward") ) | { time: .requestReceivedTimestamp, user: .user.username, source: .sourceIPs, verb: .verb, object: .objectRef, code: .responseStatus.code } ' /var/log/kubernetes/audit/audit.log八、风险判断与修复建议将 list secrets 按高风险处理,因为 Kubernetes API 返回的 Secret 列表可能包含完整 data 字段,而不只是名称。将 create pods 与工作负载安全配置联合评估。若允许挂载其他 ServiceAccount、使用 hostPath、特权容器或访问节点网络,风险可能接近权限提升。删除不必要的通配符规则,明确 apiGroups、resources、verbs 和 namespaces。优先使用命名空间级 RoleBinding;只有确有集群级需求时才使用 ClusterRoleBinding。严格限制 bind、escalate、impersonate,以及对 Role、RoleBinding、ClusterRoleBinding 的写权限。不需要调用 Kubernetes API 的工作负载,应设置 automountServiceAccountToken: false。发现 ServiceAccount 令牌可能暴露后,应先移除权限绑定,再滚动工作负载或轮换关联凭据,避免只删 Pod 而保留原有授权关系。通过 Pod Security Admission 或等价策略限制 privileged、hostPID、hostNetwork、hostPath 和高危 capabilities,避免“RBAC 不高但 Pod 创建能力过强”。例如,确认业务不依赖集群 API 后,可以在变更窗口关闭默认 ServiceAccount 的自动令牌挂载:kubectl patch serviceaccount default -n app-prod \ -p '{"automountServiceAccountToken":false}'这项修改只影响后续创建或重建的 Pod,已有 Pod 通常需要滚动更新。执行前应检查 Deployment、Job 和控制器是否显式依赖该令牌,并准备回滚方案。总结低影响验证 Kubernetes RBAC 的核心顺序是:固定身份和上下文、使用 can-i 建立基线、通过 SelfSubjectAccessReview 验证敏感权限、用服务端 dry-run 检查写操作、追溯 RoleBinding 或 ClusterRoleBinding 来源,最后结合审计日志确认实际请求。对于 Secret、pods/exec、Pod 创建及 RBAC 写权限,不需要通过读取真实数据或进入业务容器来证明风险;权限审查结果、准入响应和绑定关系通常已经能够形成完整证据链。 网络请求、日志与边界流量分析示意 安全动态、影响面和处置建议示意
20小时前20小时 低影响验证建议分成“当前身份的授权判断”和“潜在提权链检查”两部分,尽量只调用 Authorization API,不实际创建工作负载、绑定角色或读取 Secret 内容。 1. 先固定测试身份和集群,避免串上下文 kubectl config current-context kubectl auth whoami kubectl version --short 保留上述输出以及测试时间,后续方便和审计日志对应。 2. 用 SelfSubjectAccessReview 验证具体权限 kubectl auth can-i --list适合初筛,但不要只看列表结果,尤其是带 resourceNames、聚合 ClusterRole 或自定义 authorizer 时,应针对具体动作检查: # 当前命名空间 kubectl auth can-i get pods -n app-a kubectl auth can-i list secrets -n app-a kubectl auth can-i get secret/example -n app-a # 跨命名空间对比 kubectl auth can-i get pods -n app-b kubectl auth can-i list secrets -n app-b kubectl auth can-i create deployments.apps -n app-b # 集群范围资源 kubectl auth can-i get nodes kubectl auth can-i list clusterroles.rbac.authorization.k8s.io 需要留下结构化证据时,可以直接提交 SelfSubjectAccessReview。该对象不会持久化,也不会访问目标资源: cat >/tmp/ssar.json <<'EOF' { "apiVersion": "authorization.k8s.io/v1", "kind": "SelfSubjectAccessReview", "spec": { "resourceAttributes": { "namespace": "app-b", "verb": "get", "group": "", "resource": "secrets", "name": "example" } } } EOF kubectl create --raw \ /apis/authorization.k8s.io/v1/selfsubjectaccessreviews \ -f /tmp/ssar.json | jq . 重点记录 status.allowed、status.denied 和 status.reason。不要为了证明权限而直接执行 kubectl get secret -o yaml,授权判断已经足够证明可达性。 3. 排查可形成 RBAC 提权的权限组合 # 创建或修改授权对象 kubectl auth can-i create roles.rbac.authorization.k8s.io -n app-b kubectl auth can-i update roles.rbac.authorization.k8s.io -n app-b kubectl auth can-i create rolebindings.rbac.authorization.k8s.io -n app-b kubectl auth can-i patch rolebindings.rbac.authorization.k8s.io -n app-b # 绕过权限升级保护的特殊 verb kubectl auth can-i escalate roles.rbac.authorization.k8s.io -n app-b kubectl auth can-i escalate clusterroles.rbac.authorization.k8s.io kubectl auth can-i bind clusterroles.rbac.authorization.k8s.io # 身份模拟及服务账号令牌 kubectl auth can-i impersonate serviceaccount/build -n app-b kubectl auth can-i impersonate users kubectl auth can-i impersonate groups kubectl auth can-i create serviceaccounts/token -n app-b 其中 create rolebindings 不一定等于能绑定任意高权限角色,还要结合 bind 权限以及当前身份本身已拥有的权限判断;同理,能创建 Role 也不一定能写入超出自身权限的规则,除非具备 escalate。 4. 只读核对实际绑定关系 kubectl get rolebindings.rbac.authorization.k8s.io \ -A -o json >/tmp/rolebindings.json kubectl get clusterrolebindings.rbac.authorization.k8s.io \ -o json >/tmp/clusterrolebindings.json kubectl get roles.rbac.authorization.k8s.io \ -A -o json >/tmp/roles.json kubectl get clusterroles.rbac.authorization.k8s.io \ -o json >/tmp/clusterroles.json 重点检查: RoleBinding 的 roleRef 是否引用 ClusterRole。它只在该 RoleBinding 所在命名空间生效,但可能带来该命名空间内的高权限。 ClusterRoleBinding 是否绑定到普通用户、业务组或服务账号。 ClusterRole 是否包含通配符 *、secrets、pods/exec、nodes/proxy、RBAC 对象或 webhook 配置。 带 aggregationRule 的 ClusterRole 要查看聚合后的实际规则,不能只看原始标签。 可以用 jq 快速找出跨命名空间服务账号绑定: jq -r ' .items[] as $rb | $rb.subjects[]? | select(.kind=="ServiceAccount") | [ $rb.metadata.namespace, (.namespace // $rb.metadata.namespace), .name, $rb.roleRef.kind, $rb.roleRef.name ] | @tsv ' /tmp/rolebindings.json 5. 验证“创建 Pod 即可借用高权限 ServiceAccount”时要单独判断 仅有 create pods 并不能完全证明能指定任意 ServiceAccount,还可能受准入策略限制。经授权后可使用服务端 dry-run,提交一个不落库、不调度的最小对象: cat <<'EOF' | kubectl apply --dry-run=server -f - apiVersion: v1 kind: Pod metadata: name: rbac-validation namespace: app-b spec: serviceAccountName: privileged-sa automountServiceAccountToken: false restartPolicy: Never containers: - name: check image: registry.k8s.io/pause:3.9 EOF 服务端 dry-run 会经过授权和准入,但不会持久化或调度。它仍可能触发声明支持 dry-run 的 admission webhook,因此应确认测试窗口和审计要求。这个结果只能证明对象可通过创建与准入,不能证明 ServiceAccount 的令牌已实际挂载;不要为了补齐证据启动 Pod 或导出令牌。 6. 关于 --as 不要默认用 kubectl auth can-i --as=... 模拟其他用户。该请求本身需要当前身份拥有 impersonate 权限,失败并不代表目标身份没有权限,只代表当前身份不能模拟它。测试其他身份时,优先使用授权方提供的独立测试凭据,或由集群管理员执行 SubjectAccessReview。 最终报告建议按“身份、命名空间、verb、resource、resourceName、allowed、判定依据”逐条列出。这样既能证明跨命名空间授权,也不会实际读取业务数据或修改 RBAC。
创建帐户或登录后发表意见