Kubernetes权限说明
Kubernetes对外只暴露了api-server一个入口,对Kubernetes所有资源的操作都需要通过调用api-server的方式来实现,api-server一般都是通过RBAC的方式来实现权限的控制,大部分人可能对api-server如何对用户进行授权和鉴权一知半解,没有搞清楚用户和组以及ServiceAccount的概念,因此做一个相对简单的说明。由于个人能力有限,如有错误还望不吝指出。
RBAC API声明了四种对象,分别是Role、ClusterRole、RoleBinding、ClusterRoleBinding,下面就对这几个对象进行详细的说明。
Role--角色
用于在限定的命名空间中设定资源的操作权限,下面是一个示例的role,在default命名空间限定了pod的只读权限。
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
# 可以通过resourceNames:[] 来指定仅获取某些特定名称pod的资源,从而实现更细粒度的权限控制
verbs: ["get", "watch", "list"]
ClusterRole--集群角色
用于在整个集群中设定资源的操作权限,不知局限于具体命名空间,下面是一个示例的clusterrole,在整个集群中限定了pod的只读权限。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
# 可以通过resourceNames:[] 来指定仅获取某些特定名称pod的资源,从而实现更细粒度的权限控制
verbs: ["get", "watch", "list"]
Kubernetes内置的Role和ClusterRole
kubernetes实际上内置很多使用的Role以及ClusterRole来方便我们对集群做权限的管理,具体有哪些内置的角色可以参考官方文档,本文只举例几个常用的ClusterRole进行说明。可以通过 kubectl get clusterrole来获取对应的列表。
view
具有只读权限的ClusterRole
edit
具有操作部分资源的ClusterRole,包括pod、configmap等,但是无法操作secret以及创建rule和rolebinding的权限,通常可以作为指定命名空间下的普通用户权限来对处理。
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: admin-binding
namespace: test
subjects:
- kind: User
name: test
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: edit
apiGroup: rbac.authorization.k8s.io
admin
具有edit的所有权限,同时可以操作secret、rule、rulebinding等资源,通常通过rolebinding将其与指定命名空间下的user或者group进行绑定,从而赋予用户或组在指定命名空间中的管理员权限。可以以下面的示例为参考,赋予一个用户指定命名空间中的管理员权限。
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: admin-binding
namespace: test
subjects:
- kind: User
name: test
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: admin
apiGroup: rbac.authorization.k8s.io
cluster-admin
集群管理员,拥有集群的所有权限,此权限不应该随意给到用户。
RoleBinding--角色绑定
用于在限定的命名空间中绑定Role(ClusterRule)的权限到指定的用户或者组上,从而赋予用户或组操作资源的权限。
ClusterRoleBinding--集群角色绑定
用于在限定的明明空间中绑定ClusterRule的权限到指定的用户或者组上,从而赋予用户或组操作资源的权限。ClusterRoleBinding不需要指定具体的命名空间,而是在所有的命名空间都有权限。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-binding
subjects:
- kind: User
name: test
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: admin
apiGroup: rbac.authorization.k8s.io
User、Group
User和Group是无法通过kubectl get user(group)来获得的,大部分刚接触kubernetes的人可能会对此比较迷惑,既然无法获得,那怎么来判断这个用户或者组是否存在的呢?api-server又怎么知道客户端是的用户是谁呢,属于哪个组呢?接下来就详细说明一下其中的原理。
首先我们要先了解一下kubectl是如何调用api-server,我们都知道有config文件的存在,下面是一个config文件的组成部分,出于所见篇幅的原因,将其中的一些参数值以X替代。
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: XXXX
server: https://XXX.XXX.XXX.XXX:443
name: local
contexts:
- context:
cluster: local
user: test
name: test
- context:
cluster: local
user: kube-admin-local
name: local
current-context: local
kind: Config
preferences: {}
users:
- name: test
user:
client-certificate-data: XXXX
client-key-data: XXXX
- name: kube-admin-local
user:
client-certificate-data: XXXXX
client-key-data: XXXXXXXX
主要包含一下这几个部分clusters、context、current-context以及users,下面稍微解释一下。
-
clusters---集群的信息,其中包含集群的crt证书信息,以及api-server接口的地址,可以包含多个cluster。
-
context---上下文,这个说的更直白一点就是cluster和user的配对。
-
current-context---当前上下文
-
users---用户信息,包含用户的名称、组以及经过api-server认证过的crt证书信息,但具体的内容已经被加密处理,api-server经过解密就可以得出来。
User和Group信息其实就是从user的内容中解析出来的,那这些信息又是如何生成的呢,那这就又要简单的提一下如何创建一个用户以及kubernetes复杂的tls认证过程了。
一般添加一个用户的流程如下所示:
# 生成一个客户端的key
openssl genrsa -out test.key 2048
# 通过key生成一个客户端的csr证书,并指定用户命和组名
# 其中CN表示用户命,而O表示组名,一个组可以有多个用户,组名可以根据实际需要填写,也可以不填写,仅使用用户名
openssl req -new -key test.key -out test.csr -subj "/CN=test/O=apps"
# 创建一个csr请求,要求kube-controller对这个生成的客户端证书进行认证并通过ca来进行签名
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: test
spec:
groups:
- system:authenticated
request: $(cat test.csr | base64 | tr -d "\n")
signerName: kubernetes.io/kube-apiserver-client
usages:
- client auth
EOF
# 批准客户端的认证请求
kubectl certificate approve test
# 将该用户与内置的admin ClusterRole进行绑定,授予其管理员权限,到这一步,用户test实际上已经获得了访问test命名空间下大部分资源的操作权限,接下来就是如何让客户端调用的时候带上用户信息
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test-binding
namespace: test
subjects:
- kind: User
name: test
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: admin
apiGroup: rbac.authorization.k8s.io
EOF
# 获取签发完成的crt证书信息并将其写到本地文件
kubectl get csr test-o jsonpath='{.status.certificate}' | base64 -d > test.crt
# 将获取到的crt信息以及客户端的key写入到config文件的users中,为了方便起见,通过将embed-certs=true来将文件内容直接写入进去
kubectl config set-credentials test --client-key=./test.key --client-certificate=./test.crt --embed-certs=true
# 添加一个上下文,并将已有的cluster与刚才写入的user作为一对
kubectl config set-context test --cluster=local --user=test
# 将当前的上下文切换到刚才生成的上下文
kubectl config use-context test
# 完成这些操作之后,当我们再通过kubectl指令调用的api-server的时候就会使用test这个用户了,并且权限也会与之前设定的对应,只能用于操作test命名空间下的资源了。
连接完用户是怎么来的以后就可以了解一下Group的概念了。
Group就是对User的一个分组,比如我们想要一个Group都拥有test命名空间下的管理员权限,如果没有Group的情况下我们就需要一个用户添加一个RoleBinding,这样非常的不变,所以就可以通过将RoleBinding,将管理员权限直接绑定到一个Group上就可以让指定Group下的所有用户全部获得管理员权限。
# 创建指定group的用户
openssl req -new -key test.key -out test.csr -subj "/CN=test/O=test"
# 创建rolebinding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test-group-binding
namespace: test
subjects:
- kind: Group
name: test
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: admin
apiGroup: rbac.authorization.k8s.io
# 后续再创建用户的时候,只要指定group为test即可
ServiceAccount
既然谈到了User和Group,就避免不了谈一下ServiceAccount,首先要谈一下Servcie和User的区别。
最简单的理解方式就是,User和Group主要是给外部客户端(如kubectl)调用api-server时做权限控制的,而ServiceAccount是给运行在kubernetes内部的服务调用api-server的时候做权限控制的。
实际上每个运行的pod,如果没有指定serviceaccount的话都会生成一个default的serviceaccount,并且会作为一个文件挂载到/var/run/secrets/kubernetes.io/serviceaccount目录下,默认的ServiceAccount是没有权限调用api-server接口的。
当一个pod需要访问api-server资源的时候就需要额外的权限了,这时候就可以先通过RoleBinding将ServiceAccount与具有权限的Role进行绑定,然后为pod指定ServiceAccount来获取调用的权限。
# ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-serviceaccount
# RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: admin-binding
subjects:
- kind: ServiceAccount
name: admin-serviceaccount
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: admin
apiGroup: rbac.authorization.k8s.io
# Pod
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginx
serviceAccountName: admin-serviceaccount
生产环境的注意点
1、 一定要严格管控生产环境下的权限,不要随意给予超级管理员权限给到普通用于,要严格把控各个命名空间的权限,切勿直接把超级管理员的config文件给到开发人员直接使用。
2、 建议平时使用时多用rolebinding,不要为了方便就使用clusterrolebinding而造成权限管控混乱。
RBAC:https://kubernetes.io/zh/docs/reference/access-authn-authz/rbac/
ServiceAccount:https://kubernetes.io/zh/docs/tasks/configure-pod-container/configure-service-account/