一、K8S认证与授权
1. 认证「Authentication」
认证有如下几种方式:
1、HTTP Token认证:通过一个Token来识别合法用户。
HTTP Token的认证是用一个很长的特殊编码方式的并且难以被模仿的字符串来表达客户的一种方式。每一个Token对应一个用户名,存储在API Server能访问的文件中。当客户端发起API调用请求时,需要在HTTP Header里放入Token。
2、HTTP Base认证:通过用户名+密码的方式认证
用户名:密码用 base64 算法进行编码后的字符串放在 HTTP Request 中的 Heather Authorization 域里发送给服务端,服务端收到后进行解码,获取用户名和密码。
3、最严格的 HTTPS 证书认证:基于 CA 根证书签名的客户端身份认证方式
2. 授权「Authorization」
认证只是确认通信的双方都是可信的,可以相互通信。而授权是确定请求方有哪些资源的权限。API Server 目前支持如下几种授权策略(通过 API Server 的启动参数 --authorization-mode
设置,在控制平面节点上,路径:/etc/kubernetes/manifests/kube-apiserver.yaml
)
AlwaysDeny
:表示拒绝所有请求。仅用于测试AlwaysAllow
:表示允许所有请求。如果有集群不需要授权流程,则可以采用该策略Node
:节点授权是一种特殊用途的授权模式,专门授权由 kubelet 发出的 API 请求Webhook
:是一种 HTTP 回调模式,允许使用远程 REST 端点管理授权ABAC
:基于属性的访问控制,表示使用用户配置的授权规则对用户请求进行匹配和控制- RBAC:基于角色的访问控制,默认使用该规则
二、RBAC授权模式
RBAC(Role-Based Access Control)基于角色的访问控制,在Kubernetes 1.5 中引入,现为默认标准。相对其他访问控制方式,拥有如下优势:
- 对集群中的资源和非资源均拥有完整的覆盖
- 整个RBAC完全由几个 API 对象完成,同其他API对象一样,可以用 kubectl 或 API 进行操作
- 可以在运行时进行操作,无需重启API Server
1. RBAC API 类型
RBAC API 所声明的四种顶级类型【Role、ClusterRole、RoleBinding 和 ClusterRoleBinding】。用户可以像与其他 API 资源交互一样,(通过 kubectl API 调用等方式)与这些资源交互。
1.1 Role 和 ClusterRole
在 RBAC API 中,一个角色包含一组相关权限的规则。权限是纯粹累加的(不存在拒绝某操作的规则),即只能给权限累加,不存在给了XX权限,然后去掉XX01权限的情况。角色可以用 Role 来定义到某个命名空间(namespace)上, 或者用 ClusterRole 来定义到整个集群作用域(所有namespace)。
一个 Role 只可以用来对某一命名空间中的资源赋予访问权限。
Role示例:
定义到名称为 “default” 的命名空间,可以用来授予对该命名空间中的 Pods 的读取权限:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role # 资源类型为:角色
metadata:
name: pod-reader # 角色的名称
namespace: default # 角色所属的命名空间
rules:
- apiGroups: [""] # 指定 API 组,空字符串 "" 表示 Kubernetes 核心 API 组(例如 pods、services 等资源属于核心组)。
resources: ["pods"] # 指定规则适用的资源类型,这里是 pods(即 Pod 资源)。
verbs: ["get", "watch", "list"] # 指定角色对Pod资源允许的操作,获取、监控、列出
ClusterRole 可以授予的权限和 Role 相同,但是因为 ClusterRole 属于集群范围,所以它也可以授予以下访问权限:
- 集群范围资源 (比如 nodes访问)
- 非资源端点(比如 “/healthz” 访问)
- 跨命名空间访问的有名称空间作用域的资源(如 Pods),比如运行命令
kubectl get pods --all-namespaces
时需要此能力
ClusterRole示例
可用来对某特定命名空间下的 Secrets 的读取操作授权,或者跨所有名称空间执行授权(取决于它是如何绑定的):
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole # 资源类型
metadata:
name: secret-reader # 集群角色的名称
# 此处的 "namespace" 被省略掉是因为 ClusterRoles 是没有命名空间的。
rules:
- apiGroups: [""] # 指定 API 组,空字符串 "" 表示 Kubernetes 核心 API 组(secrets 属于核心组)。
resources: ["secrets"] # 指定规则适用的规则类型
verbs: ["get", "watch", "list"]
1.2 RoleBinding 和 ClusterRoleBinding
角色绑定(RoleBinding)是将角色中定义的权限赋予一个用户或者一组用户。 它包含若干主体【subjects】(users、groups 或 service accounts)的列表和对这些主体所获得的角色引用。
可以使用 RoleBinding 在指定的命名空间中执行授权,或者在集群范围的命名空间使用 ClusterRoleBinding 来执行授权。
一个 RoleBinding 可以引用同一的命名空间中的 Role。
RoleBinding示例
将 “pod-reader” 角色授予在 “default” 命名空间中的用户 “jane”; 这样,用户 “jane” 就具有了读取 “default” 命名空间中 pods 的权限。
在下面的例子中,角色绑定使用 roleRef 将用户 “jane” 绑定到前文创建的角色 Role,其名称是 pod-reader。
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding # 定义资源的类型为 RoleBinding,用于将一个角色(Role 或 ClusterRole)绑定到用户、组或服务账户
metadata:
name: read-pods # RoleBinding 的名称
namespace: default # 此 RoleBinding 作用于 default 命名空间,仅对该命名空间内的资源生效
subjects:
- kind: User # 主体类型为用户
name: jane # 名称大小写敏感
apiGroup: rbac.authorization.k8s.io # 指定主体所属的 API 组
roleRef:
kind: Role # 引用的角色类型为 Role(命名空间级别的角色),而不是 ClusterRole(集群级别的角色)
name: pod-reader # 引用的角色名称为 pod-reader,需要在 default 命名空间中存在
apiGroup: rbac.authorization.k8s.io # 角色所属的 API 组
roleRef 里的内容决定了实际创建绑定的方法。kind 可以是 Role 或 ClusterRole,name 是你要引用的 Role 或 ClusterRole 的名称。
RoleBinding 也可以引用 ClusterRole,这可以允许管理者在 整个集群中定义一组通用的角色,然后在多个命名空间中重用它们。(集群角色与角色绑定进行匹配后,就对集群角色进行了降维,绑定的用户将只能操作命名空间下的资源。)
RoleBinding示例2
下面的例子,RoleBinding 引用的是 ClusterRole, “dave” (subjects区分大小写)将只可以读取在”development” 名称空间( RoleBinding 的命名空间)中的”secrets” 。
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding # 定义资源的类型为 RoleBinding,用于将一个角色(Role 或 ClusterRole)绑定到用户、组或服务账户
metadata:
name: read-secrets # RoleBinding 的名称
namespace: default # 此 RoleBinding 作用于 default 命名空间,仅对该命名空间内的资源生效
subjects:
- kind: User # 主体类型为用户
name: dave # 名称大小写敏感
apiGroup: rbac.authorization.k8s.io # 指定主体所属的 API 组
roleRef:
kind: ClusterRole # 引用的角色类型为 ClusterRole(集群级别的角色),集群角色降维到命名空间
name: secret-reader # 引用的角色名称为 secret-reader,需要在 default 命名空间中存在
apiGroup: rbac.authorization.k8s.io # 角色所属的 API 组
最后,ClusterRoleBinding 可用来在集群级别并对所有命名空间执行授权。
ClusterRoleBinding示例
apiVersion: rbac.authorization.k8s.io/v1
# 这个集群角色绑定允许 "manager" 组中的任何用户读取任意命名空间中 "secrets"s
kind: ClusterRoleBinding
metadata:
name: read-secrets-global # 集群角色的名称
# 不需要定义 namespace,对所有名称空间有效
subjects:
- kind: Group # 绑定的主体类型为 Group
name: manager # 名称区分大小写
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader # 集群角色的名称,需要在集群中存在
apiGroup: rbac.authorization.k8s.io
当我们创建binding后,则不能修改binding所引用的Role或ClusterRole。尝试修改会导致验证错误;如果要改变binding的roleRef,那么应该删除该binding对象并且创建一个新的用来替换原来的。
2. 资源引用 Referring to resources
Kubernetes集群内一些资源一般以其名称字符串来表示,这些字符串一般会在 API 的 URL 地址中出现;同时某些资源也会包含子资源,例如 pod 的 logs 资源就属于pods的子资源,API 中 URL 样例如下:
GET /api/v1/namespaces/{namespace}/pods/{name}/log
在这种情况下,”pods” 是有名称空间的资源,而 “log” 是 pods 的子资源。在 RBAC 角色中,使用 “/” 分隔资源和子资源。
允许一个主体(subject)要同时读取 pods 和 pod logs,你可以这么写:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-and-pod-logs-reader
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list"]
对于某些请求,也可以通过 resourceNames 列表按名称引用资源。
例如:在指定时,可以将请求类型限制到资源的单个实例。限制只可以 “get” 和 “update” 到单个configmap,则可以这么写:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: configmap-updater
namespace: default
rules:
- apiGroups: [""] # 核心 API 组
resources: ["configmaps"] # 可操作的资源类型为 Configmap
resourceNames: ["configmap-demo"] # 可操作的具体是哪个 ConfigMap
verbs: ["update", "get"] # 定义操作类型,只能 更新和读取
需要注意的是,create 请求不能被 resourceName 限制,因为在鉴权时还不知道对象名称。 另一个例外是 deletecollection。
3. 主体引用 Referring to subjects
RoleBinding 或 ClusterRoleBinding 绑定一个 role 到主体(subjects)。主体(subjects)可以是 groups,users 或 ServiceAccounts 。
Kubernetes将用户名表示为字符串。这些可以是:普通名称,比如 “alice” ;邮件风格的名字,比如 “bob@example.com” ;或表示为字符串的数字用户id。
注意:前缀 system:
是保留给 Kubernetes 系统使用的,因此应该确保不会出现名称以 system:
开头的用户或组。除了这个特殊的前缀,RBAC 授权系统不要求用户名使用任何格式。
ServiceAccounts具有前缀为 system:serviceaccount:
的名称,属于具有前缀为 system:serviceaccounts: 的名称的组。
RoleBinding的示例
下面的示例只是展示 RoleBinding 中 subjects 的部分。
用户的名称为 “alice@example.com” :
subjects: - kind: User name: "alice@example.com" apiGroup: rbac.authorization.k8s.io
组的名称为 “frontend-admins” :
subjects: - kind: Group name: "frontend-admins" apiGroup: rbac.authorization.k8s.io
默认service account在 kube-system 命名空间中:
subjects: - kind: ServiceAccount name: default namespace: kube-system
查看 default 命名空间下的 ServiceAccount
$ kubectl get sa NAME SECRETS AGE default 0 77d
在名称为 “qa” 命名空间中所有的服务账号:
subjects: - kind: Group name: system:serviceaccounts:qa apiGroup: rbac.authorization.k8s.io
在任意名称空间的所有service accounts:
subjects: - kind: Group name: system:serviceaccounts apiGroup: rbac.authorization.k8s.io
所有认证过的用户(版本 1.5+):
subjects: - kind: Group name: system:authenticated apiGroup: rbac.authorization.k8s.io
所有未认证的用户(版本 1.5+):
subjects: - kind: Group name: system:unauthenticated apiGroup: rbac.authorization.k8s.io
所有用户 (版本 1.5+):
subjects: - kind: Group name: system:authenticated apiGroup: rbac.authorization.k8s.io - kind: Group name: system:unauthenticated apiGroup: rbac.authorization.k8s.io
三、案例实操
创建一个用户只能管理 dev 名字空间
1. 创建命名空间
# 创建 dev 名称空间
$ kubectl create namespace dev
namespace/dev created
# 查看名称空间
$ kubectl get ns | grep dev
dev Active 24s
2. 创建证书
在 master 节点操作,将证书创建在 /etc/kubernetes/pki
目录下, 该目录存放了 k8s 集群证书。
2.1 创建证书描述文件
vim /etc/kubernetes/pki/devuser.json
# 内容如下:
{
"CN": "devuser",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
2.2 下载证书生成工具
# 工具一
wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
mv cfssl_linux-amd64 /usr/local/bin/cfssl
# 工具二
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
mv cfssljson_linux-amd64 /usr/local/bin/cfssljson
# 工具三
wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
mv cfssl-certinfo_linux-amd64 /usr/local/bin/cfssl-certinfo
# 给生成工具授权
chmod a+x /usr/local/bin/cfssl*
2.3 生成证书
# 使用 cfssl 工具生成 Kubernetes 客户端证书,通常用于用户身份验证(如通过 kubectl 访问集群)
cfssl gencert -ca=/etc/kubernetes/pki/ca.crt -ca-key=/etc/kubernetes/pki/ca.key -profile=kubernetes /etc/kubernetes/pki/devuser.json | cfssljson -bare devuser
命令解析:
- -ca=/etc/kubernetes/pki/ca.crt : 指定 CA 的公钥证书文件路径
- -ca-key=/etc/kubernetes/pki/ca.key :指定 CA 的私钥文件路径
- -profile=kubernetes : 指定证书的配置文件中的一个 profile(指定导出的证书给谁用,这里就是 kubernetes )
- /etc/kubernetes/pki/devuser.json : 指定生成证书的 CSR(证书签名请求)配置文件路径。
- cfssljson -bare devuser : cfssljson 是 cfssl 的辅助工具,用于解析 JSON 格式的证书数据并生成 PEM 格式的证书和私钥文件
- -bare : 指定输出文件的基本名称,不添加默认后缀(如 -cert 或 -key)
- 作用:生成的证书和私钥文件将以 devuser.pem(证书)和 devuser-key.pem(私钥)的形式保存,而不是 devuser-cert.pem 或 devuser-key.pem。
- devuser : 指定输出文件的前缀名称
- 作用:生成的证书文件命名为 devuser.pem,私钥文件命名为 devuser-key.pem。
2.4 声明环境变量: Kubernetes API 服务器的地址
# 192.168.6.139 是master节点 API 服务器所在的主机地址
# 端口:6443 是 Kubernetes API 服务器的默认端口,用于处理客户端请求(如 kubectl)
export KUBE_APISERVER="https://192.168.6.139:6443"
2.5 设置集群参数
在指定的 kubeconfig 文件中添加或更新一个名为 kubernetes 的集群配置,包含 API 服务器地址和 CA 证书等信息
kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=/etc/kubernetes/pki/devuser.kubeconfig
命令解析:
config set-cluster kubernetes
设置或更新一个集群条目,kubernetes 是当前集群的名称,可以通过命令:
$ kubectl config get-clusters
查看
–certificate-authority=/etc/kubernetes/pki/ca.crt
指定集群的 CA(证书颁发机构)证书文件路径
–embed-certs=true
指定是否将 CA 证书的内容嵌入到 kubeconfig 文件中,嵌入证书后,kubeconfig 文件是自包含的,无需依赖外部 ca.crt 文件,方便分发(如给开发人员使用)。
–server=${KUBE_APISERVER}
指定 Kubernetes API 服务器的地址。
–kubeconfig=/etc/kubernetes/pki/devuser.kubeconfig
将设置的内容保存到 devuser.kubeconfig 文件中,如果文件不存在,命令会创建新的 devuser.kubeconfig 文件。
命令执行成功后,可以通过命令:
$ cat /etc/kubernetes/pki/devuser.kubeconfig
查看文件内容
2.6 设置客户端认证参数
配置 Kubernetes 的 kubeconfig 文件,为用户 devuser 添加凭证信息
kubectl config set-credentials devuser \
--client-certificate=/etc/kubernetes/pki/devuser.pem \
--client-key=/etc/kubernetes/pki/devuser-key.pem \
--embed-certs=true \
--kubeconfig=/etc/kubernetes/pki/devuser.kubeconfig
命令解析:
config set-credentials
用于在 kubeconfig 文件中设置或更新用户(user)凭证信息
–client-certificate=/etc/kubernetes/pki/devuser.pem
指定客户端证书文件的路径。此证书用于向 Kubernetes API 服务器证明用户 devuser 的身份。证书的 CN(Common Name,通常为 devuser)和 O(Organization,例如 system:masters)会影响 RBAC 权限。
–client-key=/etc/kubernetes/pki/devuser-key.pem
指定客户端私钥文件的路径,私钥用于签名客户端请求,与证书一起完成 TLS 身份验证。
–embed-certs=true
指定是否将证书和私钥的内容嵌入到 kubeconfig 文件中。true 表示将 devuser.pem 和 devuser-key.pem 的内容(Base64 编码的 PEM 数据)写入 kubeconfig,而不是仅引用文件路径。
–kubeconfig=/etc/kubernetes/pki/devuser.kubeconfig
将设置的内容保存到 devuser.kubeconfig 文件中
2.7 设置上下文参数
配置 Kubernetes 的 kubeconfig 文件,为用户 devuser 设置一个上下文(context),以便访问特定的集群和命名空间。
kubectl config set-context kubernetes \
--cluster=kubernetes \
--user=devuser \
--namespace=dev \
--kubeconfig=/etc/kubernetes/pki/devuser.kubeconfig
命令解析:
config set-context
kubectl config set-context 用于在 kubeconfig 文件中设置或更新一个上下文(context)。上下文定义了用户、集群和命名空间的组合,用于指定 kubectl 的操作环境。
kubernetes 是上下文的名称(可以自定义)。
–cluster=kubernetes
指定上下文关联的集群名称,注意:集群名称必须与 kubeconfig 文件中 clusters 部分的 name 字段匹配
–user=devuser
指定上下文关联的用户名称,注意:用户名称必须与 kubeconfig 文件中 users 部分的 name 字段匹配。
–namespace=dev
指定上下文的默认命名空间,如果不指定 –namespace,默认使用 default 命名空间。确保 dev 命名空间存在(可用 kubectl get namespaces 检查)。
2.8 给用户授权
kubectl create rolebinding devuser-admin-binding --clusterrole=admin --user=devuser --namespace=dev
# 命令转换成资源清单
$ kubectl create rolebinding devuser-admin-binding --clusterrole=admin --user=devuser --namespace=dev --dry-run -o yaml
W0614 17:49:28.687292 2342317 helpers.go:704] --dry-run is deprecated and can be replaced with --dry-run=client.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
creationTimestamp: null
name: devuser-admin-binding
namespace: dev
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: devuser
命令解析:创建角色绑定(devuser-admin-binding),绑定到集群角色admin(系统默认存在的角色), 绑定用户 devuser, 绑定到名称空间 dev。
2.9 设置默认上下文
这条命令使用 kubectl config use-context 设置 Kubernetes 的 kubeconfig 文件中的默认上下文,以便 kubectl 使用指定的上下文进行操作。
在 devuser.kubeconfig 文件中将 current-context 设置为 kubernetes,使后续的 kubectl 命令使用该上下文的配置。
kubectl config use-context kubernetes --kubeconfig=/etc/kubernetes/pki/devuser.kubeconfig
确保 kubectl 默认使用正确的集群(kubernetes)、用户(devuser)和命名空间(dev),无需每次手动指定 –kubeconfig 或 –context。
2.10 测试 root 用户使用 devuser.kubeconfig 文件操作集群
# 1. 将原有的kubeconfig 文件移除
$ mv /root/.kube/config /root/
# 2. 将新建的 devuser.kubeconfig 放到 root 目录下
$ cp -a /etc/kubernetes/pki/devuser.kubeconfig /root/.kube/config
# kubelet 命令
$ kubectl get pods
No resources found in dev namespace.
# 创建 deploy
$ kubectl create deployment dev-deploy --image=wangyanglinux/myapp:v1.0
deployment.apps/dev-deploy created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
dev-deploy-d7448d978-c8jkm 1/1 Running 0 10s
3. 将 linux 用户与 k8s 用户绑定(非必须)
3.1 创建 linux 用户
$ useradd dev
$ passwd dev
3.2 将 devuser.kubeconfig 文件放到新建用户的 家目录 中
# 创建文件目录
$ mkdir /home/dev/.kube
# 将devuser.kubeconfig文件放到 dev 用户的家目录中
$ mv /etc/kubernetes/pki/devuser.kubeconfig /home/dev/.kube/config
# 文件授权
chown -R dev:dev /home/dev/.kube
3.3 shell 使用 dev 用户登录测试
[dev@k8s-master01 ~]$ kubectl get pods
NAME READY STATUS RESTARTS AGE
dev-deploy-d7448d978-c8jkm 1/1 Running 0 8m32s
四、补充
1. 资源与角色类型的匹配
访问的资源 | 使用的角色类型 | 使用的绑定类型 |
---|---|---|
集群级别的资源(Namespace、Node、ClusterRole、ClusterRoleBinding、PersistentVolume (PV)、StorageClass 等) | ClusterRole | ClusterRoleBinding |
非资源型URL(/api、/apis、/apis/ |
ClusterRole | ClusterRoleBinding |
在任何命名空间中的资源(和跨所有命名空间的资源) | ClusterRole | ClusterRoleBinding |
在具体命名空间中的资源(在多个命名空间中重用这个相同的ClusterRole) | ClusterRole | RoleBinding |
在具体命名空间中的资源(Role必须在每个命名空间中定义好),例如:Pod、Deployment、ReplicaSet、StatefulSet、DaemonSet、Job、CronJob、Service、Ingress、ConfigMap、Secret、ServiceAccount、Role、RoleBinding、PersistentVolumeClaim (PVC)、NetworkPolicy、HorizontalPodAutoscaler (HPA)、Event、LimitRange、ResourceQuota | Role | RoleBinding |
2. 常见的预定义角色
- view(ClusterRole)
- 允许读取一个命名空间中的大多数资源, 除了Role、 RoleBinding 和 Secret
- edit(ClusterRole)
- 允许读取和修改 Secret。 但是,它也不允许查看或修改 Role 和 RoleBinding, 这是为了防止权限扩散。
- admin(ClusterRole)
- 一个命名空间中的资源的完全控制权是由 admin ClusterRole 赋予的。 有这个 ClusterRole 的主体可以读取和修改命名空间中的任何资源, 除了 ResourceQuota 和命名空间资源本身。 edit 和 admin ClusterRole 之间的主要区别是能否在命名空间中查看和修改 Role 和 RoleBinding。
- cluster-admin(ClusterRole)
- 通过将 cluster-admin ClusterRole 赋给主体, 主体可以获得 Kubernetes 集群完全控制的权限
五、准入控制
Kubernetes(k8s)中的准入控制(Admission Control)是 Kubernetes API 服务器在处理请求(创建、更新、删除等)时,用于验证和修改资源对象的机制。它是 Kubernetes 扩展性和安全性的重要组成部分,允许管理员在资源对象被持久化到 etcd 之前对其进行检查或修改。准入控制通过准入控制器(Admission Controllers)和准入 webhook 实现。
1. 什么是准入控制?
准入控制是 Kubernetes API 服务器在处理 API 请求时的一个阶段,位于 认证(Authentication)和授权(Authorization) 之后,但在对象持久化到 etcd 之前。它的主要作用是:
- 验证(Validation):检查请求是否符合特定的规则或策略(如资源配额、命名规范)。
- 修改(Mutation):动态修改请求的资源对象(如自动添加标签、设置默认值)。
- 防止不符合策略的资源被创建或更新,确保集群的安全性、合规性和一致性。
准入控制分为两个阶段:
- Mutating 阶段:修改资源对象的阶段,允许对请求的资源进行更改。
- Validating 阶段:验证资源对象的阶段,决定是否允许请求通过。
2. 准入控制的类型
Kubernetes 提供了两类准入控制机制:
2.1 内置准入控制器(Admission Controllers)
Kubernetes 提供了一系列内置的准入控制器,这些控制器是 API 服务器的静态插件,可以通过 API 服务器的启动参数 –enable-admission-plugins 启用或禁用。每个控制器负责特定的验证或修改逻辑。
常见的内置准入控制器包括:
- NamespaceLifecycle:确保删除中的命名空间不能创建新资源,防止已删除命名空间的资源被访问。
- LimitRange:强制执行命名空间中的资源限制(如 CPU、内存)。
- ResourceQuota:确保命名空间的资源使用量不超过配额。
- PodSecurity:强制执行 Pod 安全策略(如限制特权容器)。
- DefaultStorageClass:为没有指定存储类的 PVC 设置默认 StorageClass。
- DefaultTolerationSeconds:为 Pod 设置默认的容忍时间(taint toleration)。
- MutatingAdmissionWebhook:调用外部 Mutating Webhook。
- ValidatingAdmissionWebhook:调用外部 Validating Webhook。
- NodeRestriction:限制 kubelet 能修改的资源,增强节点安全性。
- ImagePolicyWebhook:通过外部 webhook 验证容器镜像。
- ServiceAccount:自动为 Pod 分配 ServiceAccount。
- AlwaysPullImages:强制容器镜像总是拉取最新版本。
2.2 准入 Webhook(Admission Webhooks)
准入 webhook 是一种动态扩展机制,允许用户定义自定义的准入控制逻辑。Webhook 是一个外部 HTTP 服务,API 服务器会向其发送请求以验证或修改资源对象。Webhook 分为两类:
- MutatingAdmissionWebhook:修改资源对象,例如添加标签、注入 sidecar 容器(如 Istio 的代理容器)。
- ValidatingAdmissionWebhook:验证资源对象,拒绝不符合策略的请求。
Webhook 通常用于实现复杂的自定义逻辑,例如:
- 强制执行组织的安全策略。
- 自动注入配置或 sidecar。
- 检查资源是否符合特定的合规性要求。
2.3 新引入的准入策略(Kubernetes 1.30+)
从 Kubernetes 1.30 开始,引入了 ValidatingAdmissionPolicy
和 MutatingAdmissionPolicy
,作为一种更结构化的准入控制方式。这些策略使用 Common Expression Language (CEL) 定义规则,相比 webhook 更轻量且无需外部服务。它们是集群级别的资源,适合定义简单的验证或修改逻辑。
3. 准入控制的工作流程
当 Kubernetes API 服务器收到一个请求(如创建 Pod),会按照以下步骤处理:
- 认证(Authentication):验证请求者的身份。
- 授权(Authorization):检查请求者是否有权限执行操作。
- 准入控制(Admission Control):
- Mutating 阶段:按顺序调用所有启用的 Mutating 准入控制器和 Mutating Webhook,修改资源对象。
- Validating 阶段:按顺序调用所有启用的 Validating 准入控制器和 Validating Webhook,验证资源对象。
- 如果任一 Validating 控制器拒绝请求,请求失败并返回错误。
- 持久化:通过验证的资源对象被写入 etcd。
注意:
- Mutating 阶段先于 Validating 阶段执行。
- 准入控制器的执行顺序由 –enable-admission-plugins 参数指定。
- 如果任何 Validating 控制器返回拒绝,请求会被阻止。
4. 常见用例
准入控制在 Kubernetes 中有广泛的应用场景,包括但不限于:
安全性:
使用 PodSecurity 限制特权容器或不安全的配置。
使用 ImagePolicyWebhook 限制 Pod 只能使用来自可信镜像仓库的镜像。
资源管理:
使用 ResourceQuota 和 LimitRange 限制命名空间的资源使用。
使用 DefaultStorageClass 为 PVC 自动分配存储类。
自动化配置:
使用 Mutating Webhook 自动为 Pod 注入 sidecar 容器(如日志收集代理)。
自动为资源添加标签或注释。
合规性:
使用 Validating Webhook 确保资源符合组织策略(如强制使用特定的标签或命名规范)。
使用 ValidatingAdmissionPolicy 检查 Pod 是否满足安全合规要求。
服务网格:
- Istio 或 Linkerd 使用 Mutating Webhook 自动为 Pod 注入代理容器。
参考链接:
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 george_95@126.com