為 Pod 配置服務賬號
Kubernetes 為在叢集中執行的客戶端,或者與叢集的控制平面有關係的客戶端,提供了兩種不同的方式來向 API 伺服器進行身份驗證。
一個_服務賬戶_為 Pod 中執行的程序提供身份,並對映到 ServiceAccount 物件。當你向 API 伺服器進行身份驗證時,你將自己標識為一個特定的_使用者_。Kubernetes 承認使用者的概念,但是 Kubernetes 本身**不**具有使用者 API。
本任務指南是關於 Kubernetes API 中確實存在的 ServiceAccount。本指南向你展示了一些為 Pod 配置 ServiceAccount 的方法。
準備工作
你需要一個 Kubernetes 叢集,並且 `kubectl` 命令列工具必須配置為與你的叢集通訊。建議在至少有兩個不充當控制平面主機的節點組成的叢集上執行本教程。如果你還沒有叢集,可以使用 minikube 建立一個,或者使用這些 Kubernetes 線上演練:
使用預設服務賬戶訪問 API 伺服器
當 Pod 訪問 API 伺服器時,Pod 會以特定的 ServiceAccount(例如 `default`)進行身份驗證。每個名稱空間中始終至少有一個 ServiceAccount。
每個 Kubernetes 名稱空間都包含至少一個 ServiceAccount:該名稱空間的預設 ServiceAccount,名為 `default`。如果你在建立 Pod 時沒有指定 ServiceAccount,Kubernetes 會自動分配該名稱空間中名為 `default` 的 ServiceAccount。
你可以獲取已建立 Pod 的詳細資訊。例如:
kubectl get pods/<podname> -o yaml
在輸出中,你會看到一個欄位 `spec.serviceAccountName`。如果你在建立 Pod 時沒有指定,Kubernetes 會自動設定該值。
在 Pod 中執行的應用程式可以使用自動掛載的服務賬戶憑據訪問 Kubernetes API。參閱訪問叢集以瞭解更多資訊。
當 Pod 以 ServiceAccount 進行身份驗證時,其訪問級別取決於正在使用的授權外掛和策略。
Pod 刪除後,API 憑據會自動撤銷,即使存在 finalizer 也是如此。具體來說,API 憑據在 Pod 上設定的 `metadata.deletionTimestamp` (刪除時間戳通常是接受**刪除**請求的時間加上 Pod 的終止寬限期) 後 60 秒撤銷。
選擇不自動掛載 API 憑據
如果你不希望 kubelet 自動掛載 ServiceAccount 的 API 憑據,你可以選擇退出預設行為。你可以透過在 ServiceAccount 上設定 `automountServiceAccountToken: false` 來選擇不自動掛載 ServiceAccount 的 API 憑據到 `/var/run/secrets/kubernetes.io/serviceaccount/token`。
例如
apiVersion: v1
kind: ServiceAccount
metadata:
name: build-robot
automountServiceAccountToken: false
...
你也可以選擇不為特定 Pod 自動掛載 API 憑據:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
serviceAccountName: build-robot
automountServiceAccountToken: false
...
如果 ServiceAccount 和 Pod 的 `spec` 都為 `automountServiceAccountToken` 指定了一個值,則 Pod 的規約優先。
使用多個 ServiceAccount
每個名稱空間至少有一個 ServiceAccount:預設的 ServiceAccount 資源,名為 `default`。你可以使用以下命令列出當前名稱空間中的所有 ServiceAccount 資源:
kubectl get serviceaccounts
輸出類似於:
NAME SECRETS AGE
default 1 1d
你可以像這樣建立額外的 ServiceAccount 物件:
kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: build-robot
EOF
ServiceAccount 物件的名稱必須是有效的 DNS 子域名。
如果你獲取服務賬戶物件的完整轉儲,像這樣:
kubectl get serviceaccounts/build-robot -o yaml
輸出類似於:
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: 2019-06-16T00:12:34Z
name: build-robot
namespace: default
resourceVersion: "272500"
uid: 721ab723-13bc-11e5-aec2-42010af0021e
你可以使用授權外掛設定服務賬戶的許可權。
要使用非預設服務賬戶,請將 Pod 的 `spec.serviceAccountName` 欄位設定為你要使用的 ServiceAccount 的名稱。
你只能在建立 Pod 時或在新的 Pod 模板中設定 `serviceAccountName` 欄位。你不能更新已存在的 Pod 的 `.spec.serviceAccountName` 欄位。
注意
`.spec.serviceAccount` 欄位是 `.spec.serviceAccountName` 的已棄用別名。如果你想從工作負載資源中刪除這些欄位,請在 Pod 模板上明確地將這兩個欄位設定為空。清理
如果你嘗試從上面的示例中建立 `build-robot` ServiceAccount,可以透過執行以下命令進行清理:
kubectl delete serviceaccount/build-robot
手動為 ServiceAccount 建立 API 令牌
假設你有一個名為“build-robot”的現有服務賬戶,如前所述。
你可以使用 `kubectl` 獲取該 ServiceAccount 的有時效性 API 令牌:
kubectl create token build-robot
該命令的輸出是一個令牌,你可以使用它作為該 ServiceAccount 進行身份驗證。你可以使用 `kubectl create token` 命令的 `--duration` 命令列引數請求特定的令牌持續時間(發行的令牌的實際持續時間可能更短,甚至可能更長)。
Kubernetes v1.33 [stable]
(預設啟用:true)使用 `kubectl` v1.31 或更高版本,可以建立直接繫結到節點的 ServiceAccount 令牌:
kubectl create token build-robot --bound-object-kind Node --bound-object-name node-001 --bound-object-uid 123...456
令牌將一直有效,直到過期或關聯的節點或服務賬戶被刪除。
注意
Kubernetes v1.22 之前的版本會自動建立用於訪問 Kubernetes API 的長期憑據。這種舊機制是基於建立令牌 Secret,然後可以將這些 Secret 掛載到執行中的 Pod。在包括 Kubernetes v1.34 在內的最新版本中,API 憑據透過使用 TokenRequest API 直接獲取,並透過投影卷掛載到 Pod 中。透過這種方法獲得的令牌具有有限的生命週期,並在掛載它們的 Pod 被刪除時自動失效。
你仍然可以手動建立服務賬戶令牌 Secret;例如,如果你需要一個永不過期的令牌。然而,建議改用 TokenRequest 子資源來獲取訪問 API 的令牌。
手動建立 ServiceAccount 的長期 API 令牌
如果你想獲取 ServiceAccount 的 API 令牌,你可以建立一個帶有特殊註解 `kubernetes.io/service-account.name` 的新 Secret。
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: build-robot-secret
annotations:
kubernetes.io/service-account.name: build-robot
type: kubernetes.io/service-account-token
EOF
如果你使用以下命令檢視 Secret:
kubectl get secret/build-robot-secret -o yaml
你可以看到 Secret 現在包含“build-robot”ServiceAccount 的 API 令牌。
由於你設定的註解,控制平面會自動為該 ServiceAccount 生成一個令牌,並將其儲存在關聯的 Secret 中。控制平面還會清理已刪除 ServiceAccount 的令牌。
kubectl describe secrets/build-robot-secret
輸出類似於:
Name: build-robot-secret
Namespace: default
Labels: <none>
Annotations: kubernetes.io/service-account.name: build-robot
kubernetes.io/service-account.uid: da68f9c6-9d26-11e7-b84e-002dc52800da
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1338 bytes
namespace: 7 bytes
token: ...
注意
這裡省略了 `token` 的內容。
請注意不要在終端/電腦螢幕可能被旁觀者看到的地方顯示 `kubernetes.io/service-account-token` Secret 的內容。
當你刪除一個關聯了 Secret 的 ServiceAccount 時,Kubernetes 控制平面會自動從該 Secret 中清理掉長期令牌。
注意
如果你使用以下命令檢視 ServiceAccount:
kubectl get serviceaccount build-robot -o yaml
你無法在 ServiceAccount API 物件的`secrets` 欄位中看到 `build-robot-secret` Secret,因為該欄位只填充自動生成的 Secret。
向服務賬戶新增 ImagePullSecrets
首先,建立一個 imagePullSecret。然後,驗證它是否已建立。例如:
建立一個 imagePullSecret,如在 Pod 上指定 ImagePullSecrets 中所述。
kubectl create secret docker-registry myregistrykey --docker-server=<registry name> \ --docker-username=DUMMY_USERNAME --docker-password=DUMMY_DOCKER_PASSWORD \ --docker-email=DUMMY_DOCKER_EMAIL
驗證它是否已建立。
kubectl get secrets myregistrykey
輸出類似於:
NAME TYPE DATA AGE myregistrykey kubernetes.io/.dockerconfigjson 1 1d
將映象拉取 Secret 新增到服務賬戶
接下來,修改名稱空間的預設服務賬戶,以使用此 Secret 作為 imagePullSecret。
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "myregistrykey"}]}'
你可以透過手動編輯物件實現相同的效果:
kubectl edit serviceaccount/default
`sa.yaml` 檔案的輸出類似於:
你選擇的文字編輯器將開啟,配置看起來像這樣:
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: 2021-07-07T22:02:39Z
name: default
namespace: default
resourceVersion: "243024"
uid: 052fb0f4-3d50-11e5-b066-42010af0d7b6
使用你的編輯器,刪除帶有鍵 `resourceVersion` 的行,新增 `imagePullSecrets:` 的行並儲存。保持 `uid` 值與你找到的相同。
進行這些更改後,編輯後的 ServiceAccount 看起來像這樣:
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: 2021-07-07T22:02:39Z
name: default
namespace: default
uid: 052fb0f4-3d50-11e5-b066-42010af0d7b6
imagePullSecrets:
- name: myregistrykey
驗證新 Pod 是否已設定 imagePullSecrets
現在,當在當前名稱空間中使用預設 ServiceAccount 建立新 Pod 時,新 Pod 的 `spec.imagePullSecrets` 欄位會自動設定:
kubectl run nginx --image=<registry name>/nginx --restart=Never
kubectl get pod nginx -o=jsonpath='{.spec.imagePullSecrets[0].name}{"\n"}'
輸出為:
myregistrykey
服務賬戶令牌卷投影
Kubernetes v1.20 [stable]
注意
要啟用和使用令牌請求投影,你必須為 `kube-apiserver` 指定以下每個命令列引數:
--service-account-issuer
- 定義服務賬戶令牌頒發者的識別符號。你可以多次指定 `--service-account-issuer` 引數,這有助於實現頒發者的非破壞性更改。當此標誌多次指定時,第一個用於生成令牌,所有其他都用於確定接受哪些頒發者。你必須執行 Kubernetes v1.22 或更高版本才能多次指定 `--service-account-issuer`。
--service-account-key-file
- 指定一個檔案路徑,該檔案包含 PEM 編碼的 X.509 私鑰或公鑰(RSA 或 ECDSA),用於驗證 ServiceAccount 令牌。指定的檔案可以包含多個金鑰,並且可以多次指定該標誌以使用不同的檔案。如果多次指定,Kubernetes API 伺服器會將由任何指定金鑰簽名的令牌視為有效。
--service-account-signing-key-file
- 指定一個檔案路徑,該檔案包含服務賬戶令牌頒發者的當前私鑰。頒發者使用此私鑰簽署頒發的 ID 令牌。
- `--api-audiences`(可省略)
- 定義 ServiceAccount 令牌的受眾。ServiceAccount 令牌身份驗證器驗證用於 API 的令牌是否繫結到這些受眾中的至少一個。如果多次指定 `api-audiences`,則 Kubernetes API 伺服器將針對任何指定受眾的令牌視為有效。如果你指定了 `--service-account-issuer` 命令列引數但未設定 `--api-audiences`,則控制平面預設使用只包含頒發者 URL 的單元素受眾列表。
kubelet 還可以將 ServiceAccount 令牌投影到 Pod 中。你可以指定令牌的所需屬性,例如受眾和有效期。這些屬性在預設 ServiceAccount 令牌上是**不可**配置的。當 Pod 或 ServiceAccount 被刪除時,令牌也將對 API 失效。
你可以使用名為 `ServiceAccountToken` 的投影卷型別,為 Pod 的 `spec` 配置此行為。
此投影卷中的令牌是一個 JSON Web Token (JWT)。此令牌的 JSON 有效負載遵循定義明確的架構——一個 Pod 繫結令牌的有效負載示例:
{
"aud": [ # matches the requested audiences, or the API server's default audiences when none are explicitly requested
"https://kubernetes.default.svc"
],
"exp": 1731613413,
"iat": 1700077413,
"iss": "https://kubernetes.default.svc", # matches the first value passed to the --service-account-issuer flag
"jti": "ea28ed49-2e11-4280-9ec5-bc3d1d84661a",
"kubernetes.io": {
"namespace": "kube-system",
"node": {
"name": "127.0.0.1",
"uid": "58456cb0-dd00-45ed-b797-5578fdceaced"
},
"pod": {
"name": "coredns-69cbfb9798-jv9gn",
"uid": "778a530c-b3f4-47c0-9cd5-ab018fb64f33"
},
"serviceaccount": {
"name": "coredns",
"uid": "a087d5a0-e1dd-43ec-93ac-f13d89cd13af"
},
"warnafter": 1700081020
},
"nbf": 1700077413,
"sub": "system:serviceaccount:kube-system:coredns"
}
使用服務賬戶令牌投影啟動 Pod
為了向 Pod 提供一個受眾為 `vault` 且有效期為兩小時的令牌,你可以定義一個類似於以下內容的 Pod 清單:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /var/run/secrets/tokens
name: vault-token
serviceAccountName: build-robot
volumes:
- name: vault-token
projected:
sources:
- serviceAccountToken:
path: vault-token
expirationSeconds: 7200
audience: vault
建立 Pod
kubectl create -f https://k8s.io/examples/pods/pod-projected-svc-token.yaml
kubelet 將:代表 Pod 請求並存儲令牌;將令牌透過可配置的檔案路徑提供給 Pod;並在令牌接近過期時重新整理它。如果令牌的有效期超過其總生命週期 (TTL) 的 80%,或者令牌超過 24 小時,kubelet 會主動請求輪換令牌。
應用程式負責在令牌輪換時重新載入令牌。對於應用程式來說,按計劃載入令牌(例如:每 5 分鐘一次),而不跟蹤實際過期時間,通常就足夠了。
服務賬戶頒發者發現
Kubernetes v1.21 [stable]
如果已在叢集中為 ServiceAccount 啟用了令牌投影,那麼你還可以使用發現功能。Kubernetes 提供了一種客戶端作為_身份提供者_進行聯邦的方式,以便一個或多個外部系統可以充當_依賴方_。
注意
頒發者 URL 必須符合 OIDC 發現規範。實際上,這意味著它必須使用 `https` 方案,並且應在 `{service-account-issuer}/.well-known/openid-configuration` 提供 OpenID 提供者配置。
如果 URL 不符合要求,則 ServiceAccount 頒發者發現端點將不會註冊或無法訪問。
啟用後,Kubernetes API 伺服器透過 HTTP 釋出 OpenID Provider Configuration 文件。該配置文件釋出在 `/.well-known/openid-configuration`。OpenID Provider Configuration 有時被稱為_發現文件_。Kubernetes API 伺服器還會透過 HTTP 在 `/openid/v1/jwks` 釋出相關的 JSON Web Key Set (JWKS)。
注意
`/.well-known/openid-configuration` 和 `/openid/v1/jwks` 響應設計為與 OIDC 相容,但並非嚴格符合 OIDC。這些文件僅包含驗證 Kubernetes 服務賬戶令牌所需的引數。使用 RBAC 的叢集包含一個名為 `system:service-account-issuer-discovery` 的預設 ClusterRole。一個預設的 ClusterRoleBinding 將此角色分配給 `system:serviceaccounts` 組,所有 ServiceAccount 都隱式屬於該組。這允許在叢集上執行的 Pod 透過其掛載的服務賬戶令牌訪問服務賬戶發現文件。管理員還可以根據其安全要求以及他們打算與之聯邦的外部系統,選擇將該角色繫結到 `system:authenticated` 或 `system:unauthenticated`。
JWKS 響應包含依賴方可用於驗證 Kubernetes 服務賬戶令牌的公鑰。依賴方首先查詢 OpenID Provider Configuration,並使用響應中的 `jwks_uri` 欄位查詢 JWKS。
在許多情況下,Kubernetes API 伺服器無法在公共網際網路上訪問,但使用者或服務提供商可以提供從 API 伺服器快取響應的公共端點。在這些情況下,可以透過向 API 伺服器傳遞 `--service-account-jwks-uri` 標誌來覆蓋 OpenID Provider Configuration 中的 `jwks_uri`,使其指向公共端點,而不是 API 伺服器的地址。與頒發者 URL 一樣,JWKS URI 要求使用 `https` 方案。
下一步
另請參閱
- 閱讀服務賬戶的叢集管理員指南
- 閱讀有關 Kubernetes 中的授權
- 閱讀有關 Secret
- 或學習使用 Secret 安全分發憑據
- 但也要記住,使用 Secret 進行 ServiceAccount 身份驗證已棄用。推薦的替代方案是ServiceAccount 令牌卷投影。
- 閱讀有關 投影卷。
- 有關 OIDC 發現的背景知識,請閱讀 ServiceAccount 簽名金鑰檢索 Kubernetes 增強提案
- 閱讀 OIDC 發現規範