簡介
本文將介紹Kubernetes基于角色的訪問控制(RBAC)API對象,以及兩個常見的用例(創(chuàng)建具有受限訪問權(quán)限的用戶、POD內(nèi)通過service account訪問api)。在本文的最后,您應(yīng)該具有足夠的知識來在集群中使用RBAC策略。
從Kubernetes 1.6版本起,系統(tǒng)默認啟用RBAC策略。 RBAC策略對于正確管理群集至關(guān)重要,因為它們使您可以根據(jù)用戶及其在組織中的角色來指定允許的操作類型。包括:
- 通過僅向管理員用戶授予特權(quán)操作(例如訪問機密)來保護集群。
在集群中強制用戶認證。 - 將資源創(chuàng)建(例如pod,持久卷,部署)限制為特定的名稱空間。您還可以使用配額來確保資源使用受到限制并受到控制。
- 讓用戶僅在其授權(quán)的名稱空間中查看資源。這使您可以隔離組織內(nèi)的資源(例如,部門之間)。
- 由于默認啟用了RBAC,因此在配置網(wǎng)絡(luò)(例如flanneld)或使Helm時,您可能會看到類似這樣的錯誤:
the server does not allow access to the requested resource
本文將向您展示如何使用RBAC,以便您可以正確處理此類問題。
準備工作
為了充分的了解本文,建議您有一套完整的Kubernetes環(huán)境,并能按我們的步驟完成整個過程,環(huán)境要求如下:
- Kubernetes 1.6以上版本,1.6前的版本,需要手動啟用RBAC,如果您是在本機用minikube安裝kubernetes,命令行如下:
minikube start --extra-config=apiserver.Authorization.Mode=RBAC
- 安裝kubectl命令行工具。
- 安裝了OpenSSL。
RBAC API 對象
Kubernetes的一項基本功能是其所有資源都是模型化的API對象,該對象允許進行CRUD(創(chuàng)建,讀取,更新,刪除)操作。 資源包括:
- Pods.
- PersistentVolumes.
- ConfigMaps.
- Deployments.
- Nodes.
- Secrets.
- Namespaces.
這些資源上可能的操作示例如下:
- create
- get
- delete
- list
- update
- edit
- watch
- exec
在更高級別上,資源與API Group(API組)相關(guān)聯(lián)(例如,Pod屬于核心API group,而Deployment屬于apps API group)。 有關(guān)所有可用資源,操作和API組的更多信息,請查看官方Kubernetes API參考。
為了在Kubernetes中管理RBAC,除了資源和操作外,我們還需要理解以下概念:
- Rules:規(guī)則是可以對屬于不同API組的一組資源執(zhí)行的一組操作。
- Roles 和 ClusterRoles: 兩者都是規(guī)則。 Role和ClusterRole之間的區(qū)別在于范圍:在Role中,規(guī)則只適用于單個命名空間(namespace),而ClusterRole則適用于整個群集,因此Role適用于多個命名空間。 ClusterRoles還可為集群范圍內(nèi)的資源(例如節(jié)點)定義規(guī)則。 Role和ClusterRoles都映射為集群內(nèi)的API資源。
- Subjects:這些對應(yīng)于嘗試在集群中進行操作的實體。共有三種類型的主題:
- User Accounts(用戶帳戶):這些是全局帳戶,用于集群外部的用戶或程序。 Kubernetes集群中沒有關(guān)聯(lián)的資源API對象。
- Service Accounts(服務(wù)帳戶):此帳戶是和命名空間相關(guān)的,適用于在Pod內(nèi)部運行的進程,這些進程需要調(diào)用API時進行身份驗證。
- Groups(組):用于引用多個帳戶,默認情況下會創(chuàng)建一些組,例如cluster-admin(在后面的部分中進行說明)。
- RoleBindings 和 ClusterRoleBindings: 就像名稱的意思,這些將Subjects綁定到角色(即給定用戶可以執(zhí)行的操作)。RoleBinding將使規(guī)則在命名空間內(nèi)有效,而ClusterRoleBinding將使規(guī)則在所有命名空間內(nèi)有效。
您可以在Kubernetes官方文檔中找到每個API元素的示例。
示例1: 創(chuàng)建一個新的用戶,從遠程訪問kubernetes集群
在此示例中,我們將為“開發(fā)組(development)”的"cjzhao"用戶創(chuàng)建一個獨享的命名空間(cjns),并從遠程服務(wù)器訪問集群,主要包括以下對象:
- Username: cjzhao
- Group: development
- Namespace: cjns
我們將添加必要的RBAC策略,以便用戶cjzhao僅在cjns命名空間內(nèi)即可完全管理deployment(即使用kubectl run命令)。 最后,我們將測試這些策略以確保它們按預期工作。
創(chuàng)建namespace
執(zhí)行kubectl create命令創(chuàng)建命名空間(以admin用戶身份):
kubectl create namespace cjns
創(chuàng)建用戶憑證(User Credentials)
Kubernetes沒有用于用戶帳戶的API。 這里我們使用OpenSSL證書(更多的認證方式請參見Kubernetes官方文檔)來管理身份驗證,具體步驟如下:
在kubernetes管控節(jié)點(或管理員機器)上執(zhí)行下面操作
- 為您的用戶創(chuàng)建一個私鑰。在此示例中,我們將文件命名為cjzhao.key:
openssl genrsa -out cjzhao.key 2048
- 使用您剛創(chuàng)建的私鑰(cjzhao.key)創(chuàng)建證書簽名請求cjzhao.csr。 確保在-subj部分中指定用戶名和組(CN表示用戶名,O表示用戶組)。 如前所述,我們將使用cjzhao作為名稱,使用development作為用戶組:
openssl req -new -key cjzhao.key -out cjzhao.csr -subj "/CN=cjzhao/O=development"
找到您的Kubernetes群集證書頒發(fā)機構(gòu)(CA)文件。 這將負責批準請求并生成訪問群集API所需的證書。 它的位置通常在
/etc/kubernetes/pki /目錄下。 對于Minikube,它在?/.minikube/。 檢查目錄下是否存在ca.crt和ca.key文件,并將它們拷貝到當前目錄。通過批準您之前提出的證書簽名請求cjzhao.csr來生成最終的證書cjzhao.crt,設(shè)置證書有效期為500天,執(zhí)行如下命令:
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幾個文件打包拷貝到新的機器。
在新的機器上執(zhí)行下面操作
- 在安裝了kubectl命令行工具的新的機器上解壓上一步中打包的文件,執(zhí)行如下命令,配置kubernetes集群、用戶憑據(jù)等信息:
//配置集群
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
配置完成后執(zhí)行如下命令:
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"
創(chuàng)建用戶角色來管理Deployments
- 使用以下內(nèi)容創(chuàng)建一個role-deployment-manager.yaml文件。 在此yaml文件中,我們創(chuàng)建規(guī)則允許用戶在Deployments,Pods和ReplicaSets對象(創(chuàng)建Deployment所必需)上執(zhí)行多個操作,這些操作屬于核心(在yaml文件中用“”表示),應(yīng)用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命令在集群中創(chuàng)建Role:
kubectl create -f role-deployment-manager.yaml
將用戶cjzhao和角色綁定
使用以下內(nèi)容創(chuàng)建一個rolebinding-deployment-manager.yaml文件。 在此文件中,我們將角色綁定到cjns命名空間內(nèi)的用戶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規(guī)則
在新的機器上執(zhí)行下面的命令創(chuàng)建一個deployment:
kubectl create deployment --image nginx myng
執(zhí)行下面的命令查看創(chuàng)建結(jié)果:
kubectl get pods
可以看到正在運行的pod。
為了驗證cjzhao的權(quán)限是否是限定在cjns命名空間,我們執(zhí)行下面的命令:
kubectl get pods -n default
結(jié)果如下:
Error from server (Forbidden): pods is forbidden: User "cjzhao" cannot list resource "pods" in API group "" in the namespace "default"
說明相關(guān)的用戶權(quán)限配置成功。
示例2: 通過Service Account從集群內(nèi)的POD訪問kubernetes Api
POD內(nèi)的進程可以通過Service Account直接訪問Kubernetes API接口,本示例我們將通過kubernetes java sdk調(diào)用api接口。
Java client SDK的相關(guān)代碼見:https://github.com/kubernetes-client/java/
本示例我們將調(diào)用API返回當前namesapce的pod信息。
Java程序
本示例使用的是Spring boot,使用jib打包為容器鏡像。請根據(jù)您的具體情況自由發(fā)揮,只要能把您的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());
}
}
創(chuàng)建Service Account
在cjns命名空間創(chuàng)建一個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
部署應(yīng)用測試
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命名空間內(nèi),default賬號沒有分配相關(guān)訪問api權(quán)限,所以在POD的定義時,需要指定serviceAccountName為我們上面創(chuàng)建的javaclient-svc-account。
本文到此結(jié)束,喜歡的點贊。