# Kubernetes 中的用戶與身份認證授權
在安裝集群的時候我們在 master 節點上生成了一堆證書、token,還在 kubelet 的配置中用到了 bootstrap token,安裝各種應用時,為了能夠與 API server 通信創建了各種 service account,在 Dashboard 中使用了 kubeconfig 或 token 登陸,那么這些都屬于什么認證方式?如何區分用戶的?我特地翻譯了下這篇官方文檔,想你看了之后你將找到答案。
重點查看 bearer token 和 HTTP 認證中的 token 使用,我們已經有所應用,如 [使用kubeconfig或token進行用戶身份認證](auth-with-kubeconfig-or-token.md)。
## 認識 Kubernetes 中的用戶
Kubernetes 集群中包含兩類用戶:一類是由 Kubernetes 管理的 service account,另一類是普通用戶。
普通用戶被假定為由外部獨立服務管理。管理員分發私鑰,用戶存儲(如 Keystone 或 Google 帳戶),甚至包含用戶名和密碼列表的文件。在這方面,_Kubernetes 沒有代表普通用戶帳戶的對象_。無法通過 API 調用的方式向集群中添加普通用戶。
相對的,service account 是由 Kubernetes API 管理的帳戶。它們都綁定到了特定的 namespace,并由 API server 自動創建,或者通過 API 調用手動創建。Service account 關聯了一套憑證,存儲在 `Secret`,這些憑證同時被掛載到 pod 中,從而允許 pod 與 kubernetes API 之間的調用。
API 請求被綁定到普通用戶或 serivce account 上,或者作為匿名請求對待。這意味著集群內部或外部的每個進程,無論從在工作站上輸入 `kubectl` 的人類用戶到節點上的 `kubelet`,到控制平面的成員,都必須在向 API Server 發出請求時進行身份驗證,或者被視為匿名用戶。
## 認證策略
Kubernetes 使用客戶端證書、bearer token、身份驗證代理或者 HTTP 基本身份驗證等身份認證插件來對 API 請求進行身份驗證。當有 HTTP 請求發送到 API server 時,插件會嘗試將以下屬性關聯到請求上:
- 用戶名:標識最終用戶的字符串。常用值可能是 `kube-admin` 或 `jane@example.com`。
- UID:標識最終用戶的字符串,比用戶名更加一致且唯一。
- 組:一組將用戶和常規用戶組相關聯的字符串。
- 額外字段:包含其他有用認證信息的字符串列表的映射。
所有的值對于認證系統都是不透明的,只有 [授權人](https://kubernetes.io/docs/admin/authorization/) 才能解釋這些值的重要含義。
您可以一次性啟用多種身份驗證方式。通常使用至少以下兩種認證方式:
- 服務帳戶的 service account token
- 至少一種其他的用戶認證的方式
當啟用了多個認證模塊時,第一個認證模塊成功認證后將短路請求,不會進行第二個模塊的認證。API server 不會保證認證的順序。
`system:authenticated` 組包含在所有已驗證用戶的組列表中。
與其他身份驗證協議(LDAP、SAML、Kerberos、x509 方案等)的集成可以使用身份驗證代理或身份驗證 webhook來實現。
### X509 客戶端證書
通過將 `--client-ca-file=SOMEFILE` 選項傳遞給 API server 來啟用客戶端證書認證。引用的文件必須包含一個或多個證書頒發機構,用于驗證提交給 API server 的客戶端證書。如果客戶端證書已提交并驗證,則使用 subject 的 Common Name(CN)作為請求的用戶名。從 Kubernetes 1.4開始,客戶端證書還可以使用證書的 organization 字段來指示用戶的組成員身份。要為用戶包含多個組成員身份,請在證書中包含多個 organization 字段。
例如,使用 `openssl` 命令工具生成用于簽名認證請求的證書:
```bash
openssl req -new -key jbeda.pem -out jbeda-csr.pem -subj "/CN=jbeda/O=app1/O=app2"
```
這將為一個用戶名為 ”jbeda“ 的 CSR,屬于兩個組“app1”和“app2”。
### 靜態 Token 文件
當在命令行上指定 `--token-auth-file=SOMEFILE` 選項時,API server 從文件讀取 bearer token。目前,token 會無限期地持續下去,并且不重新啟動 API server 的話就無法更改令牌列表。
token 文件是一個 csv 文件,每行至少包含三列:token、用戶名、用戶 uid,其次是可選的組名。請注意,如果您有多個組,則該列必須使用雙引號。
```ini
token,user,uid,"group1,group2,group3"
```
#### 在請求中放置 Bearer Token
當使用來自 http 客戶端的 bearer token 時,API server 期望 `Authorization` header 中包含 `Bearer token` 的值。Bearer token 必須是一個字符串序列,只需使用 HTTP 的編碼和引用功能就可以將其放入到 HTTP header 中。例如:如果 bearer token 是 `31ada4fd-adec-460c-809a-9e56ceb75269`,那么它將出現在 HTTP header 中,如下所示:
```http
Authorization: Bearer 31ada4fd-adec-460c-809a-9e56ceb75269
```
### Bootstrap Token
該功能仍處于 **alpha** 版本。
為了簡化新集群的初始化引導過程,Kubernetes 中包含了一個名為 *Bootstrap Token* 的動態管理的 bearer token。這些 token 使用 Secret 存儲在 `kube-system` namespace 中,在那里它們可以被動態管理和創建。Controller Manager 中包含了一個 TokenCleaner 控制器,用于在 bootstrap token 過期時刪除將其刪除。
這些 token 的形式是 `[a-z0-9]{6}.[a-z0-9]{16}`。第一部分是 Token ID,第二部分是 Token Secret。您在 HTTP header 中指定的 token 如下所示:
```http
Authorization: Bearer 781292.db7bc3a58fc5f07e
```
在 API server 的啟動參數中加上 `--experimental-bootstrap-token-auth` 標志以啟用 Bootstrap Token Authenticator。您必須通過 Controller Manager 上的 `--controllers` 標志啟用 TokenCleaner 控制器,如 `--controllers=*,tokencleaner`。如果您使用它來引導集群, `kubeadm` 會為您完成。
認證者認證為 `system:bootstrap:<Token ID>` 。被包含在 `system:bootstrappers` 組中。命名和組是有意限制用戶使用過去的 bootstap token。可以使用用戶名和組(`kubeadm` 使用)來制定適當的授權策略以支持引導集群。
有關 Bootstrap Token 身份驗證器和控制器的更深入的文檔,以及如何使用 `kubeadm` 管理這些令牌,請參閱 [Bootstrap Token](https://kubernetes.io/docs/admin/bootstrap-tokens/)。
### 靜態密碼文件
通過將 `--basic-auth-file=SOMEFILE` 選項傳遞給 API server 來啟用基本身份驗證。目前,基本身份驗證憑證將無限期地保留,并且密碼在不重新啟動API服務器的情況下無法更改。請注意,為了方便起見,目前支持基本身份驗證,而上述模式更安全更容易使用。
基本身份認證是一個 csv 文件,至少包含3列:密碼、用戶名和用戶 ID。在 Kubernetes 1.6 和更高版本中,可以指定包含以逗號分隔的組名稱的可選第四列。如果您有多個組,則必須將第四列值用雙引號(“)括起來,請參閱以下示例:
```ini
password,user,uid,"group1,group2,group3"
```
當使用來自 HTTP 客戶端的基本身份驗證時,API server 需要` Authorization` header 中包含 `Basic BASE64ENCODED(USER:PASSWORD)` 的值。
### Service Account Token
Service account 是一個自動啟用的驗證器,它使用簽名的 bearer token 來驗證請求。該插件包括兩個可選的標志:
- `--service-account-key-file` 一個包含簽名 bearer token 的 PEM 編碼文件。如果未指定,將使用 API server 的 TLS 私鑰。
- `--service-account-lookup` 如果啟用,從 API 中刪除掉的 token 將被撤銷。
Service account 通常 API server 自動創建,并通過 `ServiceAccount` [注入控制器](https://kubernetes.io/docs/admin/admission-controllers/) 關聯到集群中運行的 Pod 上。Bearer token 掛載到 pod 中眾所周知的位置,并允許集群進程與 API server 通信。 帳戶可以使用 `PodSpec` 的 `serviceAccountName` 字段顯式地與Pod關聯。
注意: `serviceAccountName` 通常被省略,因為這會自動生成。
```yaml
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 bearer token 在集群外使用也是完全有效的,并且可以用于為希望與 Kubernetes 通信的長期運行作業創建身份。要手動創建 service account,只需要使用 `kubectl create serviceaccount (NAME)` 命令。這將在當前的 namespace 和相關連的 secret 中創建一個 service account。
```bash
$ kubectl create serviceaccount jenkins
serviceaccount "jenkins" created
$ kubectl get serviceaccounts jenkins -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
# ...
secrets:
- name: jenkins-token-1yvwg
```
創建出的 secret 中擁有 API server 的公共 CA 和前面的 JSON Web Token(JWT)。
```bash
$ 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
```
注意:所有值是基于 base64 編碼的,因為 secret 總是基于 base64 編碼。
經過簽名的 JWT 可以用作 bearer token 與給定的 service account 進行身份驗證。請參閱上面關于如何在請求中放置 bearer token。通常情況下,這些 secret 被掛載到 pod 中,以便對集群內的 API server 進行訪問,但也可以從集群外訪問。
Service account 驗證時用戶名 `system:serviceaccount:(NAMESPACE):(SERVICEACCOUNT)`,被指定到組 `system:serviceaccounts` 和 `system:serviceaccounts:(NAMESPACE)`。
注意:由于 service account 的 token 存儲在 secret 中,所以具有對這些 secret 的讀取權限的任何用戶都可以作為 service account 進行身份驗證。授予 service account 權限和讀取 secret 功能時要謹慎。
### OpenID Connect Token
[OpenID Connect](https://openid.net/connect/) 是由 OAuth2 供應商提供的 OAuth2,特別是 Azure Active Directory、Salesforce 和 Google。對 OAuth2 協議的主要擴展是返回一個稱作 [ID Token](https://openid.net/specs/openid-connect-core-1_0.html#IDToken) 的格外字段。該 token 是一個 JSON Web Token (JWT) ,有服務器簽名,具有眾所周知的字段,如用戶的電子郵件。
為了識別用戶,認證者使用 OAuth2 [token 響應](https://openid.net/specs/openid-connect-core-1_0.html#TokenResponse) 中的 `id_token`(而不是 `access_token`)作為 bearer token。請參閱上面的關于將 token 置于請求中。

1. 登陸到您的身份提供商
2. 您的身份提供商將為您提供一個 `access_token`,一個 `id_token` 和一個 `refresh_token`
3. 當使用 `kubectl` 時,使用 `--token` 標志和 `id_token` ,或者直接加入到您的 `kubeconfig` 文件中
4. `kubectl` 在調用 API server 時將 `id_token` 置于 HTTP header 中
5. API server 將通過檢查配置中指定的證書來確保 JWT 簽名有效
6. 檢查以確保 `id_token` 沒有過期
7. 確保用戶已授權
8. 授權 API server 后向 `kubectl`
9. `kubectl` 向用戶提供反饋
由于所有需要驗證您身份的數據都在 `id_token` 中,Kubernetes 不需要向身份提供商 “phone home”。在每個請求都是無狀態的模型中,這為認證提供了非常可擴展的解決方案。它確實提供了一些挑戰:
1. Kubernetes 沒有 ”web 接口“ 來出發驗證進程。沒有瀏覽器或界面來收集憑據,這就是為什么您需要首先認證您的身份提供商。
2. `id_token` 無法撤銷,就像一個證書,所以它應該是短暫的(只有幾分鐘),所以每隔幾分鐘就得到一個新的令牌是非常煩人的。
3. 沒有使用 `kubectl proxy` 命令或注入 `id_token` 的反向代理,無法簡單地對 Kubernetes dashboard 進行身份驗證。
#### 配置 API Server
要啟用該插件,需要在 API server 中配置如下標志:
| 參數 | 描述 | 示例 | 是否必需 |
| ----------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -------- |
| `--oidc-issuer-url` | 允許 API server 發現公共簽名密鑰的提供者的 URL。只接受使用 `https://` 的方案。通常是提供商的 URL 地址,不包含路徑,例如“<https://accounts.google.com>” 或者 “<https://login.salesforce.com>”。這個 URL 應該指向下面的 .well-known/openid-configuration | 如果發現 URL 是 `https://accounts.google.com/.well-known/openid-configuration`,值應該是`https://accounts.google.com` | 是 |
| `--oidc-client-id` | 所有的 token 必須為其頒發的客戶端 ID | kubernetes | 是 |
| `--oidc-username-claim` | JWT聲明使用的用戶名。默認情況下,`sub` 是最終用戶的唯一標識符。管理員可以選擇其他聲明,如` email` 或 `name`,具體取決于他們的提供者。不過,`email` 以外的其他聲明將以發行者的 URL 作為前綴,以防止與其他插件命名沖突。 | sub | 否 |
| `--oidc-groups-claim` | JWT聲明使用的用戶組。如果生命存在,它必須是一個字符串數組。 | groups | 否 |
| `--oidc-ca-file` | 用來簽名您的身份提供商的網絡 CA 證書的路徑。默認為主機的跟 CA。 | `/etc/kubernetes/ssl/kc-ca.pem` | 否 |
如果為 `--oidc-username-claim` 選擇了除 `email` 以外的其他聲明,則該值將以 `--oidc-issuer-url` 作為前綴,以防止與現有 Kubernetes 名稱(例如 `system:users`)沖突。例如,如果提供商網址是 https://accounts.google.com,而用戶名聲明映射到 `jane`,則插件會將用戶身份驗證為:
```http
https://accounts.google.com#jane
```
重要的是,API server 不是 OAuth2 客戶端,而只能配置為信任單個發行者。這允許使用 Google 等公共提供者,而不必信任第三方發行的憑據。希望利用多個 OAuth 客戶端的管理員應該探索支持 `azp`(授權方)聲明的提供者,這是允許一個客戶端代表另一個客戶端發放令牌的機制。
Kubernetes不提供 OpenID Connect 身份提供商。您可以使用現有的公共 OpenID Connect 標識提供程序(例如Google 或 [其他](http://connect2id.com/products/nimbus-oauth-openid-connect-sdk/openid-connect-providers))。或者,您可以運行自己的身份提供程序,例如 CoreOS [dex](https://github.com/coreos/dex)、[Keycloak](https://github.com/keycloak/keycloak)、CloudFoundry [UAA](https://github.com/cloudfoundry/uaa) 或 Tremolo Security 的 [OpenUnison](https://github.com/tremolosecurity/openunison)。
對于身份提供商能夠適用于 Kubernetes,必須滿足如下條件:Kubernetes it must:
1. 支持 [OpenID connect 發現](https://openid.net/specs/openid-connect-discovery-1_0.html);不必是全部。
2. 使用非過時密碼在TLS中運行
3. 擁有 CA 簽名證書(即使 CA 不是商業 CA 或自簽名)
有關上述要求3的說明,需要 CA 簽名證書。如果您部署自己的身份提供商(而不是像 Google 或 Microsoft 之類的云提供商),則必須讓您的身份提供商的 Web 服務器證書由 CA 標志設置為 TRUE 的證書簽名,即使是自簽名的。這是由于 GoLang 的 TLS 客戶端實現對證書驗證的標準非常嚴格。如果您沒有 `CA`,可以使用 `CoreOS` 團隊的 [這個腳本](https://github.com/coreos/dex/blob/1ee5920c54f5926d6468d2607c728b71cfe98092/examples/k8s/gencert.sh) 創建一個簡單的 CA 和一個簽名的證書和密鑰對。
針對特定系統的安裝說明:
- [UAA](https://apigee.com/about/blog/engineering/kubernetes-authentication-enterprise)
- [Dex](https://speakerdeck.com/ericchiang/kubernetes-access-control-with-dex)
- [OpenUnison](https://github.com/TremoloSecurity/openunison-qs-kubernetes)
#### 使用 kubectl
##### 選項 1 - OIDC 身份驗證器
第一個選項是使用 `oidc` 身份驗證器。此身份驗證程序將您的 `id_token`、`refresh_token` 和您的 OIDC `client_secret` 自動刷新您的 token。一旦您對身份提供者進行了身份驗證:
```bash
kubectl config set-credentials USER_NAME \
--auth-provider=oidc \
--auth-provider-arg=idp-issuer-url=( issuer url ) \
--auth-provider-arg=client-id=( your client id ) \
--auth-provider-arg=client-secret=( your client secret ) \
--auth-provider-arg=refresh-token=( your refresh token ) \
--auth-provider-arg=idp-certificate-authority=( path to your ca certificate ) \
--auth-provider-arg=id-token=( your id_token ) \
--auth-provider-arg=extra-scopes=( comma separated list of scopes to add to "openid email profile", optional )
```
例如,在向身份提供者進行身份驗證之后運行以下命令:
```bash
kubectl config set-credentials mmosley \
--auth-provider=oidc \
--auth-provider-arg=idp-issuer-url=https://oidcidp.tremolo.lan:8443/auth/idp/OidcIdP \
--auth-provider-arg=client-id=kubernetes \
--auth-provider-arg=client-secret=1db158f6-177d-4d9c-8a8b-d36869918ec5 \
--auth-provider-arg=refresh-token=q1bKLFOyUiosTfawzA93TzZIDzH2TNa2SMm0zEiPKTUwME6BkEo6Sql5yUWVBSWpKUGphaWpxSVAfekBOZbBhaEW+VlFUeVRGcluyVF5JT4+haZmPsluFoFu5XkpXk5BXqHega4GAXlF+ma+vmYpFcHe5eZR+slBFpZKtQA= \
--auth-provider-arg=idp-certificate-authority=/root/ca.pem \
--auth-provider-arg=extra-scopes=groups \
--auth-provider-arg=id-token=eyJraWQiOiJDTj1vaWRjaWRwLnRyZW1vbG8ubGFuLCBPVT1EZW1vLCBPPVRybWVvbG8gU2VjdXJpdHksIEw9QXJsaW5ndG9uLCBTVD1WaXJnaW5pYSwgQz1VUy1DTj1rdWJlLWNhLTEyMDIxNDc5MjEwMzYwNzMyMTUyIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL29pZGNpZHAudHJlbW9sby5sYW46ODQ0My9hdXRoL2lkcC9PaWRjSWRQIiwiYXVkIjoia3ViZXJuZXRlcyIsImV4cCI6MTQ4MzU0OTUxMSwianRpIjoiMm96US15TXdFcHV4WDlHZUhQdy1hZyIsImlhdCI6MTQ4MzU0OTQ1MSwibmJmIjoxNDgzNTQ5MzMxLCJzdWIiOiI0YWViMzdiYS1iNjQ1LTQ4ZmQtYWIzMC0xYTAxZWU0MWUyMTgifQ.w6p4J_6qQ1HzTG9nrEOrubxIMb9K5hzcMPxc9IxPx2K4xO9l-oFiUw93daH3m5pluP6K7eOE6txBuRVfEcpJSwlelsOsW8gb8VJcnzMS9EnZpeA0tW_p-mnkFc3VcfyXuhe5R3G7aa5d8uHv70yJ9Y3-UhjiN9EhpMdfPAoEB9fYKKkJRzF7utTTIPGrSaSU6d2pcpfYKaxIwePzEkT4DfcQthoZdy9ucNvvLoi1DIC-UocFD8HLs8LYKEqSxQvOcvnThbObJ9af71EwmuE21fO5KzMW20KtAeget1gnldOosPtz1G5EwvaQ401-RPQzPGMVBld0_zMCAwZttJ4knw
```
將產生下面的配置:
```yaml
users:
- name: mmosley
user:
auth-provider:
config:
client-id: kubernetes
client-secret: 1db158f6-177d-4d9c-8a8b-d36869918ec5
extra-scopes: groups
id-token: eyJraWQiOiJDTj1vaWRjaWRwLnRyZW1vbG8ubGFuLCBPVT1EZW1vLCBPPVRybWVvbG8gU2VjdXJpdHksIEw9QXJsaW5ndG9uLCBTVD1WaXJnaW5pYSwgQz1VUy1DTj1rdWJlLWNhLTEyMDIxNDc5MjEwMzYwNzMyMTUyIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL29pZGNpZHAudHJlbW9sby5sYW46ODQ0My9hdXRoL2lkcC9PaWRjSWRQIiwiYXVkIjoia3ViZXJuZXRlcyIsImV4cCI6MTQ4MzU0OTUxMSwianRpIjoiMm96US15TXdFcHV4WDlHZUhQdy1hZyIsImlhdCI6MTQ4MzU0OTQ1MSwibmJmIjoxNDgzNTQ5MzMxLCJzdWIiOiI0YWViMzdiYS1iNjQ1LTQ4ZmQtYWIzMC0xYTAxZWU0MWUyMTgifQ.w6p4J_6qQ1HzTG9nrEOrubxIMb9K5hzcMPxc9IxPx2K4xO9l-oFiUw93daH3m5pluP6K7eOE6txBuRVfEcpJSwlelsOsW8gb8VJcnzMS9EnZpeA0tW_p-mnkFc3VcfyXuhe5R3G7aa5d8uHv70yJ9Y3-UhjiN9EhpMdfPAoEB9fYKKkJRzF7utTTIPGrSaSU6d2pcpfYKaxIwePzEkT4DfcQthoZdy9ucNvvLoi1DIC-UocFD8HLs8LYKEqSxQvOcvnThbObJ9af71EwmuE21fO5KzMW20KtAeget1gnldOosPtz1G5EwvaQ401-RPQzPGMVBld0_zMCAwZttJ4knw
idp-certificate-authority: /root/ca.pem
idp-issuer-url: https://oidcidp.tremolo.lan:8443/auth/idp/OidcIdP
refresh-token: q1bKLFOyUiosTfawzA93TzZIDzH2TNa2SMm0zEiPKTUwME6BkEo6Sql5yUWVBSWpKUGphaWpxSVAfekBOZbBhaEW+VlFUeVRGcluyVF5JT4+haZmPsluFoFu5XkpXk5BXq
name: oidc
```
一旦您的 `id_token` 過期,`kubectl` 將使用 `refresh_token` 刷新 `id_token`,然后在 `kube/.config` 文件的`client_secret` 中存儲 `id_token` 的值和`refresh_token` 的新值。
##### 選項 2 - 使用 `--token` 選項
可以在 `kubectl` 命令的 `--token` 選項中傳入 token。簡單的拷貝和復制 `id_token` 到該選項中:
```bash
kubectl --token=eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL21sYi50cmVtb2xvLmxhbjo4MDQzL2F1dGgvaWRwL29pZGMiLCJhdWQiOiJrdWJlcm5ldGVzIiwiZXhwIjoxNDc0NTk2NjY5LCJqdGkiOiI2RDUzNXoxUEpFNjJOR3QxaWVyYm9RIiwiaWF0IjoxNDc0NTk2MzY5LCJuYmYiOjE0NzQ1OTYyNDksInN1YiI6Im13aW5kdSIsInVzZXJfcm9sZSI6WyJ1c2VycyIsIm5ldy1uYW1lc3BhY2Utdmlld2VyIl0sImVtYWlsIjoibXdpbmR1QG5vbW9yZWplZGkuY29tIn0.f2As579n9VNoaKzoF-dOQGmXkFKf1FMyNV0-va_B63jn-_n9LGSCca_6IVMP8pO-Zb4KvRqGyTP0r3HkHxYy5c81AnIh8ijarruczl-TK_yF5akjSTHFZD-0gRzlevBDiH8Q79NAr-ky0P4iIXS8lY9Vnjch5MF74Zx0c3alKJHJUnnpjIACByfF2SCaYzbWFMUNat-K1PaUk5-ujMBG7yYnr95xD-63n8CO8teGUAAEMx6zRjzfhnhbzX-ajwZLGwGUBT4WqjMs70-6a7_8gZmLZb2az1cZynkFRj2BaCkVT3A2RrjeEwZEtGXlMqKJ1_I2ulrOVsYx01_yD35-rw get nodes
```
### Webhook Token 認證
Webhook 認證是用來認證 bearer token 的 hook。
- `--authentication-token-webhook-config-file` 是一個用來描述如何訪問遠程 webhook 服務的 kubeconfig 文件。
- `--authentication-token-webhook-cache-ttl` 緩存身份驗證策略的時間。默認為兩分鐘。
配置文件使用 [kubeconfig](https://kubernetes.io/docs/concepts/cluster-administration/authenticate-across-clusters-kubeconfig/) 文件格式。文件中的 ”user“ 指的是 API server 的 webhook,”clusters“ 是指遠程服務。見下面的例子:
```yaml
# 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
```
當客戶端嘗試使用 bearer token 與API server 進行認證是,如上論述,認證 webhook 用飽含該 token 的對象查詢遠程服務。Kubernetes 不會挑戰缺少該 header 的請求。
請注意,webhook API對象與其他 Kubernetes API 對象具有相同的 [版本控制兼容性規則](https://kubernetes.io/docs/concepts/overview/kubernetes-api/)。實現者應該意識到 Beta 對象的寬松兼容性承諾,并檢查請求的 “apiVersion” 字段以確保正確的反序列化。此外,API server 必須啟用 `authentication.k8s.io/v1beta1` API 擴展組(`--runtime config =authentication.k8s.io/v1beta1=true`)。
The request body will be of the following format:
```json
{
"apiVersion": "authentication.k8s.io/v1beta1",
"kind": "TokenReview",
"spec": {
"token": "(BEARERTOKEN)"
}
}
```
預計遠程服務將填寫請求的 `status` 字段以指示登錄成功。響應主體的 `spec` 字段被忽略,可以省略。成功驗證后的 bearer token 將返回:
```json
{
"apiVersion": "authentication.k8s.io/v1beta1",
"kind": "TokenReview",
"status": {
"authenticated": true,
"user": {
"username": "janedoe@example.com",
"uid": "42",
"groups": [
"developers",
"qa"
],
"extra": {
"extrafield1": [
"extravalue1",
"extravalue2"
]
}
}
}
}
```
未成功的請求將返回:
```json
{
"apiVersion": "authentication.k8s.io/v1beta1",
"kind": "TokenReview",
"status": {
"authenticated": false
}
}
```
HTTP狀態代碼可以用來提供額外的錯誤上下文。
### 認證代理
可以配置 API server 從請求 header 的值中識別用戶,例如 `X-Remote-User`。這樣的設計是用來與請求 header 值的驗證代理結合使用。
- `--requestheader-username-headers` 必需,大小寫敏感。按 header 名稱和順序檢查用戶標識。包含值的第一個 header 將被作為用戶名。
- `--requestheader-group-headers` 1.6 以上版本。可選。大小寫敏感。建議為 “X-Remote-Group”。按 header 名稱和順序檢查用戶組。所有指定的 header 中的所有值都將作為組名。
- `--requestheader-extra-headers-prefix` 1.6 以上版本。可選,大小寫敏感。建議為 “X-Remote-Extra-”。標題前綴可用于查找有關用戶的額外信息(通常由配置的授權插件使用)。以任何指定的前綴開頭的 header 都會刪除前綴,header 名稱的其余部分將成為額外的鍵值,而 header 值則是額外的值。
例如下面的配置:
```bash
--requestheader-username-headers=X-Remote-User
--requestheader-group-headers=X-Remote-Group
--requestheader-extra-headers-prefix=X-Remote-Extra-
```
該請求:
```http
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
```
將產生如下的用戶信息:
```yaml
name: fido
groups:
- dogs
- dachshunds
extra:
scopes:
- openid
- profile
```
為了防止 header 欺騙,驗證代理需要在驗證請求 header 之前向 API server 提供有效的客戶端證書,以對照指定的 CA 進行驗證。
- `--requestheader-client-ca-file` 必需。PEM 編碼的證書包。在檢查用戶名的請求 header 之前,必須針對指定文件中的證書頒發機構提交并驗證有效的客戶端證書。
- `--requestheader-allowed-names` 可選。Common Name (cn)列表。如果設置了,則在檢查用戶名的請求 header 之前, 必須提供指定列表中 Common Name(cn)的有效客戶端證書。如果為空,則允許使用任何 Common Name。
### Keystone 密碼
通過在啟動過程中將 `--experimental-keystone-url=<AuthURL>` 選項傳遞給 API server 來啟用 Keystone 認證。該插件在 `plugin/pkg/auth/authenticator/password/keystone/keystone.go` 中實現,目前使用基本身份驗證通過用戶名和密碼驗證用戶。
如果您為 Keystone 服務器配置了自簽名證書,則在啟動 Kubernetes API server 時可能需要設置 `--experimental-keystone-ca-file=SOMEFILE` 選項。如果您設置了該選項,Keystone 服務器的證書將由`experimental-keystone-ca-file` 中的某個權威機構驗證。否則,證書由主機的根證書頒發機構驗證。
有關如何使用 keystone 來管理項目和用戶的詳細信息,請參閱 [Keystone 文檔](http://docs.openstack.org/developer/keystone/)。請注意,這個插件仍處于試驗階段,正在積極開發之中,并可能在后續版本中進行更改。
請參考 [討論](https://github.com/kubernetes/kubernetes/pull/11798#issuecomment-129655212)、[藍圖](https://github.com/kubernetes/kubernetes/issues/11626) 和 [提出的改變](https://github.com/kubernetes/kubernetes/pull/25536) 獲取更多信息。
## 匿名請求
啟用時,未被其他已配置身份驗證方法拒絕的請求將被視為匿名請求,并給予 `system:anonymous` 的用戶名和` system:unuthenticated` 的組名。
例如,在配置了令牌認證和啟用了匿名訪問的服務器上,提供無效的 bearer token 的請求將收到 `401 Unauthorized` 錯誤。提供 bearer token 的請求將被視為匿名請求。
在 1.5.1 - 1.5.x 版本中,默認情況下命名訪問是被禁用的,可以通過傳遞 `--anonymous-auth=false` 選項給 API server 來啟用。
在 1.6+ 版本中,如果使用 `AlwaysAllow` 以外的授權模式,則默認啟用匿名訪問,并且可以通過將 `--anonymous-auth=false`選項傳遞給API服務器來禁用。從 1.6 開始,ABAC 和 RBAC 授權人需要明確授權 `system:annoymous` 或 `system:unauthenticated` 組,因此授予對 `*` 用戶或 `*` 組訪問權的傳統策略規則不包括匿名用戶。
## 用戶模擬
用戶可以通過模擬 header 充當另一個用戶。該請求會覆蓋請求認證的用戶信息。例如,管理員可以使用此功能通過暫時模擬其他用戶并查看請求是否被拒絕來調試授權策略。
模擬請求首先認證為請求用戶,然后切換到模擬的用戶信息。
- 用戶使用他們的憑證_和_模擬 header 進行 API 調用。
- API server 認證用戶
- API server 確保經過身份驗證的用戶具有模擬權限。
- 請求用戶的信息被替換為模擬值
- 請求被評估,授權作用于模擬的用戶信息。
以下 HTTP header 可用戶執行模擬請求:
- `Impersonate-User`:充當的用戶名
- `Impersonate-Group`:作為組名。可以多次使用來設置多個組。可選的,需要 “Impersonate-User”
- `Impersonate-Extra-( extra name )`:用于將額外字段與用戶關聯的動態 header。可選。需要 “Impersonate-User”
一組示例 header:
```http
Impersonate-User: jane.doe@example.com
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
```
當使用 `kubectl` 的 `--as` 標志來配置 `Impersonate-User` header 時,可以使用 `--as-group` 標志來配置 `Impersonate-Group` header。
```bash
$ 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" draine
```
為模仿用戶、組或設置額外字段,模擬用戶必須能夠對正在模擬的屬性的種類(“用戶”,“組”等)執行“模擬”動詞。對于啟用了 RBAC 授權插件的集群,以下 ClusterRole 包含設置用戶和組模擬 header 所需的規則:
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: impersonator
rules:
- apiGroups: [""]
resources: ["users", "groups", "serviceaccounts"]
verbs: ["impersonate"]
```
額外的字段被評估為資源 “userextras” 的子資源。為了允許用戶使用額外字段 “scope” 的模擬 header,應授予用戶以下角色:
```yaml
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"]
```
模擬 header 的可用值可以通過設置 `resourceNames` 可以使用的資源來限制。
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: limited-impersonator
rules:
# Can impersonate the user "jane.doe@example.com"
- apiGroups: [""]
resources: ["users"]
verbs: ["impersonate"]
resourceNames: ["jane.doe@example.com"]
# 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"]
```
## 附錄
### 創建證書
使用客戶端證書進行身份驗證時,可以使用現有的部署腳本或通過 `easyrsa` 或 `openssl` 手動生成證書。
#### 使用已有的部署腳本
**已有的部署腳本** 在 `cluster/saltbase/salt/generate-cert/make-ca-cert.sh`。
執行該腳本時需要傳遞兩個參數。第一個參數是 API server 的 IP地址。第二個參數是 IP 形式的主題備用名稱列表: `IP:<ip-address>` 或 `DNS:<dns-name>`。
該腳本將生成三個文件: `ca.crt`、`server.crt` 和 `server.key`。
最后,將一下參數添加到 API server 的啟動參數中:
- `--client-ca-file=/srv/kubernetes/ca.crt`
- `--tls-cert-file=/srv/kubernetes/server.crt`
- `--tls-private-key-file=/srv/kubernetes/server.key`
#### easyrsa
**easyrsa** 可以用來手動為集群生成證書。
1. 下載,解壓,并初始化修補版本的easyrsa3。
```bash
curl -L -O https://storage.googleapis.com/kubernetes-release/easy-rsa/easy-rsa.tar.gz
tar xzf easy-rsa.tar.gz
cd easy-rsa-master/easyrsa3
./easyrsa init-pki
```
2. 生成 CA(使用 `--batch` 設置為自動模式。使用 `--req-cn` 設置默認的 CN)
```bash
./easyrsa --batch "--req-cn=${MASTER_IP}@`date +%s`" build-ca nopass
```
3. 生成服務器證書和密鑰。(build-server-full [文件名]:生成一個鍵值對,在本地為客戶端和服務器簽名。)
```bash
./easyrsa --subject-alt-name="IP:${MASTER_IP}" build-server-full server nopass
```
4. 復制 `pki/ca.crt`, `pki/issued/server.crt` 和 `pki/private/server.key` 到您的目錄下。
5. 將以下參數添加到 API server 的啟動參數中:
```bash
--client-ca-file=/yourdirectory/ca.crt
--tls-cert-file=/yourdirectory/server.crt
--tls-private-key-file=/yourdirectory/server.key
```
#### openssl
**openssl** 可以用來手動為集群生成證書。
1. 生成一個 2048 bit 的 ca.key:
```bash
openssl genrsa -out ca.key 2048
```
2. 根據 ca.key 生成一個 ca.crt(使用 -days 設置證書的有效時間):
```bash
openssl req -x509 -new -nodes -key ca.key -subj "/CN=${MASTER_IP}" -days 10000 -out ca.crt
```
3. 生成一個 2048 bit 的 server.key:
```bash
openssl genrsa -out server.key 2048
```
4. 根據 server.key 生成一個 server.csr:
```bash
openssl req -new -key server.key -subj "/CN=${MASTER_IP}" -out server.csr
```
5. 根據 ca.key、ca.crt 和 server.csr 生成 server.crt:
```bash
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 10000
```
6. 查看證書:
```bash
openssl x509 -noout -text -in ./server.crt
```
最后,不要忘了向 API server 的啟動參數中增加配置。
#### 認證 API
您可以使用 `certificates.k8s.io` API將 x509 證書配置為用于身份驗證,如 [此處](https://kubernetes.io/docs/tasks/tls/managing-tls-in-a-cluster) 所述。
官方最新文檔地址:https://kubernetes.io/docs/admin/authentication/
譯者:[Jimmy Song](https://jimmysong.io)
- 序言
- 云原生
- 云原生(Cloud Native)的定義
- CNCF - 云原生計算基金會簡介
- CNCF章程
- 云原生的設計哲學
- Play with Kubernetes
- 快速部署一個云原生本地實驗環境
- Kubernetes與云原生應用概覽
- 云原生應用之路——從Kubernetes到Cloud Native
- 云原生編程語言
- 云原生編程語言Ballerina
- 云原生編程語言Pulumi
- 云原生的未來
- Kubernetes架構
- 設計理念
- Etcd解析
- 開放接口
- CRI - Container Runtime Interface(容器運行時接口)
- CNI - Container Network Interface(容器網絡接口)
- CSI - Container Storage Interface(容器存儲接口)
- Kubernetes中的網絡
- Kubernetes中的網絡解析——以flannel為例
- Kubernetes中的網絡解析——以calico為例
- 具備API感知的網絡和安全性管理開源軟件Cilium
- Cilium架構設計與概念解析
- 資源對象與基本概念解析
- Pod狀態與生命周期管理
- Pod概覽
- Pod解析
- Init容器
- Pause容器
- Pod安全策略
- Pod的生命周期
- Pod Hook
- Pod Preset
- Pod中斷與PDB(Pod中斷預算)
- 集群資源管理
- Node
- Namespace
- Label
- Annotation
- Taint和Toleration(污點和容忍)
- 垃圾收集
- 控制器
- Deployment
- StatefulSet
- DaemonSet
- ReplicationController和ReplicaSet
- Job
- CronJob
- Horizontal Pod Autoscaling
- 自定義指標HPA
- 準入控制器(Admission Controller)
- 服務發現
- Service
- Ingress
- Traefik Ingress Controller
- 身份與權限控制
- ServiceAccount
- RBAC——基于角色的訪問控制
- NetworkPolicy
- 存儲
- Secret
- ConfigMap
- ConfigMap的熱更新
- Volume
- Persistent Volume(持久化卷)
- Storage Class
- 本地持久化存儲
- 集群擴展
- 使用自定義資源擴展API
- 使用CRD擴展Kubernetes API
- Aggregated API Server
- APIService
- Service Catalog
- 資源調度
- QoS(服務質量等級)
- 用戶指南
- 資源對象配置
- 配置Pod的liveness和readiness探針
- 配置Pod的Service Account
- Secret配置
- 管理namespace中的資源配額
- 命令使用
- Docker用戶過度到kubectl命令行指南
- kubectl命令概覽
- kubectl命令技巧大全
- 使用etcdctl訪問kubernetes數據
- 集群安全性管理
- 管理集群中的TLS
- kubelet的認證授權
- TLS bootstrap
- 創建用戶認證授權的kubeconfig文件
- IP偽裝代理
- 使用kubeconfig或token進行用戶身份認證
- Kubernetes中的用戶與身份認證授權
- Kubernetes集群安全性配置最佳實踐
- 訪問Kubernetes集群
- 訪問集群
- 使用kubeconfig文件配置跨集群認證
- 通過端口轉發訪問集群中的應用程序
- 使用service訪問群集中的應用程序
- 從外部訪問Kubernetes中的Pod
- Cabin - Kubernetes手機客戶端
- Kubernetic - Kubernetes桌面客戶端
- Kubernator - 更底層的Kubernetes UI
- 在Kubernetes中開發部署應用
- 適用于kubernetes的應用開發部署流程
- 遷移傳統應用到Kubernetes中——以Hadoop YARN為例
- 最佳實踐概覽
- 在CentOS上部署Kubernetes集群
- 創建TLS證書和秘鑰
- 創建kubeconfig文件
- 創建高可用etcd集群
- 安裝kubectl命令行工具
- 部署master節點
- 安裝flannel網絡插件
- 部署node節點
- 安裝kubedns插件
- 安裝dashboard插件
- 安裝heapster插件
- 安裝EFK插件
- 生產級的Kubernetes簡化管理工具kubeadm
- 使用kubeadm在Ubuntu Server 16.04上快速構建測試集群
- 服務發現與負載均衡
- 安裝Traefik ingress
- 分布式負載測試
- 網絡和集群性能測試
- 邊緣節點配置
- 安裝Nginx ingress
- 安裝配置DNS
- 安裝配置Kube-dns
- 安裝配置CoreDNS
- 運維管理
- Master節點高可用
- 服務滾動升級
- 應用日志收集
- 配置最佳實踐
- 集群及應用監控
- 數據持久化問題
- 管理容器的計算資源
- 集群聯邦
- 存儲管理
- GlusterFS
- 使用GlusterFS做持久化存儲
- 使用Heketi作為Kubernetes的持久存儲GlusterFS的external provisioner
- 在OpenShift中使用GlusterFS做持久化存儲
- GlusterD-2.0
- Ceph
- 用Helm托管安裝Ceph集群并提供后端存儲
- 使用Ceph做持久化存儲
- 使用rbd-provisioner提供rbd持久化存儲
- OpenEBS
- 使用OpenEBS做持久化存儲
- Rook
- NFS
- 利用NFS動態提供Kubernetes后端存儲卷
- 集群與應用監控
- Heapster
- 使用Heapster獲取集群和對象的metric數據
- Prometheus
- 使用Prometheus監控kubernetes集群
- Prometheus查詢語言PromQL使用說明
- 使用Vistio監控Istio服務網格中的流量
- 分布式跟蹤
- OpenTracing
- 服務編排管理
- 使用Helm管理Kubernetes應用
- 構建私有Chart倉庫
- 持續集成與發布
- 使用Jenkins進行持續集成與發布
- 使用Drone進行持續集成與發布
- 更新與升級
- 手動升級Kubernetes集群
- 升級dashboard
- 領域應用概覽
- 微服務架構
- 微服務中的服務發現
- 使用Java構建微服務并發布到Kubernetes平臺
- Spring Boot快速開始指南
- Service Mesh 服務網格
- 企業級服務網格架構
- Service Mesh基礎
- Service Mesh技術對比
- 采納和演進
- 定制和集成
- 總結
- Istio
- 安裝并試用Istio service mesh
- 配置請求的路由規則
- 安裝和拓展Istio service mesh
- 集成虛擬機
- Istio中sidecar的注入規范及示例
- 如何參與Istio社區及注意事項
- Istio教程
- Istio免費學習資源匯總
- 深入理解Istio Service Mesh中的Envoy Sidecar注入與流量劫持
- 深入理解Istio Service Mesh中的Envoy Sidecar代理的路由轉發
- Linkerd
- Linkerd 使用指南
- Conduit
- Condiut概覽
- 安裝Conduit
- Envoy
- Envoy的架構與基本術語
- Envoy作為前端代理
- Envoy mesh教程
- SOFAMesh
- SOFAMesh中的Dubbo on x-protocol
- SOFAMosn
- 使用 SOFAMosn 構建 SOFAMesh
- 大數據
- Spark standalone on Kubernetes
- 運行支持Kubernetes原生調度的Spark程序
- Serverless架構
- 理解Serverless
- FaaS-函數即服務
- OpenFaaS快速入門指南
- 邊緣計算
- 人工智能