為Kubernetes叢集新增使用者認證

福祿網路研發團隊發表於2021-10-25

Kubernetes中的使用者

K8S中有兩種使用者(User)——服務賬號(ServiceAccount)和普通意義上的使用者(User)
ServiceAccount是由K8S管理的,而User通常是在外部管理,K8S不儲存使用者列表——也就是說,新增/編輯/刪除使用者都是在外部進行,無需與K8S API互動,雖然K8S並不管理使用者,但是在K8S接收API請求時,是可以認知到發出請求的使用者的,實際上,所有對K8S的API請求都需要繫結身份資訊(User或者ServiceAccount),這意味著,可以為User配置K8S叢集中的請求許可權

有什麼區別?

最主要的區別上面已經說過了,即ServiceAccount是K8S內部資源,而User是獨立於K8S之外的。從它們的本質可以看出:

  • User通常是人來使用,而ServiceAccount是某個服務/資源/程式使用的

  • User獨立在K8S之外,也就是說User是可以作用於全域性的,在任何名稱空間都可被認知,並且需要在全域性唯一
    而ServiceAccount作為K8S內部的某種資源,是存在於某個名稱空間之中的,在不同名稱空間中的同名ServiceAccount被認為是不同的資源

  • K8S不會管理User,所以User的建立/編輯/登出等,需要依賴外部的管理機制,K8S所能認知的只有一個使用者名稱
    ServiceAccount是由K8S管理的,建立等操作,都通過K8S完成

這裡說的新增使用者指的是普通意義上的使用者,即存在於叢集外的使用者,為k8s的使用者。
實際上叫做新增使用者也不準確,使用者早已存在,這裡所做的只是使K8S能夠試別此使用者,並且控制此使用者在叢集內的許可權

使用者驗證

儘管K8S認知使用者靠的只是使用者的名字,但是隻需要一個名字就能請求K8S的API顯然是不合理的,所以依然需要驗證此使用者的身份
在K8S中,主要有以下幾種驗證方式:

  • X509客戶端證書
    客戶端證書驗證通過為API Server指定--client-ca-file=xxx選項啟用,API Server通過此ca檔案來驗證API請求攜帶的客戶端證書的有效性,一旦驗證成功,API Server就會將客戶端證書Subject裡的CN屬性作為此次請求的使用者名稱

  • 靜態token檔案
    通過指定--token-auth-file=SOMEFILE 選項來啟用bearer token驗證方式,引用的檔案是一個包含了 token,使用者名稱,使用者ID 的csv檔案
    請求時,帶上Authorization: Bearer 31ada4fd-adec-460c-809a-9e56ceb75269頭資訊即可通過bearer token驗證

  • 靜態密碼檔案
    通過指定--basic-auth-file=SOMEFILE選項啟用密碼驗證,類似的,引用的檔案時一個包含 密碼,使用者名稱,使用者ID 的csv檔案
    請求時需要將Authorization頭設定為Basic BASE64ENCODED(USER:PASSWORD)

這裡只介紹客戶端驗證

為使用者生成證書

假設我們操作的使用者名稱為tom

  1. 首先需要為此使用者建立一個私鑰
    openssl genrsa -out tom.key 2048

  2. 接著用此私鑰建立一個csr(證書籤名請求)檔案,其中我們需要在subject裡帶上使用者資訊(CN為使用者名稱,O為使用者組)
    openssl req -new -key tom.key -out tom.csr -subj "/CN=tom/O=MGM"
    其中/O引數可以出現多次,即可以有多個使用者組

  3. 找到K8S叢集(API Server)的CA證書檔案,其位置取決於安裝叢集的方式,通常會在/etc/kubernetes/pki/路徑下,會有兩個檔案,一個是CA證書(ca.crt),一個是CA私鑰(ca.key)

  4. 通過叢集的CA證書和之前建立的csr檔案,來為使用者頒發證書
    openssl x509 -req -in tom.csr -CA path/to/ca.crt -CAkey path/to/ca.key -CAcreateserial -out tom.crt -days 365
    -CA和-CAkey引數需要指定叢集CA證書所在位置,-days引數指定此證書的過期時間,這裡為365天

  5. 最後將證書(tom.crt)和私鑰(tom.key)儲存起來,這兩個檔案將被用來驗證API請求

為使用者新增基於角色的訪問控制(RBAC)

角色(Role)

在RBAC中,角色有兩種——普通角色(Role)和叢集角色(ClusterRole),ClusterRole是特殊的Role,相對於Role來說:

  • Role屬於某個名稱空間,而ClusterRole屬於整個叢集,其中包括所有的名稱空間

  • ClusterRole能夠授予叢集範圍的許可權,比如node資源的管理,比如非資源型別的介面請求(如"/healthz"),比如可以請求全名稱空間的資源(通過指定 --all-namespaces)

為使用者新增角色

首先創造一個角色

kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  namespace: a-1
  name: admin
rules:
- apiGroups: [""]
  resources: ["*"]
  verbs: ["*"]

這是在a-1名稱空間內建立了一個admin管理員角色,這裡只是用admin角色舉例,實際上如果只是為了授予使用者某名稱空間管理員的許可權的話,是不需要新建一個角色的,K8S已經內建了一個名為admin的ClusterRole

將角色和使用者繫結

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: admin-binding
  namespace: a-1
subjects:
- kind: User
  name: tom
  apiGroup: ""
roleRef:
  kind: Role
  name: admin
  apiGroup: ""

如yaml中所示,RoleBinding資源建立了一個 Role-User 之間的關係,roleRef節點指定此RoleBinding所引用的角色,subjects節點指定了此RoleBinding的受體,可以是User,也可以是前面說過的ServiceAccount,在這裡只包含了名為 tom 的使用者

新增名稱空間管理員的另一種方式

前面說過,K8S內建了一個名為admin的ClusterRole,所以實際上我們無需建立一個admin Role,直接對叢集預設的admin ClusterRole新增RoleBinding就可以了

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: admin-binding
  namespace: a-1
subjects:
- kind: User
  name: tom
  apiGroup: ""
roleRef:
  kind: ClusterRole
  name: admin
  apiGroup: ""

這裡雖然引用的是作為ClusterRole的admin角色,但是其許可權被限制在RoleBinding admin-binding所處的名稱空間,即a-1內
如果想要新增全名稱空間或者說全叢集的管理員,可以使用cluster-admin角色

到此為止,我們已經:

  • 為tom使用者提供了基於X509證書的驗證
  • 為a-1名稱空間創造了一個admin角色
  • 為使用者tom和角色admin建立了繫結關係

為kubectl配置使用者

tom已經是管理員了,現在我們想要通過kubectl以tom的身份來操作叢集,需要將tom的認證資訊新增進kubectl的配置,即~/.kube/config中

這裡假設config中已經配置好了k8s叢集

  1. 通過命令kubectl config set-credentials tom --client-certificate=path/to/tom.crt --client-key=path/to/tom.key將使用者tom的驗證資訊新增進kubectl的配置
    此命令會在配置中新增一個名為tom的使用者

  2. kubectl config set-context tom@aliyun --cluster=aliyun --namespace=a-1 --user=tom
    此命令新增了一個context配置——設定使用aliyun叢集,預設使用a-1名稱空間,使用使用者tom進行驗證

  3. 在命令中帶上 kubectl --context=tom@aliyun ... 引數即可指定kubectl使用之前新增的名為tom@aliyun的context操作叢集
    也可以通過命令 kubectl config use-context tom@aliyun 來設定當前使用的context

Tips: 將認證資訊嵌入kubectl的配置中

通過kubectl config set-credentials命令新增的使用者,其預設使用的是引用證書檔案路徑的方式,表現在~/.kube/config中,就是:

users:
- name: tom
  user:
    client-certificate: path/to/tom.crt
    client-key: path/to/tom.key

如果覺得這樣總是帶著兩個證書檔案不方便的話,可以將證書內容直接放到config檔案裡

  1. 將tom.crt/tom.key的內容用BASE64編碼
    cat tom.crt | base64 --wrap=0
    cat tom.key | base64 --wrap=0

  2. 將獲取的編碼後的文字複製進config檔案中

users:
- name: ich
  user:
    client-certificate-data: ...
    client-key-data: ...

這樣就不再需要證書和私鑰檔案了,當然這兩個檔案還是儲存起來比較好

與企業自有使用者系統整合

通常來說,對於Kubernetes的操作是由平臺或應用的運維人員來完成,多數情況下,可以直接為相應人員手動或者自動地建立證書或service account,不需要與企業人員系統整合。
如果確實有與企業人員系統整合的需求的話,可以考慮:

  1. 實現自動化的證書籤發並繫結到企業人員系統中
  2. 使用OIDC認證外掛,尤其是在企業人員系統已經支援OIDC的情況下,比如企業如果使用Azure ActiveDirectory或者Google Identity作為企業的Identity Provider時,這些Identity Provider均已實現了OIDC
  3. 使用Webhook Token Authentication

參考資料:
Authenticating - Kubernetes Docs
Configure RBAC in your Kubernetes Cluster
Using RBAC Authorization - Kubernetes Docs
Kubectl Reference Docs#config
Kubernetes auth: X509 client certificates

福祿·研發中心 龍舌蘭日落

相關文章