天天看点

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/​​