如果你在Kubernetes上工作了一段时间,那么你可能会遇到这样一种情况:你必须为一些用户提供对Kubernetes集群的有限访问。例如,你可能希望用户(比如来自开发部门的Alice)只能访问development命名空间中的一些资源,而不能访问其他任何资源。为了实现这种基于角色的访问,我们在Kubernetes中使用了身份验证和授权的概念。

一般来说,有三种用户需要访问Kubernetes集群:

  1. 开发人员/管理员: 负责在集群上执行管理或开发任务的用户。这包括升级集群或在集群上创建资源/工作负载等操作。
  2. 最终用户: 访问部署在Kubernetes集群上的应用程序的用户。这些用户的访问限制由应用程序本身管理。例如,运行在Kubernetes集群上的web应用程序将拥有自己的安全机制,以防止未经授权的访问。
  • 应用程序/机器人: 其他应用程序可能需要访问Kubernetes集群,通常是与集群内的资源或工作负载进行通信。Kubernetes通过使用服务帐户( Service Accounts)来促进这一点,这是另一篇文章的主题。这里,我们将重点讨论基于角色的访问控制(Role Based Access Control,RBAC)。

因此,可以使用RBAC管理的用户类别是开发人员/管理员。简而言之,在使用RBAC时,你将创建用户并为他们分配角色。每个角色都映射了特定的授权,从而将每个用户限制为一组由分配给他们的角色定义的操作。到目前为止,Kubernetes还没有任何机制来创建或管理集群内的用户。它们需要在外部创建和管理。现在让我们实际看看Kubernetes的RBAC。

这里我们要做的是创建一个允许执行某些任务或仅从命名空间访问某些资源的用户。此用户不应能够执行任何其他任务或访问任何其他资源。

我已经使用了一个minikube集群来演示这一点,但是只要你有一个运行良好的Kubernetes集群,也会很适合你。如果你感兴趣,下面是我的具体minikube版本。

Kubernetes v1.14.2 on Docker 18.09.6
minikube version: v1.1.0

让我们首先创建一个命名空间。

$ kubectl create namespace development
namespace/development created

创建用于身份验证的客户端证书

因为我们知道,任何客户机都可以使用基于SSL的身份验证机制,通过向kube-apiserver进行身份验证来访问Kubernetes集群。我们将不得不生成私钥和X-509客户端证书,以便对一个名为DevUser的用户进行kube-apiserver身份验证。该用户将使用development命名空间。让我们为DevUser创建私钥和CSR(Certificate Signing Request,证书签名请求)

$ cd ${HOME}/.kube
$ openssl genrsa -out DevUser.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
$ openssl req -new -key DevUser.key -out DevUser.csr -subj "/CN=DevUser/O=development"

主题(subject)的通用名称(common name,CN)将用作身份验证请求的用户名。组织字段(organization field,O)将用于表示用户的组成员关系。

当我们有了私钥和CSR,我们就必须自签名CSR来生成证书。我们必须提供Kubernetes集群的CA密钥来生成证书,因为这个CA已经被minikube集群批准了。

$ openssl x509 -req -in DevUser.csr -CA ${HOME}/.minikube/ca.crt -CAkey ${HOME}/.minikube/ca.key -CAcreateserial -out DevUser.crt -days 45
Signature ok
subject=CN = DevUser, O = development
Getting CA Private Key

请务必提供正确的CA证书和密钥集。要了解这一点,你可以运行kubectl config view并获取详细信息。

配置kubectl

现在你已经有了一个用户(DevUser)、一个私有密匙和一个证书来连接kube-apiserver,是时候在一个配置文件(即Kubeconfig)中配置这些细节了。我们可以使用这些细节来查询来自Kubernetes集群的资源。我们可以手动配置这些细节,也可以使用kubectl客户端对配置文件进行更改。Kubeconfig文件与其他Kubernetes资源清单一样,有三个主要部分:clusters(集群)、contexts(上下文)和users(用户)。正如名称所暗示的那样,kubeconfig文件的集群部分将包含集群的详细信息。用户部分将包含用户的详细信息,而上下文部分将包含集群和用户之间的关系。我们在配置文件中有另一个字段,它告诉我们当前配置的上下文。如果我们在使用kubectl时不提供任何上下文,则将使用此上下文。

下面是我拥有的kubeconfig文件的一个示例。

# cat ~/.kube/config
apiVersion: v1
clusters:
- cluster:
certificate-authority: /home/vivek/.minikube/ca.crt
server: https://192.168.99.100:8443
name: minikube
contexts:
- context:
cluster: minikube
user: minikube
name: minikube
current-context: minikube
kind: Config
preferences: {}
users:
- name: minikube
user:
client-certificate: /home/vivek/.minikube/client.crt
client-key: /home/vivek/.minikube/client.key

将条目添加到users部分

让我们继续添加我们创建的用户。要在Kubeconfig文件中添加用户,我们可以执行下面的命令(set-credentials)。请确保你提供了正确的私钥路径和DevUser证书。

$ kubectl config set-credentials DevUser –client-certificate ${HOME}/.kube/DevUser.crt –client-key ${HOME}/.kube/DevUser.key
User “DevUser” set.

现在,如果我们使用kubectl config view命令查看配置文件,我们将能够看到在用户部分中添加的新用户。

$ kubectl config view
…
users:
- name: DevUser
user:
client-certificate: DevUser.crt
client-key: DevUser.key
- name: minikube
user:
client-certificate: /home/vivek/.minikube/client.crt
client-key: /home/vivek/.minikube/client.key

将条目添加到contexts部分

下一步是在配置文件中添加上下文,这将允许该用户(DevUser)访问集群中的开发命名空间。使用下面的命令执行操作。

$ kubectl config set-context DevUser-context --cluster=minikube --namespace=development --user=DevUser
Context "DevUser-context" created.

验证配置文件中是否添加了其他上下文。

# cat ~/.kube/config
…
contexts:
- context:
cluster: minikube
namespace: development
user: DevUser
name: DevUser-context
- context:
cluster: minikube
user: minikube
name: minikube

向用户添加更多权限

运行kubectl get pods将返回当前上下文minikube命名空间的默认资源。但是如果我们更改上下文DevUser-context,我们将无法访问资源。因此,运行带有新上下文的kubectl get pods将导致下面的错误:

$ kubectl get pods --context=DevUser-context 
Error from server (Forbidden): pods is forbidden: User "DevUser" cannot list resource "pods" in API group "" in the namespace "development"

为了使这个新创建的用户能够只访问development命名空间中的pods,让我们创建一个角色,然后使用rolebinding资源将该角色绑定到DevUser。角色就像Kubernetes的其他资源一样。它决定了一个人在扮演这个角色时能够采取的资源和行动。使用以下清单创建角色资源:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: dev-role
namespace: development
rules:
- apiGroups: [""] 
resources: ["pods"]
verbs: ["get", "update", "list"]

我们只提供了动词get、update和list。这确保DevUser只能获取、更新和列出pod上的活动,而不能做其他事情。

使用下面的清单,使用rolebinding资源将我们在上面创建的角色绑定到

DevUser:
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: dev-DevUser
namespace: development
subjects:
- kind: User
name: DevUser
apiGroup: ""
roleRef:
kind: Role
name: dev-role
apiGroup: ""

因此,你可以在这里看到,我们正在将角色dev-role(我们在前面创建的)与DevUser关联起来。

在创建角色和角色绑定之后,让我们再次列出pod。我们将成功地把它们列出来。

$ kubectl get pods --context=DevUser-context 
No resources found.
# we are not able to see any resources because we don't have any pods running
# in development namespace

正如你现在看到的,我们可以使用新创建的上下文列出资源。我们知道DevUser应该只能获取、更新和列出pod。让我们尝试使用这个上下文创建一个pod。

$ kubectl run nginx --image=nginx --context=DevUser-context 
Error from server (Forbidden): deployments.apps is forbidden: User "DevUser" cannot create resource "deployments" in API group "apps" in the namespace "development"

类似地,如果试图使用此上下文删除正在运行的pod,则无法这样做。如果你想让该用户也能够创建和删除,那么只需更改分配给该用户的角色。确保你有正确的资源和角色中的动词。

如果希望让其他用户能够访问你的集群,请重复这些步骤。