k8s 身份驗證

譯自官方文檔:
https://kubernetes.io/docs/admin/authentication/#users-in-kubernetes

Users in Kubernetes

所有的k8s集羣有兩類用戶:
1. service account (managed by kuberentes)
2. normal user

普通用戶一般認爲由外部的獨立服務管理。管理員分發私鑰, 用戶將私鑰存儲到Keystone或者Google Accounts甚至是文件中。由此可見,k8s沒有能夠代表普通用戶賬戶的對象。因此常規用戶無法通過API調用加入到集羣。

作爲對比, service account 是由k8s api管理的用戶。它們會和特定的namespace做綁定,可以通過api server自動創建,或者手動調用API來創建。service accounts 和一系列存儲在Secret中的證書相關聯,這些證書被安裝到集羣中,允許集羣進程與k8s api對話。

API 請求綁定到普通用戶或者service account,或者被視爲匿名請求。
這意味着集羣內部或外部的每個進程,從在工作站上鍵入kubectl的人類用戶到節點上的kubelet,到控制平面的成員,都必須在向API服務器發出請求時進行身份驗證,或者被視爲匿名用戶。

認證策略

Kubernete 使用客戶端證書,承載令牌,認證代理或者http基礎認證,通過身份認證常見對API請求進行身份認證。由於是向apiserver發送請求,插件會嘗試將一下屬性和請求相關聯:
- Username: 一個代表了最終用戶的字符串。一般是kube-adm或者[email protected].
- UID: 一個標識最終用戶的字符串,比用戶名更加一致和唯一。
- Groups: 將用戶與一組常用用戶相關聯的字符串集合。
- Extra fields: 一個包含了可能有用的額外信息的字符串和列表的映射。

所有值對於認證系統都是不透明的,並且只有授權人驗證時才能派上用場。

你可以同時開啓多種認證方式。最少要使用兩種方式:
1. service account token for service accounts
2. 一種或更多的普通用戶認證

當開啓了多個認證模塊時,第一個模塊會驗證請求的根路徑(對於/aaa/bbb/ccc, 會驗證/aaa). apiserver 不保證授權模塊的順序執行。

system:authenticated 包含了所有經過鑑定的用戶。

與其他身份驗證協議(LDAP,SAML,Kerberos,備用x509方案等)的集成可以使用身份驗證代理或身份驗證webhook完成。

X509 客戶端證書

x509 是一種通用證書格式

啓動apiserver時,添加--client-ca-file=SOMEFILE 可以開啓客戶端證書認證。被引用的證書文件必須包含一個或者多個證書頒發機構,用於驗證API server的客戶端證書。如果客戶端提供並且通過了認證,the common name of the subject is used as the user name for the request(這句不會翻)。在k8s1.4中,客戶端證書還可以使用證書的機構字段來指示用戶的組成員身份。想要爲用戶添加多個組,將多個機構字段包含到證書中去。

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

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

這會爲“jbeda”用戶創建一個CSR,屬與組“app1”和“app2”。

如何生成客戶端證書參考Managing Certificates

Static Token File

apiserver 通過 --token-auth-file=SOMEFILE 參數來讀取token.一般來說,token有效期無上限,token 列表修改後需要重啓apiserver。

token file是一個csv文件最少包含3列:token, user name, user uid, 後面是可選的group name。如果你有多個組名,必須要用雙引號來區分。e.g:

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

使用token請求

從http客戶端使用token鑑權的時候,需要在請求頭內帶上Authorization: token。token必須是字符序列,可以使用不超過http的編碼和引用。例如:假設token值爲: 31ada4fd-adec-460c-809a-9e56ceb75269,在http頭部裏面如下所示:

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

Bootstrap Tokens

這個特性當前在alpha 階段。

爲了簡化新集羣的引導, k8s加入了一個可動態管理的token類型叫做bootstrap token.這個token以Secret的形式存儲在kube-system命名空間中。k8s的controller manager中有個 TokenCleaner controller會在該token過期後刪除它。token的格式爲[a-z0-9]{6}.[a-z0-9]{16},在http請求頭中如下所示:

    Authorization: Bearer 781292.db7bc3a58fc5f07e

要啓用bootstrap token 需要爲apiserver添加--experimental-bootstrap-token-auth參數。同時需要在controller manager上開啓TokenCleaner 通過參數--controllers.配置起來類似--controllers=*,tokencleaner. 如果是通過kubeadm 創建的集羣,會自動執行上述步驟。

鑑權模塊會將token作爲system:bootstrap:<Token ID>。它包含在system:bootsrappers 組中。命名和組是有意限制的,爲了防止用戶通過引導非法使用這些令牌。用戶名和組可以被使用(被kubeadm 所使用),來制定適當的授權策略以支持集羣引導。

更多資料請參考Bootstrap Tokens

靜態密碼文件

基礎的認證可以通過在apiserver中通過--basic-auth-file=SOMEFILE 來開啓。基礎認證不存在過期,對密碼的修改也必須要重啓apiserver.請注意,爲了方便起見,目前支持基本身份驗證,直到我們讓上述更安全的模式更容易使用。

基礎認證文件是一個csv文件,至少包含3列:password, username, user id. 在k8s 1.6及以後版本,你可定義額外行來指定所屬的group。例如:

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

從http客戶端使用基本認證時,API服務器需要一個值爲Basic: BASE64ENCODED(USER:PASSWORD)的授權請求頭.

Service Account Tokens

service account 是默認開啓的。使用承載令牌來驗證請求。該插件需要開啓一下兩個參數:
- --service-account-key-file 一個包含了PEM編碼的祕鑰,用於token簽名。如果未開啓該參數,默認使用apiserver 的TLS私鑰。
- --service-account-lookup 如果開啓該參數,從API中刪除的token將被撤銷。

service account 通常會被apiserver自動創建,會和通過ServiceAccount Admission Controller 在集羣中運行的pod相關聯。token會被掛載到一個約定好的目錄下,並允許集羣進程與apiserver的通信。pod通過serviceAccountName 字段來和具體賬戶關聯。

Note: serviceAccountName 一般會自動添加,因此大部分情況該參數會被省略。

apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: default
spec:
  replicas: 3
  template:
    metadata:
    # ...
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        serviceAccountName: bob-the-bot

service account token 在集羣外部使用是完全有效的,並且可以用來爲長期工作創建身份,以便與Kubernetes API通信。手動創建service account 通過命令kubectl create serviceaccount <name>. 這會在當前的namespace創建並且關聯一個密碼。

$ kubectl create serviceaccount jenkins
serviceaccount "jenkins" created
$ kubectl get serviceaccounts jenkins -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  # ...
secrets:
- name: jenkins-token-1yvwg

創建的祕鑰包含apiserver的公共CA和簽名的JSON Web Token(JWT)。

$ kubectl get secret jenkins-token-1yvwg -o yaml
apiVersion: v1
data:
  ca.crt: (APISERVER'S CA BASE64 ENCODED)
  namespace: ZGVmYXVsdA==
  token: (BEARER TOKEN BASE64 ENCODED)
kind: Secret
metadata:
  # ...
type: kubernetes.io/service-account-token

Note: 祕鑰的值是經過base64編碼的。按照慣例Secret都已base64編碼後存儲。

簽過名的JWT可以當做承載令牌來驗證給定的service account.在使用token請求章節可以看到請求如何使用token. 通常爲了訪問集羣內的apiserver, 這些祕鑰(這裏應該指的是token)會掛載到相關的pod上。但是祕鑰(token)可以在集羣外部使用。

service account 鑑定通過用戶名 system:serviceaccount:<NAMESPACE>:<SERVICEACCOUNT>, 然後指派到組system:serviceaccounts 以及 system:serviceaccounts:<NAMESPACE>

WARNING: 由於service account token 以secret形式保存,擁有該secret可讀權限的用戶都能夠以此service account來進行認證。因此在給service account的secret可讀權限時需要謹慎。

OpenID Connect Token

應爲沒用到,所以就不翻譯了

Webhook Token Authentication

Webhook 認證是定義一個鉤子方法來驗證token.

  • --authentication-token-webhook-config-file 指定一個kubeconfig 文件,描述如何遠程的webhook服務
  • --authentication-token-webhook-cache-ttl 決定認證信息保存多長時間。默認兩分鐘

配置文件使用kubeconfig 文件格式。在文件中,“user” 指的是 apiserver webhook, “cluster” 指的是遠程服務。示例如下:

# clusters refers to the remote service.
clusters:
  - name: name-of-remote-authn-service
    cluster:
      certificate-authority: /path/to/ca.pem         # CA for verifying the remote service.
      server: https://authn.example.com/authenticate # URL of remote service to query. Must use 'https'.

# users refers to the API server's webhook configuration.
users:
  - name: name-of-api-server
    user:
      client-certificate: /path/to/cert.pem # cert for the webhook plugin to use
      client-key: /path/to/key.pem          # key matching the cert

# kubeconfig files require a context. Provide one for the API server.
current-context: webhook
contexts:
- context:
    cluster: name-of-remote-authn-service
    user: name-of-api-sever
  name: webhook

當客戶端嘗試使用token向apiserver進行認證時,webhook使用包含令牌的對象查詢遠程服務。如果客戶端請求頭中缺少token時,kubernetes不會發起上述認證步驟。

請注意,webhook API對象與其他Kubernetes API對象具有相同的版本控制兼容性規則。實現者應該意識到Beta對象的寬鬆兼容性承諾,並檢查請求的“apiVersion”字段以確保正確的反序列化。 此外,API服務器必須啓用authentication.k8s.io/v1beta1 API擴展組(--runtime-config=authentication.k8s.io/v1beta1=true)。

請求的body體格式如下:

{
  "apiVersion": "authentication.k8s.io/v1beta1",
  "kind": "TokenReview",
  "spec": {
    "token": "(BEARERTOKEN)"
  }
}

當token認證成功時,遠程服務返回信息格式如下:

{
  "apiVersion": "authentication.k8s.io/v1beta1",
  "kind": "TokenReview",
  "status": {
    "authenticated": true,
    "user": {
      "username": "[email protected]",
      "uid": "42",
      "groups": [
        "developers",
        "qa"
      ],
      "extra": {
        "extrafield1": [
          "extravalue1",
          "extravalue2"
        ]
      }
    }
  }
}

失敗時,返回信息如下:

{
  "apiVersion": "authentication.k8s.io/v1beta1",
  "kind": "TokenReview",
  "status": {
    "authenticated": false
  }
}

HTTP狀態代碼可以用來提供額外的錯誤上下文。

Authenticating Proxy

可以將APIserver 配置爲從請求頭中鑑定用戶。例如X-Remote-User。該頭部結合認證代理一起使用,認證代理負責設置頭部值。

  • --requestheader-username-headers 必選, 大小寫敏感。頭部名按順序檢查用戶標識。 包含一個值的第一個頭部被用作用戶名。
  • --requestheader-group-headers k8s1.6+, 可選參數,大小寫敏感。建議使用X-Remote-Group頭部字段。頭部名按順序檢查用戶組。 所有在該字段中的值都將被作爲組名使用。
  • --requesetheader-extra-headers-prefix 1.6+, 可選, 大小寫敏感。 X-Remote-Extra-. 頭部前綴可用於查找有關用戶的額外信息(通常由配置的授權插件使用)。 任何以任何指定的前綴開頭的標題都將刪除前綴,頭部名稱的其餘部分將成爲額外的鍵值,而頭部字段則是額外的值。

例如:

--requestheader-username-headers=X-Remote-User
--requestheader-group-headers=X-Remote-Group
--requestheader-extra-headers-prefix=X-Remote-Extra-

請求頭:

GET / HTTP/1.1
X-Remote-User: fido
X-Remote-Group: dogs
X-Remote-Group: dachshunds
X-Remote-Extra-Scopes: openid
X-Remote-Extra-Scopes: profile

產生的用戶信息:

name: fido
groups:
- dogs
- dachshunds
extra:
  scopes:
  - openid
  - profile

爲了預防頭部字段欺騙, 認證代理在檢查請求頭之前,需要客戶端向apiserver提供由指定CA頒發合法的證書。

  • --requestheader-client-ca-file 必選。 PEM編碼證書。在檢查用戶名的請求頭之前,必須針對指定文件中的證書頒發機構提交併驗證有效的客戶端證書。
  • --requestheader-allowed-names 可選。comman names(cn)清單。如果設置了該參數,在檢查用戶名的請求頭之前,必須提供指定列表中具有comman name(cn)的有效客戶端證書。 如果爲空,則允許使用任何cn。

Keystone Password

在apiserver啓動時,通過參數--experimental-keystone-url=<AuthURL> 來開啓Keystone 驗證。該插件在plugin/pkg/auth/authenticator(認證者)/password/keystone/keystone.go 中實現,當前使用基礎認證。驗證用戶名和密碼。

如果你爲keystone服務器配置了自簽名證書,可能需要在apiserver啓動時設置--experimental-keystone-ca-file=SOMEFILE 參數。如果已經設置,experimental-keystone-ca-file中定義的ca會認證Keystone 服務器證書. 不然的話,會使用主機的ca根證書來認證。

有關如何使用keystone來管理項目和用戶的詳細信息,請參閱Keystone文檔。 請注意,這個插件仍處於試驗階段,正在積極開發之中,並可能在後續版本中進行更改。

請參考 discussion, blueprint以及proposed changes以獲取更詳細的信息。

Anonymous requests

啓用時,未被其他已配置身份驗證方法拒絕的請求將被視爲匿名請求,並給予system:anonymous的用戶名和一組system:unuthenticated

例如,在配置了令牌認證和啓用匿名訪問的服務器上,提供無效承載令牌的請求將收到401 Unauthorized錯誤。 提供不記名令牌的請求將被視爲匿名請求。

在1.5.1-1.5.x中,默認情況下匿名訪問是禁用的,可以通過將--anonymous-auth=true選項傳遞給API服務器來啓用。

在1.6+版本中,如果使用AlwaysAllow以外的授權模式,則默認啓用匿名訪問,並且可以通過將--anonymous-auth=false選項傳遞給API服務器來禁用。 從1.6開始,ABAC和RBAC授權人需要明確授權system:anonymoussystem:unauthenticated的組,因此授予對* 用戶或*組訪問權限的傳統策略規則不包括匿名用戶。

User impersonation

用戶可以通過模擬請求頭部充當另一個用戶。例如,管理員可以使用此功能通過暫時模仿其他用戶並查看請求是否被拒絕來調試授權策略。

模擬請求首先認證爲請求用戶,然後切換到模擬的用戶信息。

  • 用戶使用他們的證書和模擬請求頭部進行API調用。
  • apiserver 認證用戶
  • apiserver 確認已授權用戶擁有模擬權限
  • 請求中的用戶信息被替換成模擬的用戶信息
  • 請求被評估,授權對模擬的用戶信息起作用。

以下HTTP頭部可用於執行模擬請求:

  • Impersonate-User: 要扮演用戶的名稱
  • Impersonate-Group: 要扮演用戶的組名。可以出現多次來設置多個組。是個可選的頭部,需要預先定義Impersonate-User
  • Impersonate-Extra-<extrs name>: 用於將額外字段與用戶關聯的動態標題。是個可選的頭部,需要預先定義Impersonate-User

示例如下:

Impersonate-User: [email protected]
Impersonate-Group: developers
Impersonate-Group: admins
Impersonate-Extra-dn: cn=jane,ou=engineers,dc=example,dc=com
Impersonate-Extra-scopes: view
Impersonate-Extra-scopes: development

使用kubelet的時,設置--as參數來配置Impersonate-User頭部,--as-group來配置Impoersonate_Group頭部。

$ kubectl drain mynode
Error from server (Forbidden): User "clark" cannot get nodes at the cluster scope. (get nodes mynode)

$ kubectl drain mynode --as=superman --as-group=system:masters
node "mynode" cordoned
node "mynode" drained

爲模仿用戶,組或設置額外字段,模擬用戶必須能夠對正在模擬的屬性的種類(“用戶”,“組”等)執行“模擬”動詞。 對於啓用RBAC授權插件的集羣,以下ClusterRole包含設置用戶和組模擬頭部所需的規則:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: impersonator
rules:
- apiGroups: [""]
  resources: ["users", "groups", "serviceaccounts"]
  verbs: ["impersonate"]

額外的字段被評估爲資源“userextras”的子資源。 要允許用戶使用額外字段“範圍”的模擬頭部,應授予用戶以下角色:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: scopes-impersonator
# Can set "Impersonate-Extra-scopes" header.
- apiGroups: ["authentication.k8s.io"]
  resources: ["userextras/scopes"]
  verbs: ["impersonate"]

模擬頭部的值也可以通過限制資源可以使用的資源名稱來限制:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: limited-impersonator
rules:
# Can impersonate the user "[email protected]"
- apiGroups: [""]
  resources: ["users"]
  verbs: ["impersonate"]
  resourceNames: ["[email protected]"]

# Can impersonate the groups "developers" and "admins"
- apiGroups: [""]
  resources: ["groups"]
- verbs: ["impersonate"]
  resourceNames: ["developers","admins"]

# Can impersonate the extras field "scopes" with the values "view" and "development"
- apiGroups: ["authentication.k8s.io"]
  resources: ["userextras/scopes"]
  verbs: ["impersonate"]
  resourceNames: ["view", "development"]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章