在kubernetes集群中配置RBAC
简介
本文将介绍Kubernetes基于角色的访问控制(RBAC)API对象,以及两个常见的用例(创建具有受限访问权限的用户、POD内通过service account访问api)。在本文的最后,您应该具有足够的知识来在集群中使用RBAC策略。
从Kubernetes 1.6版本起,系统默认启用RBAC策略。 RBAC策略对于正确管理群集至关重要,因为它们使您可以根据用户及其在组织中的角色来指定允许的操作类型。包括:
- 通过仅向管理员用户授予特权操作(例如访问机密)来保护集群。
在集群中强制用户认证。 - 将资源创建(例如pod,持久卷,部署)限制为特定的名称空间。您还可以使用配额来确保资源使用受到限制并受到控制。
- 让用户仅在其授权的名称空间中查看资源。这使您可以隔离组织内的资源(例如,部门之间)。
- 由于默认启用了RBAC,因此在配置网络(例如flanneld)或使Helm时,您可能会看到类似这样的错误:
the server does not allow access to the requested resource
本文将向您展示如何使用RBAC,以便您可以正确处理此类问题。
准备工作
为了充分的了解本文,建议您有一套完整的Kubernetes环境,并能按我们的步骤完成整个过程,环境要求如下:
- Kubernetes 1.6以上版本,1.6前的版本,需要手动启用RBAC,如果您是在本机用minikube安装kubernetes,命令行如下:
minikube start --extra-config=apiserver.Authorization.Mode=RBAC
- 安装kubectl命令行工具。
- 安装了OpenSSL。
RBAC API 对象
Kubernetes的一项基本功能是其所有资源都是模型化的API对象,该对象允许进行CRUD(创建,读取,更新,删除)操作。 资源包括:
- Pods.
- PersistentVolumes.
- ConfigMaps.
- Deployments.
- Nodes.
- Secrets.
- Namespaces.
这些资源上可能的操作示例如下:
- create
- get
- delete
- list
- update
- edit
- watch
- exec
在更高级别上,资源与API Group(API组)相关联(例如,Pod属于核心API group,而Deployment属于apps API group)。 有关所有可用资源,操作和API组的更多信息,请查看官方Kubernetes API参考。
为了在Kubernetes中管理RBAC,除了资源和操作外,我们还需要理解以下概念:
- Rules:规则是可以对属于不同API组的一组资源执行的一组操作。
- Roles 和 ClusterRoles: 两者都是规则。 Role和ClusterRole之间的区别在于范围:在Role中,规则只适用于单个命名空间(namespace),而ClusterRole则适用于整个群集,因此Role适用于多个命名空间。 ClusterRoles还可为集群范围内的资源(例如节点)定义规则。 Role和ClusterRoles都映射为集群内的API资源。
- Subjects:这些对应于尝试在集群中进行操作的实体。共有三种类型的主题:
- User Accounts(用户帐户):这些是全局帐户,用于集群外部的用户或程序。 Kubernetes集群中没有关联的资源API对象。
- Service Accounts(服务帐户):此帐户是和命名空间相关的,适用于在Pod内部运行的进程,这些进程需要调用API时进行身份验证。
- Groups(组):用于引用多个帐户,默认情况下会创建一些组,例如cluster-admin(在后面的部分中进行说明)。
- RoleBindings 和 ClusterRoleBindings: 就像名称的意思,这些将Subjects绑定到角色(即给定用户可以执行的操作)。RoleBinding将使规则在命名空间内有效,而ClusterRoleBinding将使规则在所有命名空间内有效。
您可以在Kubernetes官方文档中找到每个API元素的示例。
示例1: 创建一个新的用户,从远程访问kubernetes集群
在此示例中,我们将为“开发组(development)”的"cjzhao"用户创建一个独享的命名空间(cjns),并从远程服务器访问集群,主要包括以下对象:
- Username: cjzhao
- Group: development
- Namespace: cjns
我们将添加必要的RBAC策略,以便用户cjzhao
仅在cjns
命名空间内即可完全管理deployment
(即使用kubectl run命令)。 最后,我们将测试这些策略以确保它们按预期工作。
创建namespace
执行kubectl create
命令创建命名空间(以admin用户身份):
kubectl create namespace cjns
创建用户凭证(User Credentials)
Kubernetes没有用于用户帐户的API。 这里我们使用OpenSSL证书(更多的认证方式请参见Kubernetes官方文档)来管理身份验证,具体步骤如下:
在kubernetes管控节点(或管理员机器)上执行下面操作
- 为您的用户创建一个私钥。在此示例中,我们将文件命名为cjzhao.key:
openssl genrsa -out cjzhao.key 2048
- 使用您刚创建的私钥(cjzhao.key)创建证书签名请求cjzhao.csr。 确保在-subj部分中指定用户名和组(CN表示用户名,O表示用户组)。 如前所述,我们将使用cjzhao作为名称,使用development作为用户组:
openssl req -new -key cjzhao.key -out cjzhao.csr -subj "/CN=cjzhao/O=development"
-
找到您的Kubernetes群集证书颁发机构(CA)文件。 这将负责批准请求并生成访问群集API所需的证书。 它的位置通常在
/etc/kubernetes/pki /
目录下。 对于Minikube,它在〜/.minikube/
。 检查目录下是否存在ca.crt和ca.key文件,并将它们拷贝到当前目录。 -
通过批准您之前提出的证书签名请求cjzhao.csr来生成最终的证书cjzhao.crt,设置证书有效期为500天,执行如下命令:
openssl x509 -req -in cjzhao.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out cjzhao.crt -days 500
- 将cjzhao.crt、cjzhao.key、ca.crt几个文件打包拷贝到新的机器。
在新的机器上执行下面操作
- 在安装了kubectl命令行工具的新的机器上解压上一步中打包的文件,执行如下命令,配置kubernetes集群、用户凭据等信息:
//配置集群
kubectl config set-cluster MyK8sCluster --server=https://your_server_ip:6443 --certificate-authority=./ca.crt
//配置用户信息
kubectl config set-credentials cjzhao --client-certificate=./cjzhao.crt --client-key=./cjzhao.key
//配置上文(将用户和集群绑定)
kubectl config set-context cjzhao-context --cluster=yourcluster --namespace=cjns --user=cjzhao
配置完成后执行如下命令:
kubectl config use-context cjzhao-context
kubectl get pods
您将看到会报下面的错:
Error from server (Forbidden): pods is forbidden: User "cjzhao" cannot list resource "pods" in API group "" in the namespace "cjns"
创建用户角色来管理Deployments
- 使用以下内容创建一个role-deployment-manager.yaml文件。 在此yaml文件中,我们创建规则允许用户在Deployments,Pods和ReplicaSets对象(创建Deployment所必需)上执行多个操作,这些操作属于核心(在yaml文件中用“”表示),应用apps和扩展extensions API组:
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: cjns
name: deployment-manager
rules:
- apiGroups: \["", "extensions", "apps"\]
resources: \["deployments", "replicasets", "pods"\]
verbs: \["get", "list", "watch", "create", "update", "patch", "delete"\] \# You can also use \["\*"\]
使用kubectl create
命令在集群中创建Role:
kubectl create -f role-deployment-manager.yaml
将用户cjzhao和角色绑定
使用以下内容创建一个rolebinding-deployment-manager.yaml文件。 在此文件中,我们将角色绑定到cjns命名空间内的用户cjzhao:
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: deployment-manager-binding
namespace: cjns
subjects:
- kind: User
name: cjzhao
apiGroup: ""
roleRef:
kind: Role
name: deployment-manager
apiGroup: ""
通过运行kubectl create
命令部署RoleBinding:
kubectl create -f rolebinding-deployment-manager.yaml
测试RBAC规则
在新的机器上执行下面的命令创建一个deployment:
kubectl create deployment --image nginx myng
执行下面的命令查看创建结果:
kubectl get pods
可以看到正在运行的pod。
为了验证cjzhao的权限是否是限定在cjns命名空间,我们执行下面的命令:
kubectl get pods -n default
结果如下:
Error from server (Forbidden): pods is forbidden: User "cjzhao" cannot list resource "pods" in API group "" in the namespace "default"
说明相关的用户权限配置成功。
示例2: 通过Service Account从集群内的POD访问kubernetes Api
POD内的进程可以通过Service Account直接访问Kubernetes API接口,本示例我们将通过kubernetes java sdk调用api接口。
Java client SDK的相关代码见:https://github.com/kubernetes-client/java/
本示例我们将调用API返回当前namesapce的pod信息。
Java程序
本示例使用的是Spring boot,使用jib打包为容器镜像。请根据您的具体情况自由发挥,只要能把您的java程序打包容器镜像都可以。
程序代码如下:
package cn.devincloud.demo.k8sjavaclient.controller;
import java.io.IOException;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import io.kubernetes.client.ApiClient;
import io.kubernetes.client.ApiException;
import io.kubernetes.client.Configuration;
import io.kubernetes.client.apis.CoreV1Api;
import io.kubernetes.client.models.V1Pod;
import io.kubernetes.client.models.V1PodList;
import io.kubernetes.client.util.ClientBuilder;
@RestController
public class PodController {
@GetMapping("/pods")
private List<String> getPods() throws IOException, ApiException{
ApiClient client = ClientBuilder.cluster().build();
Configuration.setDefaultApiClient(client);
// the CoreV1Api loads default api-client from global configuration.
CoreV1Api api = new CoreV1Api();
// invokes the CoreV1Api client
V1PodList list = api.listNamespacedPod("cjns", null, null, null, null, null, null, null, null, null);
return list.getItems().stream().map(new Function<V1Pod,String>(){
@Override
public String apply(V1Pod t) {
return t.getMetadata().getName();
}
}).collect(Collectors.toList());
}
}
创建Service Account
在cjns命名空间创建一个Service Account: javaclient-svc-account
apiVersion: v1
kind: ServiceAccount
metadata:
name: javaclient-svc-account
namespace: cjns
绑定角色
我们的客户端需要读取cjns命名空间的pod,所有可以直接将Service Account:javaclient-svc-account
与示例1中的deployment-manager
角色绑定即可。
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: k8sjavaclient-rbac
namespace: cjns
subjects:
- kind: ServiceAccount
name: javaclient-svc-account
namespace: cjns
roleRef:
kind: Role
name: deployment-manager
apiGroup: rbac.authorization.k8s.io
部署应用测试
apiVersion: apps/v1
kind: Deployment
metadata:
name: k8sjavaclient
spec:
selector:
matchLabels:
app: k8sjavaclient
template:
metadata:
labels:
app: k8sjavaclient
spec:
serviceAccountName: javaclient-svc-account
containers:
- name: k8sjavaclient
image: kube.gwunion.cn/cj/k8sjavaclient
ports:
- containerPort: 8080
kubernetes默认为将Service Acccount: default
绑定到POD,本例中,我们在cjns命名空间内,default账号没有分配相关访问api权限,所以在POD的定义时,需要指定serviceAccountName
为我们上面创建的javaclient-svc-account
。
本文到此结束,喜欢的点赞。