i007.cc

i007.cc

优先队列-降维打击

05.价值资料

讲讲RBAC/PSA如何配置和排障

这两个是完全不同层面的安全机制,经常被放在一起讲是因为都属于”谁能做什么”,但一个管的是 API 调用权限,一个管的是 Pod 运行时的安全约束。分开讲。

RBAC —— 谁能对哪些资源做什么操作

四个核心对象

Role / ClusterRole        —— "有哪些权限"(一堆规则的集合)
RoleBinding / ClusterRoleBinding —— "把这些权限授予谁"

 

Role 是命名空间级别的(只在它所在的 namespace 里生效),ClusterRole 是集群级别的——但 ClusterRole 也可以被 RoleBinding(命名空间级别的绑定)引用,这时权限只在这个 RoleBinding 所在的命名空间生效。这个组合非常常见:K8s 内置的 admin/edit/view 都是 ClusterRole,大部分场景下是拿一个 RoleBinding 把它绑定到某个具体命名空间,而不是整个集群都给权限。

配置示例:给一个 ServiceAccount 只读 fleet 命名空间里的 Pod

yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: fleet
rules:
  - apiGroups: [""]           # "" 表示 core API group
    resources: ["pods"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: fleet
subjects:
  - kind: ServiceAccount
    name: fleet-api
    namespace: fleet
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

verbs 常见的有 get/list/watch/create/update/patch/delete/deletecollectionresources 可以用 resourceNames 进一步限制到某个具体名字的对象(比如只能读某一个 Secret,而不是所有 Secret)。

其实你已经在自己集群里看到过 RBAC 实际运作的例子——crossplane-rbac-manager 这个 Pod 存在的意义就是:每装一个 Provider(比如 provider-azure-management),它会自动生成一批 ClusterRole,把这个 Provider 需要的权限(管理 resourcegroup.azure.upbound.io 这类 CRD)动态授予对应的 ServiceAccount,不用你手写。

排障:最重要的一条命令

bash
kubectl auth can-i <verb> <resource> --as=<user-or-sa> -n <namespace>

 

比如验证 fleet-api 这个 ServiceAccount 能不能读 Secret:

bash
kubectl auth can-i get secrets --as=system:serviceaccount:fleet:fleet-api -n fleet

 

返回 yes/no,比翻半天 YAML 快得多。想看某个身份所有权限:

bash
kubectl auth can-i --list --as=system:serviceaccount:fleet:fleet-api -n fleet

 

常见踩坑点

RoleBinding 绑定 ClusterRole 只在自己的命名空间生效——很多人以为绑了 cluster-admin 这个 ClusterRole 就等于集群管理员,结果发现只在某一个命名空间有效,因为用的是 RoleBinding 而不是 ClusterRoleBinding。反过来,ClusterRoleBinding 绑定的权限才是真正全集群生效。

Subject 里的 namespace 字段容易漏写或写错——ServiceAccount 是有命名空间归属的,subjects 里如果 namespace 跟 SA 实际所在的命名空间对不上,绑定完全不生效,但也不会报错,只会在实际调用时表现为 “Forbidden”,很难第一时间看出问题在这。

应用日志里报 Forbidden/is forbidden: User "system:serviceaccount:...cannot ... resource ..." 时,直接把这条报错原封不动拿去跑 kubectl auth can-i,一步到位确认到底是权限问题还是别的问题(比如资源真的不存在):

bash
kubectl get events -A --field-selector reason=Forbidden

 

PSA(Pod Security Admission)—— Pod 本身能不能用某些危险特性

这个是 K8s 1.25 之后内置在 apiserver 里的准入控制器,取代了已经被移除的 PodSecurityPolicy(PSP 是个独立的、要单独装、要单独配 RBAC 绑定的资源类型;PSA 完全不同,是靠命名空间标签驱动的,apiserver 天生自带,不用额外装东西)。

三个级别 + 三种模式

级别(从松到严):privileged → baseline → restrictedrestricted 基本要求:不能以 root 跑(runAsNonRoot: true)、不能用 privileged 容器、不能用 hostNetwork/hostPID/hostIPCcapabilities 必须 drop: ["ALL"](最多加回 NET_BIND_SERVICE)、allowPrivilegeEscalation: falseseccompProfile 必须是 RuntimeDefault 或 Localhost

模式:enforce(真的拒绝)、audit(放行但记进审计日志)、warn(放行但 kubectl apply 时给你一句警告)。三种模式可以同时配、级别还能不一样——这是最实用的用法,比如先只开 warn,观察现有工作负载会不会中招,再决定要不要真的 enforce

yaml
apiVersion: v1
kind: Namespace
metadata:
  name: fleet
  labels:
    pod-security.kubernetes.io/enforce: baseline
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/warn-version: latest

 

排障

PSA 拒绝的报错非常直白,直接告诉你违反了哪一条、字段该怎么改,不用猜:

Error from server (Forbidden): error when creating "deployment.yaml": pods "fleet-api-xxx" is forbidden:
violates PodSecurity "restricted:latest": allowPrivilegeEscalation != false
(container "fleet-api" must set securityContext.allowPrivilegeEscalation=false),
unrestricted capabilities (container "fleet-api" must set securityContext.capabilities.drop=["ALL"])

 

先查当前命名空间到底配了什么级别:

bash
kubectl get ns fleet --show-labels

 

想在不影响现有负载的前提下摸底”如果我把某个命名空间调到 restricted 会炸多少东西”,可以直接拿你的 fleet 命名空间练手:

bash
kubectl label ns fleet pod-security.kubernetes.io/warn=restricted --overwrite
kubectl apply -f ./ -n fleet   # 干跑一遍,看 warn 输出,不会真的拒绝

 

一个很现实的坑:像你之前用的那份 ingress-nginx-kind.yaml,是官方给 kind 场景写的清单,里面很多历史遗留的容器默认不满足 restricted 的要求(比如没显式设 runAsNonRoot、没 drop capabilities),如果你把 ingress-nginx 这个命名空间直接打上 enforce: restricted,控制器 Pod 会直接创建失败——这也是为什么生产环境切换到 restricted 之前,通常要先跑一轮 warn/audit 观察期,而不是直接一刀切。

最后提一句容易混淆的点:kube-system 命名空间里的系统组件(etcdkube-apiserver 这些静态 Pod)通常需要特权访问,集群一般会把 kube-system 排除在 PSA 强制范围外(通过 apiserver 的 PodSecurity 准入插件配置文件里的 exemptions,不是靠命名空间标签),所以你不会看到给 kube-system 打 PSA 标签这种操作。

发表回复