更新时间:2024-05-31 GMT+08:00

参考: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,以提高安全性。
$ SECRET=$(kubectl -n dev get sa dev -o go-template='{{range .secrets}}{{.name}}{{end}}')
$ API_SERVER="https://172.22.132.51:6443"
$ CA_CERT=$(kubectl -n dev get secret ${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 ${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中验证权限是否符合预期

  1. 添加有权限控制的kubeconfig到Jenkins系统中

  2. 启动Jenkins任务,部署到namespace default失败,部署到namespace dev成功。

场景二:基于具体资源的权限控制

  1. 生成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

  2. 生成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,以提高安全性。
     SECRET=$(kubectl -n dev get sa sa-test0304 -o go-template='{{range .secrets}}{{.name}}{{end}}')
     API_SERVER=" https://192.168.0.153:5443"
     CA_CERT=$(kubectl -n dev get secret ${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 ${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

  3. 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