為Kubernetes集群添加用戶認證

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

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