為 Pod 配置服務帳戶

Kubernetes 提供兩種不同的方式,讓叢集內執行的用戶端,或與叢集控制平面有關係的其他用戶端,可以向 API 伺服器驗證身分。

服務帳戶為在 Pod 中執行的程序提供身分,並對應到 ServiceAccount 物件。當您向 API 伺服器驗證身分時,您會將自己識別為特定的使用者。Kubernetes 認知使用者的概念,但是,Kubernetes 本身沒有 User API。

本任務指南是有關 ServiceAccount,其存在於 Kubernetes API 中。本指南向您展示一些為 Pod 配置 ServiceAccount 的方法。

準備開始

您需要有一個 Kubernetes 叢集,而且必須將 kubectl 命令列工具設定為與您的叢集通訊。建議在至少有兩個節點的叢集上執行本教學課程,這些節點不作為控制平面主機。如果您還沒有叢集,可以使用 minikube 建立一個,或者您可以使用這些 Kubernetes Playground 之一

使用預設服務帳戶存取 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 憑證也會自動撤銷。特別是,API 憑證會在 Pod 上設定的 .metadata.deletionTimestamp 之後 60 秒撤銷(刪除時間戳記通常是刪除請求被接受的時間加上 Pod 的終止寬限期)。

選擇不使用 API 憑證自動掛載

如果您不希望 kubelet 自動掛載 ServiceAccount 的 API 憑證,您可以選擇不使用預設行為。您可以透過在 ServiceAccount 上設定 automountServiceAccountToken: false,來選擇不自動掛載 /var/run/secrets/kubernetes.io/serviceaccount/token 上服務帳戶的 API 憑證

例如

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:名為 default 的預設 ServiceAccount 資源。您可以使用以下指令,列出目前命名空間中的所有 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 子網域名稱

如果您取得 Service Account 物件的完整傾印,會像這樣:

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

您可以使用授權外掛程式來設定 Service Account 的權限

若要使用非預設的 Service Account,請將 Pod 的 spec.serviceAccountName 欄位設定為您想要使用的 ServiceAccount 名稱。

您只能在建立 Pod 時,或是在新 Pod 的範本中設定 serviceAccountName 欄位。您無法更新已存在 Pod 的 .spec.serviceAccountName 欄位。

清除

如果您嘗試從上面的範例中建立 build-robot ServiceAccount,您可以使用以下指令來清除它:

kubectl delete serviceaccount/build-robot

為 ServiceAccount 手動建立 API 權杖

假設您有一個名為 "build-robot" 的現有 Service Account,如先前所述。

您可以使用 kubectl 為該 ServiceAccount 取得有時間限制的 API 權杖

kubectl create token build-robot

該指令的輸出是一個權杖,您可以使用該權杖以該 ServiceAccount 的身分進行驗證。您可以使用 kubectl create token--duration 命令列引數請求特定的權杖持續時間(發出的權杖的實際持續時間可能會更短,甚至可能更長)。

功能狀態: Kubernetes v1.31 [beta](預設啟用:true)

使用 kubectl v1.31 或更高版本,可以建立直接繫結到節點 (Node) 的 Service Account 權杖

kubectl create token build-robot --bound-object-kind Node --bound-object-name node-001 --bound-object-uid 123...456

權杖將在到期或關聯的節點或 Service Account 被刪除之前有效。

為 ServiceAccount 手動建立長期有效的 API 權杖

如果您想要取得 ServiceAccount 的 API 權杖,您可以建立一個新的 Secret,並帶有一個特殊的註解 kubernetes.io/service-account.name

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:          ...

當您刪除具有關聯 Secret 的 ServiceAccount 時,Kubernetes 控制平面會自動從該 Secret 中清除長期有效的權杖。

將 ImagePullSecrets 新增至 Service Account

首先,建立 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
    

將 image pull secret 新增至 Service Account

接下來,修改命名空間的預設 Service Account,以使用此 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

現在,當在目前的命名空間中建立新的 Pod 並使用預設 ServiceAccount 時,新的 Pod 會自動設定其 spec.imagePullSecrets 欄位

kubectl run nginx --image=<registry name>/nginx --restart=Never
kubectl get pod nginx -o=jsonpath='{.spec.imagePullSecrets[0].name}{"\n"}'

輸出結果為:

myregistrykey

ServiceAccount 權杖卷投影

功能狀態: Kubernetes v1.20 [stable]

kubelet 也可以將 ServiceAccount 權杖投影到 Pod 中。您可以指定權杖的所需屬性,例如對象和有效期限。這些屬性在預設 ServiceAccount 權杖上是不可設定的。當 Pod 或 ServiceAccount 被刪除時,權杖也會對 API 失效。

您可以使用名為 ServiceAccountToken投影卷類型,為 Pod 的 spec 設定此行為。

來自此投影卷的權杖是 JSON Web 權杖 (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"
}

啟動使用 Service Account 權杖投影的 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 分鐘一次),而無需追蹤實際的到期時間,就已足夠。

Service Account 簽發者探索

功能狀態: Kubernetes v1.21 [stable]

如果您已為叢集中的 ServiceAccount 啟用權杖投影,那麼您也可以使用探索功能。Kubernetes 提供了一種讓用戶端可以作為身分提供者聯合的方式,以便一個或多個外部系統可以充當依賴方

啟用後,Kubernetes API 伺服器會透過 HTTP 發布 OpenID 提供者組態文件。組態文件發布在 /.well-known/openid-configuration。OpenID 提供者組態有時被稱為探索文件。Kubernetes API 伺服器也會透過 HTTP 在 /openid/v1/jwks 發布相關的 JSON Web 金鑰集 (JWKS)。

使用 RBAC 的叢集包含名為 system:service-account-issuer-discovery 的預設 ClusterRole。預設的 ClusterRoleBinding 會將此角色指派給 system:serviceaccounts 群組,所有 ServiceAccount 都隱含地屬於該群組。這允許在叢集上執行的 Pod 透過它們掛載的 Service Account 權杖存取 Service Account 探索文件。管理員還可以選擇將角色繫結到 system:authenticatedsystem:unauthenticated,具體取決於其安全性需求以及他們打算與哪些外部系統聯合。

JWKS 回應包含依賴方可以用於驗證 Kubernetes Service Account 權杖的公鑰。依賴方首先查詢 OpenID 提供者組態,並使用回應中的 jwks_uri 欄位來尋找 JWKS。

在許多情況下,Kubernetes API 伺服器在公共網際網路上不可用,但使用者或服務提供者可以提供從 API 伺服器提供快取回應的公共端點。在這些情況下,可以覆寫 OpenID 提供者組態中的 jwks_uri,使其指向公共端點,而不是 API 伺服器的位址,方法是將 --service-account-jwks-uri 標誌傳遞給 API 伺服器。與簽發者 URL 一樣,JWKS URI 也必須使用 https 協定。

下一步

另請參閱