玩轉 K8s 許可權控制:RBAC + kubeconfig 搞定 kubectl 許可權管理那些事

胡說雲原生發表於2023-12-13

1. 先拋需求

當一個 K8s 叢集需要被多個租戶共享時,就涉及到了許可權問題,比如你是管理員,這時候你會面臨著“給每個使用者分配一個 Namespace”類似的需求。

更進一步,可能你需要限制特定使用者只能夠對叢集進行特定的操作,比如不能讓“張三”有機會執行 kubectl delete node <NODE_NAME> 這種 sao 命令。

在上一篇文章《透過 VS Code 優雅地編輯 Pod 內的程式碼(非 NodePort)》中我們講到怎樣在不暴露一堆 NodePort 的前提下,透過 VS Code 更新 Pod 內的程式碼。VS Code 裡去 Attach Pod 其實也是用的本地 kubeconfig 來和 apiserver 通訊,進而操作到 Pod。換言之,要實現“多租戶透過 VS Code 連線自己的 Pod”這個需求,也涉及到給不同租戶建立合適的“最小許可權 kubeconfig”。行,今天就來解決這個問題。

2. RBAC 配置

整體就兩步,先倒騰 RBAC,然後倒騰 kubeconfig。我們先來看 RBAC吧。

2.1. K8s 裡的 RBAC 機制介紹

先複習下 K8s 裡的 RBAC 機制。

(這時候需要用到 GPT 了。)

  • :Hello ChatGPT,用中文總結下 K8s 裡的 RBAC 是個啥。

  • ChatGPT:

在 Kubernetes 中,RBAC 是一種強大的訪問控制機制,用於管理對叢集資源的訪問許可權。RBAC 可以幫助管理員精確地控制使用者、ServiceAccount 或其他實體對 Kubernetes API 中資源的操作許可權。RBAC 基於角色的授權模型使得管理員可以定義角色和角色繫結,從而實現對不同使用者或實體的訪問許可權控制。

RBAC 由四個基本概念組成:

  • 角色(Role):角色定義了一組操作許可權,例如對某個名稱空間下資源的讀取、建立或刪除等操作。
  • 角色繫結(RoleBinding):角色繫結將特定的角色授予 User、Group 或者 ServiceAccount,從而賦予它們相應的許可權。
  • 叢集角色(ClusterRole):類似於角色,但作用範圍更廣,可以授權對整個叢集中資源的操作許可權。
  • 叢集角色繫結(ClusterRoleBinding):將叢集角色繫結給 User、Group 或者 ServiceAccount,授予它們在整個叢集範圍內的許可權。

透過 RBAC,管理員可以根據需求精確控制不同使用者或實體在叢集中的許可權範圍,避免了不必要的許可權洩露或誤操作,提高了叢集的安全性和管理靈活性。

行,就總結到這裡,接著我們要實操了。

2.2 建立 ServiceAccount、Role、RoleBinding 和 Secret

  1. ServiceAccount:以使用者 user1 為例,來一個 user1-account
apiVersion: v1
kind: ServiceAccount
metadata:
  name: user1-account
  namespace: default
  1. Role:繼續來一個 user1-role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: user1-role
  namespace: default
rules:
- apiGroups: [""]
  resources: ["pods", "pods/exec"]
  verbs: ["get", "list", "watch", "create", "delete", "update", "patch"]

這裡就可以在 rules 下精細地控制這個角色所能夠訪問的資源、執行的操作了。如果需要叢集維度資源的控制,比如 Node,那就得用到 ClusterRole 了,玩法類似,不贅述。

  1. RoleBinding:把使用者和角色綁起來
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: user1-access-default-namespace
  namespace: default
subjects:
- kind: ServiceAccount
  name: user1-account
  namespace: default
roleRef:
  kind: Role
  name: user1-role
  apiGroup: rbac.authorization.k8s.io
  1. Secret:在 K8s 1.24 版本之後,ServiceAccount 對應的 Secret 就不會自動建立了。哎,手動搞吧
apiVersion: v1
kind: Secret
metadata:
  name: user1-account-secret
  annotations:
    kubernetes.io/service-account.name: "user1-account"
type: kubernetes.io/service-account-token

這個 Secret 建立出來之後,K8s 會自動將 ServiceAccount 對應的 token 寫進這個 Secret。

一頓 apply 操作之後,RBAC 相關的幾個資源就都有了。前幾個沒啥好說的,Secret 的關鍵欄位貼一下,大家感受下 K8s 在背地裡偷偷幹了些啥:

  • kgsec user1-account-secret -o yaml
apiVersion: v1
data:
  ca.crt: LS0t……==
  namespace: ZGVmYXVsdA==
  token: ZXlKa……=
kind: Secret
metadata:
  annotations:
    kubernetes.io/service-account.name: user1-account
  name: user1-account-secret
  namespace: default
type: kubernetes.io/service-account-token

data 部分,發現了嗎,ca.crttoken 資訊被填進去了。這兩段配置在後面要用到。

3. 配置 kubeconfig 檔案

user1 的許可權配置已經 OK 了,下一步就是將 token 搞到 kubeconfig 裡。

3.1 kubeconfig 檔案介紹

呵呵,老規矩,我這麼懶的人,怎麼可能自己總結。

  • ChatGPT:

kubeconfig 是 Kubernetes 的一個配置檔案,它包含了訪問 Kubernetes 叢集所需的所有資訊。這些資訊包括叢集的地址、使用者證書、使用者名稱和名稱空間等。kubeconfig 檔案使得使用者和 CI/CD 工具可以方便地與 Kubernetes 叢集進行互動。

kubeconfig 檔案通常位於使用者的主目錄下的 .kube 目錄中,檔名為 config。然而,使用者也可以透過設定 KUBECONFIG 環境變數來指定其他位置的 kubeconfig 檔案。

kubeconfig 檔案主要由以下三部分組成:

  • 叢集(clusters):定義了要連線的 Kubernetes 叢集的資訊,包括叢集的名稱、伺服器的地址和 CA 證書。

  • 使用者(users):定義了使用者的認證資訊,包括使用者的名稱、客戶端證書和金鑰。

  • 上下文(contexts):定義了使用者和叢集之間的關係。一個上下文包含了一個使用者和一個叢集,以及使用者在該叢集中的預設名稱空間。

透過在 kubeconfig 檔案中定義不同的上下文,使用者可以輕鬆地在不同的 Kubernetes 叢集和名稱空間之間切換。

稍顯稚嫩,不過將就吧。關於 kubeconfig 是個啥的資料太多了,我就不過多囉嗦了。

貼一個 minikube 預設建立的 kubeconfig 檔案:

apiVersion: v1
clusters:
- cluster:
    certificate-authority: /Users/danielhu/.minikube/ca.crt
    extensions:
    - extension:
        last-update: Wed, 13 Dec 2023 15:28:46 CST
        provider: minikube.sigs.k8s.io
        version: v1.32.0
      name: cluster_info
    server: https://127.0.0.1:60719
  name: minikube
contexts:
- context:
    cluster: minikube
    extensions:
    - extension:
        last-update: Wed, 13 Dec 2023 15:28:46 CST
        provider: minikube.sigs.k8s.io
        version: v1.32.0
      name: context_info
    namespace: default
    user: minikube
  name: minikube
current-context: minikube
kind: Config
preferences: {}
users:
- name: minikube
  user:
    client-certificate: /Users/danielhu/.minikube/profiles/minikube/client.crt
    client-key: /Users/danielhu/.minikube/profiles/minikube/client.key

總之就是 clusters 裡定義一堆可用的叢集資訊,users 裡定義一堆使用者資訊,然後在 contexts 裡將 user 和 cluster 關聯起來;最後透過切換 context 就可以實現切換“使用者/叢集”了。

3.2 具體的 kubeconfig 配置

前面建立的 Secret 裡有一個 token,將其複製出來備用。(這裡要注意,別拿 base64 轉碼後的結果。kubectl get -o yaml 拿到的是 base64 編碼的;kubectl describe 拿到的是原始的,你可以直接拿原始的,也可以拿編碼後的自己 echo "xxx" | base64 -d 解碼一下。

此外 Secret 裡有一個 ca.crt,這個 ca 的內容是叢集維度統一的,你在其他地方複製也行,不過這裡有,順手拿一個也不打緊。這裡需要是 base64 編碼後的內容,注意這個細節。

然後準備這樣一個 kubeconfig 檔案:

apiVersion: v1
kind: Config
clusters:
- name: minikube1
  cluster:
    server: https://127.0.0.1:60719
    certificate-authority-data: <ca.crt, base64>

users:
- name: user1-account
  user:
    token: <token>

contexts:
- name: user1-context
  context:
    cluster: minikube1
    namespace: default
    user: user1-account

注意幾個細節:

  1. clusters 下面的 name 記得不要和你係統內預設 config 中的 clusters 重名;
  2. server 地址可以抄你的預設 config 裡的配置;
  3. ca 配置其實也是一樣的,你的系統內有,複用配置也行;我這裡選擇貼一個 base64 版本的內容,為了不引入“外部檔案”,方便分發;
  4. token 填寫前面準備的 token,非 base64。

3.3 kubeconfig 切換測試

最簡單粗暴的辦法,你可以直接備份 $HOME/.kube/config,然後將這個新檔案替換進去,這樣就能測試新的 kubeconfig 是不是正常工作了。

或者,你可以配置上 KUBECONFIG 環境變數,將新的 kubeconfig 儲存路徑追加進去。比如 mac 可以這樣:

export KUBECONFIG=/Users/danielhu/.kube/config:/Users/danielhu/Work/test/kubeconfig

Windows 系統得用分號(;)。

這時候你再執行 kubectl config view 就可以看到一個 merge 之後的 kubeconfig 配置,也就是新的舊的 kubeconfig 都在一起了。

下一步,我推薦你用 kubectx來切換 context

  • kubectx
minikube
user1-context
  • kubectx user1-context

OK,這時候就能切換到新的 context 了。接著可以試下是不是隻有 pods 能被操作到:

4. 總結

打完收工。沒啥好總結的。See you next day.

相關文章