Kubernetes-身份認證

1Kubernetes中的用戶

所有的系統都存在訪問和使用其的用戶,Kubernetes也一樣,在Kubernetes集羣中有存在兩類用戶:

  • service accounts:由Kubernetes進行管理的特殊用戶
  • 普通用戶:普通用戶是由外部應用進行管理的用戶。

對於普通用戶,Kubernetes管理員只負責爲其分配私鑰。普通用戶可能來自於Keystone或google中,或者甚至是存儲在文件中的用戶名和密碼列表。在Kubernetes中,沒有表達普通用戶的對象,因此,也就不能通過API將普通用戶添加到集羣中。

而Service Account是由Kubernetes API管理的用戶,它們被綁定到特定的命名空間中,並由API服務器自動創建或通過API調用手動創建。Service Account與存儲在Secrets的一組證書相關聯,這些憑據被掛載到pod中,以允許集羣中進程與Kubernetes API進行通信。

API請求要麼來自於普通用戶或Service Account,或來自於匿名請求。這就意味着集羣內外部的所有進程(從來自於用戶使用kubectl輸入的請求,或來自於Nodes中kubelet的請求,或來自控制板的成員的請求)都需要進行認證才能與API server進行交互。。

2、認證策略(Authentication strategies

Kubernetes的用戶可以使用客戶端證書、Bearer Token、身份驗證代理或HTTP基本認證,通過身份驗證插件來驗證API請求。比如,當HTTP請求到達API server,插件嘗試將以下的屬性與請求進行關聯:

  • Username:用戶名,標識最終用戶的字符串。通常,Username的值可能像“kube-admin”或者“[email protected]”。
  • UID:用戶的唯一標識標識。
  • Groups:用戶組組名。
  • Extra fields:記錄用戶其他信息的屬性。

上述所有值對於認證系統都是不透明的,只有在被授權者解釋時纔有意義。

可以同時啓用上面的多個認證方法。通常至少使用兩種:

  • service accounts使用serive account tokens。
  • 用戶認證至少使用另外一種方法。

當同時啓用多個認證模塊時,根據短路徑評估,使用第一個認證模塊成功地認證了請求。API server不保證接下來的認證是通過的。

system:authenticated 組被包括在所有已認證用戶的組列表中。

可以通過使用authenticating.proxy或者authenticaiton webhook與其他的認證協議進行集成(LDAP, SAML, Kerberos, alternate x509 schemes, etc)

2.1 X509客戶端證書

客戶端證書身份認證模式通過在API Server中設置–client-ca-file = SOMEFILE選項來啓用。所引用的文件中必須包含一個或多個證書管理機構,用以驗證提交給API服務器的客戶端證書。如果客戶端提交的證書通過驗證,主體的通用名稱將被用作請求的用戶名。從Kubernetes的1.4版本起,客戶端證書也可以通過證書的組織(organization)區域指定用戶的組成員資格。客戶端證書認證叫作TLS雙向認證,也就是服務器客戶端互相驗證證書的正確性,在都正確的情況下協調通信加密方案。CA_CERTIFICATE_FILE肯定包括一個或者多個認證中心,可以被用來驗證呈現給api-server的客戶端證書。客戶端證書的/CN將作爲用戶名。

例如,使用openssl命令行工具生成證書籤名請求:

$ openssl req -new -key jbeda.pem -out jbeda-csr.pem -subj ”/CN=jbeda/O=app1/O=app2

這將會創建一個用戶名爲“jbeda”,所屬組爲”app1”和“app2”的簽名請求。 使用客戶端證書身份驗證時,可以通過easyrsa、OpenSSL或cfssl手動生成證書,x509證書一般會用到三類文件,key(私用密鑰),csr(證書請求文件,用於申請證書),crt(CA認證後的證書文件)。

數字證書則是由證書認證機構(CA)對證書申請者真實身份驗證之後,用CA的根證書對申請人的一些基本信息以及申請人的公鑰進行簽名(相當於加蓋發證書機構的公章)後形成的一個數字文件。數字證書包含證書中所標識的實體的公鑰(就是說你的證書裏有你的公鑰),由於證書將公鑰與特定的個人匹配,並且該證書的真實性由頒發機構保證(就是說可以讓大家相信你的證書是真的),因此,數字證書爲如何找到用戶的公鑰並知道它是否有效這一問題提供瞭解決方案。

此處以Openssl爲例進行闡述,通過openssl手動創建。首先,生成一個CA根證書;然後,用CA根證書來簽發用戶證書。 用戶的證書過程是:先生成一個私鑰;然後,用私鑰生成證書請求(證書請求裏應含有公鑰信息);最後,利用CA根證書來簽發用戶證書。通過Openssl生成證書的過程如下:

2.1.1 生成CA根證書

1)用2048位生成一個ca私鑰:

$ openssl genrsa -out ca.key 2048

2)根據ca私鑰生成證書ca根證書(用天設置證書的有效時間):

$ openssl req -x509 -new -nodes -key ca.key -subj "/CN=${MASTER_IP}" -days 10000 -out ca.crt

2.1.2 生成服務器端用戶證書

1)使用2048位生成服務器端用戶私鑰:

$ openssl genrsa -out server.key 2048

2)爲證書籤名請求(CSR)創建一個配置文件(例如:csr.conf)。在將真實的值保持到文件之前,一定要用要尖括號把這些值標起來(例如< master_ip >)。注意,MASTER_CLUSTER_IP的值是服務集羣IP服務器如前所描述的服務羣集IP。

[ req ]default_bits = 2048 prompt = no default_md = sha256 req_extensions = req_ext distinguished_name = dn
[ dn ]C = <country> ST = <state> L = <city> O = <organization> OU = <organization unit> CN = <MASTER_IP> [ req_ext ]subjectAltName = @alt_names [ alt_names ]DNS.1 = kubernetes DNS.2 = kubernetes.default DNS.3 = kubernetes.default.svc 
DNS.4 = kubernetes.default.svc.cluster DNS.5 = kubernetes.default.svc.cluster.local IP.1 = <MASTER_IP> 
IP.2 = <MASTER_CLUSTER_IP> [ v3_ext ]authorityKeyIdentifier=keyid,issuer:alwaysbasicConstraints=CA:FALSEkeyUsage=keyEncipherment,
dataEnciphermentextendedKeyUsage=serverAuth,clientAuthsubjectAltName=@alt_names

3)基於配置文件和私鑰生成證書籤名請求:

$ openssl req -new -key server.key -out server.csr -config csr.conf

4)使用ca根證書,ca私鑰和服務器端用戶證書請求創建服務器用戶證書:

$ openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \-CAcreateserial -out server.crt -days 10000 \-extensions v3_ext -extfile csr.conf

5)查看服務器端用戶證書:

$ openssl x509 -noout -text -in ./server.crt

最後,將相同的參數添加到API Server的啓動參數。

6)生成pem格式證書:

有時可能需要用到pem格式的證書,可以用以下方式合併證書文件(crt)和私鑰文件(key)來生成

$cat server.crt server.key > server.pem

2.2 Service Account令牌

在有些情況下,希望在 Pod 內部訪問 API server,獲取集羣的信息,以及對集羣進行改動。針對這種情況,kubernetes 提供了一種特殊的認證方式:Service Account令牌。 Service Account 是限定命名空間的。在創建命名空間的時候,kubernetes 會爲每一個命名空間創建一個默認的 Service Account;這個默認的 Service Account 只能訪問該命名空間內的資源。Service Account 和 Pod、Service、Deployment 一樣是 Kubernetes 集羣中的一種資源,用戶也可以通過手動的方式創建Service Account。

Service Account是一個自動啓用的認證器,它使用被簽名的Bearer Token對請求進行認證,該插件接受兩個可選參數:

  • – -service-account-key-file: 一個包含用於對Bearer Token進行簽名的PEM編碼密鑰文件。如果不指定,將使用API服務器的TLS私鑰。
  • – -service-account-lookup :如果啓用,從API中刪除的tokens將會被廢除。

Service Account通常由API服務器自動創建,並通過ServiceAccount Admission Controller與集羣中的Pods進行關聯。 Bearer tokens被掛載到pod中衆所周知的位置,從使集羣中的進程可以與API服務器進行通信。Service Account可以使用PodSpec的serviceAccountName字段來關聯到Pod中。

注意:通常省略serviceAccountName字段,因爲一般是自動完成的。

apiVersion: apps/v1 # this apiVersion is relevant as of Kubernetes 1.9 kind: Deployment metadata:  name: nginx-deployment  namespace: default spec:  replicas: 3  template:  metadata:  # ...  spec:  serviceAccountName: bob-the-bot  containers:  - name: nginx  image: nginx:1.7.9

Service Account的bearer tokens也在集羣外部使用,可以用於創建希望與API進行通信的身份。通過使用kubectl create serviceaccount(NAME)命令,可以創建Service Account,並會創建一個關聯的密鑰。

$ kubectl create serviceaccount jenkins

serviceaccount "jenkins" created
$ kubectl get serviceaccounts jenkins -o yaml

創建的證書保存了API server公共CA和簽名的JSON Web Token(JWT)。

$ kubectl get secret jenkins-token-mk89c -o yaml
apiVersion: v1 data:  # ca證書
ca.crt: (APISERVER'S CA BASE64 ENCODED)
 # 命名空間
namespace: ZGVmYXVsdA==
# 令牌
 token: (BEARER TOKEN BASE64 ENCODED) kind: Secret metadata:  # ... type: kubernetes.io/service-account-token

注意:保密字典的值是基於base64編碼的,因爲通常祕鑰都是使用base64進行編碼的。

簽名的JWT可以作爲bearer token來驗證給定的service account。通常,這些祕鑰被掛載到Pods中,用於集羣中訪問API服務器,但也可以在羣集外部使用。

Service Account使用用戶名進行驗證 system:serviceaccount:(NAMESPACE):(SERVICEACCOUNT),並分配給組 system:serviceaccountssystem:serviceaccounts:(NAMESPACE)

警告:由於service account 令牌存儲在祕鑰中,任何具有對這些祕鑰的讀取訪問權限的用戶都可以作爲service account 進行身份驗證。

ServiceAccount 主要包含了三個內容:命名空間、令牌 CA。命名空間指定了 Pod 所在的 命名空間;CA是用於驗證 api server 的證書;令牌用作身份驗證。它們都通過掛接的方式保存在 pod 的文件系統中,其中令牌保存的路徑是: /var/run/secrets/kubernetes.io/serviceaccount/token ,這是 apiserver 使用base64 編碼通過私鑰籤的令牌; CA 保存的路徑是 /var/run/secrets/kubernetes.io/serviceaccount/ca.crt ,命名空間保存的路徑是 /var/run/secrets/kubernetes.io/serviceaccount/namespace ,也是使用 base64 編碼。

如果令牌能夠通過認證,那麼請求的用戶名將被設置爲 system:serviceaccount:(NAMESPACE):(SERVICEACCOUNT) ,而請求的組名有兩個: system:serviceaccountssystem:serviceaccounts:(NAMESPACE)

2.3 靜態Tokent文件

API server通過-token-auth-file=SOMEFILE選擇讀取不記名的Token。當前,token是無期限持續的,除非重啓API server。Token文件是一個至少包含3列的csv文件: token, user name, user uid,後跟可選的組名。注意,如果您有多個組,則列必須是雙引號,例如:

token,user,uid,"group1,group2,group3"

用token唯一標識請求者,只要apiserver存在該token,則認爲認證通過,但是如果需要新增Token,則需要重啓kube-apiserver組件,實際效果不是很好。

當通過客戶端使用 bearer token 認證時,API服務器需要一個值爲帶有Bearer THETOKEN值的Authorization頭。bearer token必須是一個字符序列,能夠放在HTTP請求頭中。例如:如果bearer token是31ada4fd-adec-460c-809a-9e56ceb75269,它將會在HTTP頭中按下面的方式呈現:

Authorization: Bearer 31ada4fd-adec-460c-809a-9e56ceb75269

2.4 Bootstrap令牌

此特性目前還是alpha階段。爲了能夠在新的集羣中使用bootstrapping認證,Kubernetes需要包括一個動態管理的Bearer token(成爲Bootstrap Token),這種token以Secrets的方式存儲在kube-system命名空間中,在這個命名空間token可以被動態的管理和創建。Controller Manager有一個TokenCleaner控制器,通過此控制器刪除過期了的bootstrap token。

token證書格式爲:[a-z0-9]{6}.[a-z0-9]{16},Token的第一部分是一個Token ID,第二部分是token的祕鑰。你需要在http協議頭中加上類似的信息:

Authorization: Bearer 781292.db7bc3a58fc5f07e

如果要使用Bootstrap,需要在API Sever中設置–experimental-bootstrap-token-auth。同時,必須在Controller Manager中設置–controllers=*,tokencleaner來啓用TokenCleaner控制器。

在使用kubeadm部署Kubernetes時,kubeadm會自動創建默認token,可通過kubeadm token list命令查詢。

2.5 靜態密碼文件

基礎認證模式通過在API Server中設置–basic-auth-file=SOMEFILE來啓用。一旦API server服務啓動,加載的用戶名和密碼信息就不會發生改變,任何對源文件的修改必須重啓 apiserver 才能生效。

靜態密碼文件是 CSV 格式的文件,每行對應一個用戶的信息,前面3列爲:密碼、用戶名、用戶 ID,這些是是必須的;第四列是可選的組名(如果有多個組,必須用雙引號):

password,user,uid,"group1,group2,group3"

當Http客戶端使用基礎認證時,API Server需要一個帶有Basic BASE64ENCODED(USER:PASSWORD) 值的 Authorization 頭。API Server 解析出客戶端提供的用戶名和密碼,如果和文件中的某一行匹配,就認爲認證成功。

注意: 這種方式很不靈活,也不安全,可以說名存實亡,不推薦使用。

2.6 Keystone密碼

Kubernetes也可以使用Openstack的Keystone組件進行身份認證和授權,這個方法對於已經使用 openstack 來搭建 IaaS 平臺的公司比較適用,直接使用 keystone 可以保證 Iaas 和 Caas 平臺保持一致的用戶體系。

需要API Server在啓動時指定–experimental-keystone-url=<AuthURL>,而https時還需要設置–experimental-keystone-ca-file=SOMEFILE

3、匿名請求

如果用戶請求沒有Kubernetes任何方式的身份認證,在正常情況下,Kubernetes會直接返回 “401” 錯誤信息。但是,在 kubernetes 還提供另外一種方案,即給沒有通過認證的請求一個特殊的用戶名 :system:anonymous 和組名: system:unauthenticated 。這樣的話,就可以跟授權模式結合起來,爲匿名請求設置一些特殊的權限,比如,只能讀取當前 namespace 的 pod 信息,以方便用戶訪問。

在Kubernetes的1.5.1-1.5.x版本,在默認情況下匿名請求是不可用的,但能夠通過在API Server中設置–anonymous-auth=true來啓用。

在Kubernetes的1.6+版本,如果使用AlwaysAllow以外的收取模式,則匿名請求默認開啓,但可用通過設置–anonymous-auth=false禁止匿名請求。從1.6版本開始,ABAC和RBAC授權需要顯示對system:anonymous用戶和system:unauthenticated的組進行授權,通過* user或*group這種方式進行訪問授權將不包含匿名的用戶。

本文轉自中文社區-Kubernetes-身份認證

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章