参考:Jenkins对接Kubernetes集群的RBAC
前提条件
集群需要开启RBAC。
场景一:基于namespace的权限控制
新建ServiceAccount和role,然后做rolebinding
# kubectl create ns dev # kubectl -n dev create sa dev # cat <<EOF > dev-user-role.yml kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: namespace: dev name: dev-user-pod rules: - apiGroups: ["*"] resources: ["deployments", "pods", "pods/log"] verbs: ["get", "watch", "list", "update", "create", "delete"] EOF # kubectl create -f dev-user-role.yml # kubectl create rolebinding dev-view-pod \ --role=dev-user-pod \ --serviceaccount=dev:dev \ --namespace=dev
生成指定ServiceAccount的kubeconfig文件
- 1.21以前版本的集群中,Pod中获取Token的形式是通过挂载ServiceAccount的Secret来获取Token,这种方式获得的Token是永久的。该方式在1.21及以上的版本中不再推荐使用,并且根据社区版本迭代策略,在1.25及以上版本的集群中,ServiceAccount将不会自动创建对应的Secret。
1.21及以上版本的集群中,直接使用TokenRequest API获得Token,并使用投射卷(Projected Volume)挂载到Pod中。使用这种方法获得的Token具有固定的生命周期,并且当挂载的Pod被删除时这些Token将自动失效。详情请参见Token安全性提升说明。
- 如果您在业务中需要一个永不过期的Token,您也可以选择手动管理ServiceAccount的Secret。尽管存在手动创建永久ServiceAccount Token的机制,但还是推荐使用TokenRequest的方式使用短期的Token,以提高安全性。
由于本案例使用的集群版本为v1.25,ServiceAccount不会自动创建对应的Secret。下面手动创建名为dev-secret的Secret,并与名为dev的ServiceAccount关联。
手动创建的Secret要与待关联的ServiceAccount处于同一命名空间,否则可能创建失败。
# kubectl apply -f - <<EOF apiVersion: v1 kind: Secret metadata: namespace: dev # 此处表示命名空间 name: dev-secret annotations: kubernetes.io/service-account.name: dev type: kubernetes.io/service-account-token EOF
检查dev-secret是否创建成功。若命名空间dev的Secrets中出现dev-secret,则说明创建成功。
# kubectl get secrets -n dev NAME TYPE DATA AGE default-secret kubernetes.io/dockerconfigjson 1 2d22h dev-secret kubernetes.io/service-account-token 3 4h14m paas.elb cfe/secure-opaque 1 2d22h
利用dev-secret生成kubeconfig文件。
# API_SERVER="https://172.22.132.51:6443" # CA_CERT=$(kubectl -n dev get secret dev-secret -o yaml | awk '/ca.crt:/{print $2}') # cat <<EOF > dev.conf apiVersion: v1 kind: Config clusters: - cluster: certificate-authority-data: $CA_CERT server: $API_SERVER name: cluster EOF # TOKEN=$(kubectl -n dev get secret dev-secret -o go-template='{{.data.token}}') # kubectl config set-credentials dev-user \ --token=`echo ${TOKEN} | base64 -d` \ --kubeconfig=dev.conf # kubectl config set-context default \ --cluster=cluster \ --user=dev-user \ --kubeconfig=dev.conf # kubectl config use-context default \ --kubeconfig=dev.conf
利用以下命令行进行验证。
# kubectl --kubeconfig=dev.conf get po Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:dev:dev" cannot list pods in the namespace "default" # kubectl -n dev --kubeconfig=dev.conf run nginx --image nginx --port 80 --restart=Never # kubectl -n dev --kubeconfig=dev.conf get po NAME READY STATUS RESTARTS AGE nginx 1/1 Running 0 39s
Jenkins中验证权限是否符合预期
- 添加有权限控制的kubeconfig到Jenkins系统中
- 启动Jenkins任务,部署到namespace default失败,部署到namespace dev成功。
场景二:基于具体资源的权限控制
- 生成SA和role及绑定:
# kubectl -n dev create sa sa-test0304 # cat <<EOF > test0304-role.yml kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: namespace: dev name: role-test0304 rules: - apiGroups: ["*"] resources: ["deployments"] resourceNames: ["tomcat03", "tomcat04"] verbs: ["get", "update", "patch"] EOF # kubectl create -f test0304-role.yml # kubectl create rolebinding test0304-bind \ --role=role-test0304 \ --serviceaccount=dev:sa-test0304\ --namespace=dev
- 生成kubeconfig文件:
- 1.21以前版本的集群中,Pod中获取Token的形式是通过挂载ServiceAccount的Secret来获取Token,这种方式获得的Token是永久的。该方式在1.21及以上的版本中不再推荐使用,并且根据社区版本迭代策略,在1.25及以上版本的集群中,ServiceAccount将不会自动创建对应的Secret。
1.21及以上版本的集群中,直接使用TokenRequest API获得Token,并使用投射卷(Projected Volume)挂载到Pod中。使用这种方法获得的Token具有固定的生命周期,并且当挂载的Pod被删除时这些Token将自动失效。详情请参见Token安全性提升说明。
- 如果您在业务中需要一个永不过期的Token,您也可以选择手动管理ServiceAccount的Secret。尽管存在手动创建永久ServiceAccount Token的机制,但还是推荐使用TokenRequest的方式使用短期的Token,以提高安全性。
由于本案例使用的集群版本为v1.25,ServiceAccount不会自动创建对应的Secret。下面手动创建名为test-secret的Secret,并与sa-test0304关联。
# kubectl apply -f - <<EOF apiVersion: v1 kind: Secret metadata: namespace: dev name: test-secret annotations: kubernetes.io/service-account.name: sa-test0304 type: kubernetes.io/service-account-token EOF
检查test-secret是否创建成功。若命名空间dev的Secrets中出现test-secret,则说明创建成功。
# kubectl get secrets -n dev NAME TYPE DATA AGE default-secret kubernetes.io/dockerconfigjson 1 2d22h dev-secret kubernetes.io/service-account-token 3 4h14m paas.elb cfe/secure-opaque 1 2d22h test-secret kubernetes.io/service-account-token 3 25m
利用test-secret生成kubeconfig文件。
# API_SERVER=" https://192.168.0.153:5443" # CA_CERT=$(kubectl -n dev get secret test-secret -o yaml | awk '/ca.crt:/{print $2}') # cat <<EOF > test0304.conf apiVersion: v1 kind: Config clusters: - cluster: certificate-authority-data: $CA_CERT server: $API_SERVER name: cluster EOF # TOKEN=$(kubectl -n dev get secret test-secret -o go-template='{{.data.token}}') # kubectl config set-credentials test0304-user \ --token=`echo ${TOKEN} | base64 -d` \ --kubeconfig=test0304.conf # kubectl config set-context default \ --cluster=cluster \ --user=test0304-user \ --kubeconfig=test0304.conf # kubectl config use-context default \ --kubeconfig=test0304.conf
- 1.21以前版本的集群中,Pod中获取Token的形式是通过挂载ServiceAccount的Secret来获取Token,这种方式获得的Token是永久的。该方式在1.21及以上的版本中不再推荐使用,并且根据社区版本迭代策略,在1.25及以上版本的集群中,ServiceAccount将不会自动创建对应的Secret。
- Jenkins中的运行效果符合预期。
Pipeline脚本,依次更新tomcat03/04/05的deployment。
try { kubernetesDeploy( kubeconfigId: "test0304", configs: "test03.yaml") println "hooray, success" } catch (e) { println "oh no! Deployment failed! " println e } echo "test04" try { kubernetesDeploy( kubeconfigId: "test0304", configs: "test04.yaml") println "hooray, success" } catch (e) { println "oh no! Deployment failed! " println e } echo "test05" try { kubernetesDeploy( kubeconfigId: "test0304", configs: "test05.yaml") println "hooray, success" } catch (e) { println "oh no! Deployment failed! " println e }
查看运行效果:
图1 test03
图2 test04