Kubernetes 使用 API 服务器对 API 请求进行鉴权。 它根据所有策略评估所有请求属性来决定允许或拒绝请求。 一个 API 请求的所有部分都必须被某些策略允许才能继续。 这意味着默认情况下拒绝权限。
当系统配置了多个鉴权模块时,Kubernetes 将按顺序使用每个模块。 如果任何鉴权模块批准或拒绝请求,则立即返回该决定,并且不会与其他鉴权模块协商。 如果所有模块对请求没有意见,则拒绝该请求。 被拒绝响应返回 HTTP 状态代码 403。
鉴权模块
- Node :一个专用鉴权模式,根据调度到 kubelet 上运行的 Pod 为 kubelet 授予权限
- ABAC :基于属性的访问控制(ABAC)定义了一种访问控制范型,通过使用将属性组合在一起的策略, 将访问权限授予用户。策略可以使用任何类型的属性(用户属性、资源属性、对象,环境属性等)
- RBAC :基于角色的访问控制(RBAC) 是一种基于企业内个人用户的角色来管理对计算机或网络资源的访问的方法;
- Webhook :WebHook 是一个 HTTP 回调:发生某些事情时调用的 HTTP POST; 通过 HTTP POST 进行简单的事件通知。 实现 WebHook 的 Web 应用程序会在发生某些事情时将消息发布到 URL。
鉴权模块设置参数
设置鉴权策略使用的参数有:
--authorization-mode=ABAC
基于属性的访问控制(ABAC)模式允许你使用本地文件配置策略。--authorization-mode=RBAC
基于角色的访问控制(RBAC)模式允许你使用 Kubernetes API 创建和存储策略。--authorization-mode=Webhook
WebHook 是一种 HTTP 回调模式,允许你使用远程 REST 端点管理鉴权。--authorization-mode=Node
节点鉴权是一种特殊用途的鉴权模式,专门对 kubelet 发出的 API 请求执行鉴权。--authorization-mode=AlwaysDeny
该标志阻止所有请求。仅将此标志用于测试。--authorization-mode=AlwaysAllow
此标志允许所有请求。仅在你不需要 API 请求的鉴权时才使用此标志。
你可以选择多个鉴权模块。模块按顺序检查,以便较靠前的模块具有更高的优先级来允许或拒绝请求。
RBAC鉴权
基于角色(Role)的访问控制(RBAC)是一种基于组织中用户的角色来调节控制对计算机或网络资源的访问的方法。
RBAC 鉴权机制使用 rbac.authorization.k8s.io
来驱动鉴权决定, 允许你通过 Kubernetes API 动态配置策略。
要启用 RBAC,在启动API 服务器时将 --authorization-mode
参数设置为一个逗号分隔的列表并确保其中包含 RBAC
。
kube-apiserver --authorization-mode=Node,RBAC --<其他选项> --<其他选项>
Role 和 ClusterRole
Role 总是用来在某个名字空间内设置访问权限;ClusterRole 则是一个集群作用域的资源。
Role 示例
下面是一个位于 “default” 名字空间的 Role 的示例,可用来授予对Pod的读访问权限:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""] # "" 标明 core API 组
resources: ["pods"]
verbs: ["get", "watch", "list"]
ClusterRole 示例
ClusterRole 同样可以用于授予 Role 能够授予的权限。 因为 ClusterRole 属于集群范围,所以它也可以为以下资源授予访问权限:
- 集群范围资源(比如Node)
- 非资源端点(比如
/healthz
) - 跨名字空间访问的名字空间作用域的资源(如 Pod)
下面是一个 ClusterRole 的示例,可用来为任一特定名字空间中的 Secret授予读访问权限, 或者跨名字空间的访问权限(取决于该角色是如何绑定的):
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
# "namespace" 被忽略,因为 ClusterRoles 不受名字空间限制
name: secret-reader
rules:
- apiGroups: [""]
# 在 HTTP 层面,用来访问 Secret 资源的名称为 "secrets"
resources: ["secrets"]
verbs: ["get", "watch", "list"]
Role 或 ClusterRole 对象的名称必须是合法的路径分段名称。
RoleBinding 和 ClusterRoleBinding
角色绑定(Role Binding)是将角色中定义的权限赋予一个或者一组用户。 它包含若干主体(Subject)(用户、组或服务账户)的列表和对这些主体所获得的角色的引用。 RoleBinding 在指定的名字空间中执行授权,而 ClusterRoleBinding 在集群范围执行授权。
一个 RoleBinding 可以引用同一的名字空间中的任何 Role。 或者,一个 RoleBinding 可以引用某 ClusterRole 并将该 ClusterRole 绑定到 RoleBinding 所在的名字空间。 如果你希望将某 ClusterRole 绑定到集群中所有名字空间,你要使用 ClusterRoleBinding。
RoleBinding 示例
下面的例子中的 RoleBinding 将 “pod-reader” Role 授予在 “default” 名字空间中的用户 “jane”。 这样,用户 “jane” 就具有了读取 “default” 名字空间中所有 Pod 的权限。
apiVersion: rbac.authorization.k8s.io/v1
# 此角色绑定允许 "jane" 读取 "default" 名字空间中的 Pod
# 你需要在该名字空间中有一个名为 “pod-reader” 的 Role
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects:
# 你可以指定不止一个“subject(主体)”
- kind: User
name: jane # "name" 是区分大小写的
apiGroup: rbac.authorization.k8s.io
roleRef:
# "roleRef" 指定与某 Role 或 ClusterRole 的绑定关系
kind: Role # 此字段必须是 Role 或 ClusterRole
name: pod-reader # 此字段必须与你要绑定的 Role 或 ClusterRole 的名称匹配
apiGroup: rbac.authorization.k8s.io
RoleBinding 也可以引用 ClusterRole,以将对应 ClusterRole 中定义的访问权限授予 RoleBinding 所在名字空间的资源。这种引用使得你可以跨整个集群定义一组通用的角色, 之后在多个名字空间中复用。
例如,尽管下面的 RoleBinding 引用的是一个 ClusterRole,“dave”(这里的主体, 区分大小写)只能访问 “development” 名字空间中的 Secret 对象,因为 RoleBinding 所在的名字空间(由其 metadata 决定)是 “development”。
apiVersion: rbac.authorization.k8s.io/v1
# 此角色绑定使得用户 "dave" 能够读取 "development" 名字空间中的 Secret
# 你需要一个名为 "secret-reader" 的 ClusterRole
kind: RoleBinding
metadata:
name: read-secrets
# RoleBinding 的名字空间决定了访问权限的授予范围。
# 这里隐含授权仅在 "development" 名字空间内的访问权限。
namespace: development
subjects:
- kind: User
name: dave # 'name' 是区分大小写的
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
ClusterRoleBinding 示例
要跨整个集群完成访问权限的授予,你可以使用一个 ClusterRoleBinding。 下面的 ClusterRoleBinding 允许 “manager” 组内的所有用户访问任何名字空间中的 Secret。
apiVersion: rbac.authorization.k8s.io/v1
# 此集群角色绑定允许 “manager” 组中的任何人访问任何名字空间中的 Secret 资源
kind: ClusterRoleBinding
metadata:
name: read-secrets-global
subjects:
- kind: Group
name: manager # 'name' 是区分大小写的
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
创建了绑定之后,你不能再修改绑定对象所引用的 Role 或 ClusterRole。 试图改变绑定对象的 roleRef
将导致合法性检查错误。 如果你想要改变现有绑定对象中 roleRef
字段的内容,必须删除重新创建绑定对象。
这种限制有两个主要原因:
-
将
roleRef
设置为不可以改变,这使得可以为用户授予对现有绑定对象的update
权限, 这样可以让他们管理主体列表,同时不能更改被授予这些主体的角色。 -
针对不同角色的绑定是完全不一样的绑定。要求通过删除/重建绑定来更改
roleRef
, 这样可以确保要赋予绑定的所有主体会被授予新的角色(而不是在允许或者不小心修改了roleRef
的情况下导致所有现有主体未经验证即被授予新角色对应的权限)。
命令 kubectl auth reconcile
可以创建或者更新包含 RBAC 对象的清单文件, 并且在必要的情况下删除和重新创建绑定对象,以改变所引用的角色。 更多相关信息请参照命令用法和示例。
创建普通用户
给普通用户操作单Namespace下操作权限
- 创建用户凭证
[root@master rbac]# id haifeng
uid=1001(haifeng) gid=1001(haifeng) 组=1001(haifeng)
[root@master rbac]# openssl genrsa -out haifeng.key 2048
[root@master rbac]# openssl req -new -key haifeng.key -out haifeng.csr -subj "/CN=haifeng/O=haifeng"
# 集群kubeadm安装的,CA证书在/etc/kubernetes/pki目录下
[root@master rbac]# openssl x509 -req -in haifeng.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out haifeng.crt -days 500
# 创建haifeng用户凭证
[root@master rbac]# kubectl config set-credentials haifeng --client-certificate=haifeng.crt --client-key=haifeng.key
# 添加上下文配置
[root@master rbac]# kubectl config set-context haifeng-context --cluster=kubernetes --namespace=kube-system --user=haifeng
# 验证
[root@master rbac]# cat ~/.kube/config |grep haifeng
user: haifeng
name: haifeng-context
- name: haifeng
client-certificate: /tmp/haifeng.crt
client-key: /tmp/haifeng.key
kubectl config set-credentials
用于设置或修改kubeconfig文件中特定用户的认证信息。Kubeconfig文件是 Kubernetes用来存储访问集群所需的配置信息的文件,包括集群信息、用户信息以及上下文(context)等;
kubectl config set-context
主要作用是设置或修改kubeconfig文件中特定的上下文(context)配置
- 创建角色
# haifeng-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: haifeng-role
namespace: default
rules:
- apiGroups: ["", "apps"] # 定义可访问的API对象
resources: ["deployments", "replicasets", "pods"] # 定义可访问的API资源类型
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # 允许的操作,如果全部允许可以使用['*']
补充两个命令:
kubectl explain
命令显示 Kubernetes 中资源对象(例如 Pod、Service、Deployment 等)和其各个字段的详细信息
kubectl api-resources
命令显示集群中所有可用的API资源信息
- 创建角色权限绑定
# haifeng-rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: haifeng-rolebinding
namespace: default
subjects:
- kind: User
name: haifeng
apiGroup: ""
roleRef:
kind: Role
name: haifeng-role
apiGroup: rbac.authorization.k8s.io # 字符串可以为空,默认使用当前的apiGroup
- 测试验证
[root@master rbac]# kubectl get pods --context=haifeng-context
Error from server (Forbidden): pods is forbidden: User "haifeng" cannot list resource "pods" in API group "" in the namespace "kube-system"
[root@master rbac]# kubectl get pods --context=haifeng-context -n default
NAME READY STATUS RESTARTS AGE
happy-panda-mariadb-0 0/1 Pending 0 93m
happy-panda-wordpress-d9c9b875-qw6nc 0/1 Pending 0 93m
nginx-deploy-7848d4b86f-d5hsk 1/1 Running 0 133m
nginx-deploy-7848d4b86f-wjbgt 1/1 Running 0 133m
创建服务账户
Service Account在Kubernetes中是为了方便Pod里面的进程调用Kubernetes API或其他外部服务而设计的。通过Service Account,可以实现访问控制,即为不同的用户或服务设置不同的权限和访问级别。
Service Account的作用
- 身份验证与授权:Service Account为Pod中的进程提供了一种身份标识,使其能够访问Kubernetes API。与user account的全局性权限不同,service account更适合一些轻量级的任务,更聚焦于授权给某些特定Pod中的进程所使用。每个Pod都会自动关联一个Service Account,如果没有自定义,则采用默认的Service Account。
- 资源访问控制:通过为不同的Service Account分配不同的权限,可以实现对资源的访问控制。这意味着你可以控制哪些Pod可以访问哪些资源,从而增强了系统的安全性。
- API通信:Pod通过Service Account中的token文件(通常位于/var/run/secret/kubernetes.io/serviceaccount/token)来进行API服务器的身份认证,实现与API服务器的通信。
单Namespace访问
- 创建service account账户
[root@master rbac]# kubectl create sa haifeng-sa -n kube-system
serviceaccount/haifeng-sa created
- 创建角色
# haifeng-sa-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: haifeng-sa-role
namespace: kube-system
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
[root@master rbac]# kubectl apply -f haifeng-sa-role.yaml
role.rbac.authorization.k8s.io/haifeng18-sa-role created
- 创建角色权限绑定
# haifeng-sa-rolebinding.yaml
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: haifeng-sa-rolebinding
namespace: kube-system
subjects:
- kind: ServiceAccount
name: haifeng-sa
namespace: kube-system
roleRef:
kind: Role
name: haifeng-sa-role
apiGroup: rbac.authorization.k8s.io
---
[root@master rbac]# kubectl apply -f haifeng-sa-rolebinding.yaml
rolebinding.rbac.authorization.k8s.io/haifeng-sa-rolebinding created
- 提取账户Token
[root@master rbac]# kubectl get secret -n kube-system |grep haifeng-sa
haifeng-sa-token-rtqrk kubernetes.io/service-account-token 3 6m3s
[root@master rbac]# kubectl get secret -n kube-system |grep haifeng-sa-token-rtqrk
haifeng-sa-token-rtqrk kubernetes.io/service-account-token 3 20m
# 通过base64 工具解码Token数据
[root@master rbac]# kubectl get secret haifeng-sa-token-rtqrk -o jsonpath={.data.token} -n kube-system |base64 -d
eyJhbGciOiJSUzI1NiIsImtpZ......
- 访问接口验证
# 访问默认的命名空间没有权限
[root@master rbac]# curl -H "Authorization: Bearer $Token" https://10.x.x.x:6443/api/v1/namespaces/default/pods -k
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {
},
"status": "Failure",
"message": "pods is forbidden: User \"system:serviceaccount:kube-system:haifeng-sa\" cannot list resource \"pods\" in API group \"\" in the namespace \"default\"",
"reason": "Forbidden",
"details": {
"kind": "pods"
},
"code": 403
}
# 访问kube-system命名空间
[root@master rbac]# curl -H "Authorization: Bearer $Token" https://10.x.x.x.:6443/api/v1/namespaces/kube-system/pods/calico-node-84lrq -k
{
"kind": "Pod",
"apiVersion": "v1",
"metadata": {
"name": "calico-node-84lrq",
"generateName": "calico-node-",
"namespace": "kube-system",
"uid": "b5b39647-cfe7-4ed3-91ac-a50a38ea334c",
"resourceVersion": "4940",
"creationTimestamp": "2024-03-13T03:16:04Z",
"labels": {
"controller-revision-hash": "66f8c6dcdb",
"k8s-app": "calico-node",
"pod-template-generation": "1"
},
"ownerReferences": [
{
"apiVersion": "apps/v1",
"kind": "DaemonSet",
"name": "calico-node",
"uid": "b9c318b1-8267-48cb-b870-590fb6b45a20",
"controller": true,
"blockOwnerDeletion": true
}
]
......
}
全局访问
- 创建账户
[root@master rbac]# kubectl create sa haifeng-sa2 -n kube-system
serviceaccount/haifeng-sa2 created
- 创建ClusterRoleBinding
# 给haifeng-sa2绑定cluster-admin的角色权限
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: haifeng-sa2-clusterrolebinding
subjects:
- kind: ServiceAccount
name: haifeng-sa2
namespace: kube-system
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
验证方法同上。
Node 鉴权
节点鉴权是一种特殊用途的鉴权模式,专门对 kubelet 发出的 API 请求进行授权。
节点鉴权器允许 kubelet 执行 API 操作。包括:
读取操作
- services
- endpoints
- nodes
- pods
- 与绑定到 kubelet 节点的 Pod 相关的 Secret、ConfigMap、PersistentVolumeClaim 和持久卷
写入操作
- 节点和节点状态(启用
NodeRestriction
准入插件以限制 kubelet 只能修改自己的节点) - Pod 和 Pod 状态 (启用
NodeRestriction
准入插件以限制 kubelet 只能修改绑定到自身的 Pod) - 事件
身份认证与鉴权相关的操作
- 对于基于 TLS 的启动引导过程时使用的 certificationsigningrequests API 的读/写权限
- 为委派的身份验证/鉴权检查创建 TokenReview 和 SubjectAccessReview 的能力
在将来的版本中,节点鉴权器可能会添加或删除权限,以确保 kubelet 具有正确操作所需的最小权限集。
为了获得节点鉴权器的授权,kubelet 必须使用一个凭据以表示它在 system:nodes
组中,用户名为 system:node:<nodeName>
。上述的组名和用户名格式要与 kubelet TLS 启动引导 过程中为每个 kubelet 创建的标识相匹配。
<nodeName>
的值必须与 kubelet 注册的节点名称精确匹配。默认情况下,节点名称是由 hostname
提供的主机名,或者通过 kubelet --hostname-override
选项 覆盖。 但是,当使用 --cloud-provider
kubelet 选项时,具体的主机名可能由云提供商确定, 忽略本地的 hostname
和 --hostname-override
选项。有关 kubelet 如何确定主机名的详细信息,请参阅 kubelet 选项参考。
要启用节点鉴权器,请使用 --authorization-mode=Node
启动 API 服务器。
要限制 kubelet 可以写入的 API 对象,请使用 --enable-admission-plugins=...,NodeRestriction,...
启动 API 服务器,从而启用 NodeRestriction 准入插件。