Kubernetes 為Pod配置服務(wù)賬戶(hù)

2022-06-10 11:05 更新

為 Pod 配置服務(wù)賬戶(hù)

服務(wù)賬戶(hù)為 Pod 中運(yùn)行的進(jìn)程提供了一個(gè)標(biāo)識(shí)。

Note: 本文是服務(wù)賬戶(hù)的用戶(hù)使用介紹,描述服務(wù)賬號(hào)在集群中如何起作用。 你的集群管理員可能已經(jīng)對(duì)你的集群做了定制,因此導(dǎo)致本文中所講述的內(nèi)容并不適用。

當(dāng)你(自然人)訪問(wèn)集群時(shí)(例如,使用 ?kubectl?),API 服務(wù)器將你的身份驗(yàn)證為 特定的用戶(hù)帳戶(hù)(當(dāng)前這通常是 ?admin?,除非你的集群管理員已經(jīng)定制了你的集群配置)。 Pod 內(nèi)的容器中的進(jìn)程也可以與 api 服務(wù)器接觸。 當(dāng)它們進(jìn)行身份驗(yàn)證時(shí),它們被驗(yàn)證為特定的服務(wù)帳戶(hù)(例如,?default?)。

在開(kāi)始之前

你必須擁有一個(gè) Kubernetes 的集群,同時(shí)你的 Kubernetes 集群必須帶有 kubectl 命令行工具。 建議在至少有兩個(gè)節(jié)點(diǎn)的集群上運(yùn)行本教程,且這些節(jié)點(diǎn)不作為控制平面主機(jī)。 如果你還沒(méi)有集群,你可以通過(guò) Minikube 構(gòu)建一個(gè)你自己的集群,或者你可以使用下面任意一個(gè) Kubernetes 工具構(gòu)建:

要檢查版本,請(qǐng)輸入 ?kubectl version?。

使用默認(rèn)的服務(wù)賬戶(hù)訪問(wèn) API 服務(wù)器

當(dāng)你創(chuàng)建 Pod 時(shí),如果沒(méi)有指定服務(wù)賬戶(hù),Pod 會(huì)被指定給命名空間中的 ?default ?服務(wù)賬戶(hù)。 如果你查看 Pod 的原始 JSON 或 YAML(例如:?kubectl get pods/podname -o yaml?), 你可以看到 ?spec.serviceAccountName? 字段已經(jīng)被自動(dòng)設(shè)置了。

你可以使用自動(dòng)掛載給 Pod 的服務(wù)賬戶(hù)憑據(jù)訪問(wèn) API。 服務(wù)賬戶(hù)的 API 許可取決于你所使用的 鑒權(quán)插件和策略。

在 1.6 以上版本中,你可以通過(guò)在服務(wù)賬戶(hù)上設(shè)置 ?automountServiceAccountToken: false? 來(lái)實(shí)現(xiàn)不給服務(wù)賬號(hào)自動(dòng)掛載 API 憑據(jù):

apiVersion: v1
kind: ServiceAccount
metadata:
  name: build-robot
automountServiceAccountToken: false
...

在 1.6 以上版本中,你也可以選擇不給特定 Pod 自動(dòng)掛載 API 憑據(jù):

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  serviceAccountName: build-robot
  automountServiceAccountToken: false
  ...

如果 Pod 和服務(wù)賬戶(hù)都指定了 ?automountServiceAccountToken ?值,則 Pod 的 spec 優(yōu)先于服務(wù)帳戶(hù)。

使用多個(gè)服務(wù)賬戶(hù) 

每個(gè)命名空間都有一個(gè)名為 ?default ?的服務(wù)賬戶(hù)資源。 你可以用下面的命令查詢(xún)這個(gè)服務(wù)賬戶(hù)以及命名空間中的其他 ServiceAccount 資源:

kubectl get serviceAccounts

輸出類(lèi)似于:

NAME      SECRETS    AGE
default   1          1d

你可以像這樣來(lái)創(chuàng)建額外的 ServiceAccount 對(duì)象:

kubectl create -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
  name: build-robot
EOF

ServiceAccount 對(duì)象的名字必須是一個(gè)有效的 DNS 子域名.

如果你查詢(xún)服務(wù)帳戶(hù)對(duì)象的完整信息,如下所示:

kubectl get serviceaccounts/build-robot -o yaml

輸出類(lèi)似于:

apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: 2015-06-16T00:12:59Z
  name: build-robot
  namespace: default
  resourceVersion: "272500"
  uid: 721ab723-13bc-11e5-aec2-42010af0021e
secrets:
- name: build-robot-token-bvbk5

那么你就能看到系統(tǒng)已經(jīng)自動(dòng)創(chuàng)建了一個(gè)令牌并且被服務(wù)賬戶(hù)所引用。

你可以使用授權(quán)插件來(lái)設(shè)置服務(wù)賬戶(hù)的訪問(wèn)許可。

要使用非默認(rèn)的服務(wù)賬戶(hù),將 Pod 的 ?spec.serviceAccountName? 字段設(shè)置為你想用的服務(wù)賬戶(hù)名稱(chēng)。

Pod 被創(chuàng)建時(shí)服務(wù)賬戶(hù)必須存在,否則會(huì)被拒絕。

你不能更新已經(jīng)創(chuàng)建好的 Pod 的服務(wù)賬戶(hù)。

你可以清除服務(wù)賬戶(hù),如下所示:

kubectl delete serviceaccount/build-robot

手動(dòng)創(chuàng)建服務(wù)賬戶(hù) API 令牌 

假設(shè)我們有一個(gè)上面提到的名為 "build-robot" 的服務(wù)賬戶(hù),然后我們手動(dòng)創(chuàng)建一個(gè)新的 Secret。

kubectl create -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

現(xiàn)在,你可以確認(rèn)新構(gòu)建的 Secret 中填充了 "build-robot" 服務(wù)帳戶(hù)的 API 令牌。 令牌控制器將清理不存在的服務(wù)帳戶(hù)的所有令牌。

kubectl describe secrets/build-robot-secret

輸出類(lèi)似于:

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

Note: 這里省略了 ?token ?的內(nèi)容。

為服務(wù)賬戶(hù)添加 ImagePullSecrets 

創(chuàng)建 ImagePullSecret

  • 創(chuàng)建一個(gè) ImagePullSecret,如同為 Pod 設(shè)置 ImagePullSecret所述。
  • kubectl create secret docker-registry myregistrykey --docker-server=DUMMY_SERVER \
              --docker-username=DUMMY_USERNAME --docker-password=DUMMY_DOCKER_PASSWORD \
              --docker-email=DUMMY_DOCKER_EMAIL
  • 確認(rèn)創(chuàng)建成功:
  • kubectl get secrets myregistrykey
    

    輸出類(lèi)似于:

    NAME             TYPE                              DATA    AGE
    myregistrykey    kubernetes.io/.dockerconfigjson   1       1d

將鏡像拉取 Secret 添加到服務(wù)賬號(hào)

接著修改命名空間的 ?default ?服務(wù)帳戶(hù),以將該 Secret 用作 ?imagePullSecret?。

kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "myregistrykey"}]}'

你也可以使用 ?kubectl edit?,或者如下所示手動(dòng)編輯 YAML 清單:

kubectl get serviceaccounts default -o yaml > ./sa.yaml

?sa.yaml? 文件的內(nèi)容類(lèi)似于:

apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: 2015-08-07T22:02:39Z
  name: default
  namespace: default
  resourceVersion: "243024"
  uid: 052fb0f4-3d50-11e5-b066-42010af0d7b6
secrets:
- name: default-token-uudge

使用你常用的編輯器(例如 ?vi?),打開(kāi) ?sa.yaml? 文件,刪除帶有鍵名 ?resourceVersion ?的行,添加帶有 ?imagePullSecrets:? 的行,最后保存文件。

所得到的 ?sa.yaml? 文件類(lèi)似于:

apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: 2015-08-07T22:02:39Z
  name: default
  namespace: default
  uid: 052fb0f4-3d50-11e5-b066-42010af0d7b6
secrets:
- name: default-token-uudge
imagePullSecrets:
- name: myregistrykey

最后,用新的更新的 ?sa.yaml? 文件替換服務(wù)賬號(hào)。

kubectl replace serviceaccount default -f ./sa.yaml

驗(yàn)證鏡像拉取 Secret 已經(jīng)被添加到 Pod 規(guī)約 

現(xiàn)在,在當(dāng)前命名空間中創(chuàng)建使用默認(rèn)服務(wù)賬號(hào)的新 Pod 時(shí),新 Pod 會(huì)自動(dòng)設(shè)置其 ?.spec.imagePullSecrets? 字段:

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

輸出為:

myregistrykey

服務(wù)帳戶(hù)令牌卷投射 

FEATURE STATE: Kubernetes v1.20 [stable]

為了啟用令牌請(qǐng)求投射,你必須為 ?kube-apiserver? 設(shè)置以下命令行參數(shù):

  • ?--service-account-issuer ?
  • 此參數(shù)可作為服務(wù)賬戶(hù)令牌發(fā)放者的身份標(biāo)識(shí)(Identifier)。你可以多次指定 ?--service-account-issuer? 參數(shù),對(duì)于要變更發(fā)放者而又不想帶來(lái)業(yè)務(wù)中斷的場(chǎng)景, 這樣做是有用的。如果這個(gè)參數(shù)被多次指定,則第一個(gè)參數(shù)值會(huì)被用來(lái)生成令牌, 而所有參數(shù)值都會(huì)被用來(lái)確定哪些發(fā)放者是可接受的。你所運(yùn)行的 Kubernetes 集群必須是 v1.22 或更高版本,才能多次指定 ?--service-account-issuer?。

  • ?--service-account-key-file ?
  • 包含 PEM 編碼的 x509 RSA 或 ECDSA 私鑰或公鑰,用來(lái)檢查 ServiceAccount 的令牌。所指定的文件中可以包含多個(gè)秘鑰,并且你可以多次使用此參數(shù), 每次參數(shù)值為不同的文件。多次使用此參數(shù)時(shí),由所給的秘鑰之一簽名的令牌會(huì)被 Kubernetes API 服務(wù)器認(rèn)為是合法令牌。

  • ?--service-account-signing-key-file ?
  • 指向包含當(dāng)前服務(wù)賬戶(hù)令牌發(fā)放者的私鑰的文件路徑。 此發(fā)放者使用此私鑰來(lái)簽署所發(fā)放的 ID 令牌。

  • ?--api-audiences? (可以省略)

    服務(wù)賬號(hào)令牌身份檢查組件會(huì)檢查針對(duì) API 訪問(wèn)所使用的令牌, 確認(rèn)令牌至少是被綁定到這里所給的受眾(audiences)之一。 如果此參數(shù)被多次指定,則針對(duì)所給的多個(gè)受眾中任何目標(biāo)的令牌都會(huì)被 Kubernetes API 服務(wù)器當(dāng)做合法的令牌。如果 ?--service-account-issuer? 參數(shù)被設(shè)置,而這個(gè)參數(shù)未指定,則這個(gè)參數(shù)的默認(rèn)值為一個(gè)只有一個(gè)元素的列表, 且該元素為令牌發(fā)放者的 URL。

kubelet 還可以將服務(wù)帳戶(hù)令牌投射到 Pod 中。 你可以指定令牌的期望屬性,例如受眾和有效期限。 這些屬性在 default 服務(wù)帳戶(hù)令牌上無(wú)法配置。 當(dāng)刪除 Pod 或 ServiceAccount 時(shí),服務(wù)帳戶(hù)令牌也將對(duì) API 無(wú)效。

使用名為 ServiceAccountToken 的 ProjectedVolume 類(lèi)型在 PodSpec 上配置此功能。 要向 Pod 提供具有 "vault" 用戶(hù)以及兩個(gè)小時(shí)有效期的令牌,可以在 PodSpec 中配置以下內(nèi)容:

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

創(chuàng)建 Pod:

kubectl create -f https://k8s.io/examples/pods/pod-projected-svc-token.yaml

?kubelet ?組件會(huì)替 Pod 請(qǐng)求令牌并將其保存起來(lái), 通過(guò)將令牌存儲(chǔ)到一個(gè)可配置的路徑使之在 Pod 內(nèi)可用, 并在令牌快要到期的時(shí)候刷新它。 ?kubelet ?會(huì)在令牌存在期達(dá)到其 TTL 的 80% 的時(shí)候或者令牌生命期超過(guò) 24 小時(shí)的時(shí)候主動(dòng)輪換它。

應(yīng)用程序負(fù)責(zé)在令牌被輪換時(shí)重新加載其內(nèi)容。對(duì)于大多數(shù)使用場(chǎng)景而言, 周期性地(例如,每隔 5 分鐘)重新加載就足夠了。

發(fā)現(xiàn)服務(wù)賬號(hào)分發(fā)者

FEATURE STATE: Kubernetes v1.21 [stable]

當(dāng)啟用服務(wù)賬號(hào)令牌投射時(shí)啟用發(fā)現(xiàn)服務(wù)賬號(hào)分發(fā)者(Service Account Issuer Discovery) 這一功能特性,如上面的服務(wù)帳戶(hù)令牌卷投射所述。

分發(fā)者的 URL 必須遵從 OIDC 發(fā)現(xiàn)規(guī)范。 這意味著 URL 必須使用 ?https ?模式,并且必須在 ?{service-account-issuer}/.well-known/openid-configuration? 路徑給出 OpenID 提供者(Provider)配置。

如果 URL 沒(méi)有遵從這一規(guī)范,?ServiceAccountIssuerDiscovery ?末端就不會(huì)被注冊(cè), 即使該特性已經(jīng)被啟用。

發(fā)現(xiàn)服務(wù)賬號(hào)分發(fā)者這一功能使得用戶(hù)能夠用聯(lián)邦的方式結(jié)合使用 Kubernetes 集群(“Identity Provider”,標(biāo)識(shí)提供者)與外部系統(tǒng)(“Relying Parties”, 依賴(lài)方)所分發(fā)的服務(wù)賬號(hào)令牌。

當(dāng)此功能被啟用時(shí),Kubernetes API 服務(wù)器會(huì)在 ?/.well-known/openid-configuration? 提供一個(gè) OpenID 提供者配置文檔,并在 ?/openid/v1/jwks? 處提供與之關(guān)聯(lián)的 JSON Web Key Set(JWKS)。 這里的 OpenID 提供者配置有時(shí)候也被稱(chēng)作“發(fā)現(xiàn)文檔(Discovery Document)”。

集群包括一個(gè)的默認(rèn) RBAC ClusterRole, 名為 ?system:service-account-issuer-discovery?。 默認(rèn)的 RBAC ClusterRoleBinding 將此角色分配給 ?system:serviceaccounts? 組, 所有服務(wù)帳戶(hù)隱式屬于該組。這使得集群上運(yùn)行的 Pod 能夠通過(guò)它們所掛載的服務(wù)帳戶(hù)令牌訪問(wèn)服務(wù)帳戶(hù)發(fā)現(xiàn)文檔。 此外,管理員可以根據(jù)其安全性需要以及期望集成的外部系統(tǒng)選擇是否將該角色綁定到 ?system:authenticated? 或 ?system:unauthenticated?。

對(duì) ?/.well-known/openid-configuration? 和 ?/openid/v1/jwks? 路徑請(qǐng)求的響應(yīng) 被設(shè)計(jì)為與 OIDC 兼容,但不是完全與其一致。 返回的文檔僅包含對(duì) Kubernetes 服務(wù)賬號(hào)令牌進(jìn)行驗(yàn)證所必須的參數(shù)。

JWKS 響應(yīng)包含依賴(lài)方可以用來(lái)驗(yàn)證 Kubernetes 服務(wù)賬號(hào)令牌的公鑰數(shù)據(jù)。 依賴(lài)方先會(huì)查詢(xún) OpenID 提供者配置,之后使用返回響應(yīng)中的 ?jwks_uri ?來(lái)查找 JWKS。

在很多場(chǎng)合,Kubernetes API 服務(wù)器都不會(huì)暴露在公網(wǎng)上,不過(guò)對(duì)于緩存并向外提供 API 服務(wù)器響應(yīng)數(shù)據(jù)的公開(kāi)末端而言,用戶(hù)或者服務(wù)提供商可以選擇將其暴露在公網(wǎng)上。 在這種環(huán)境中,可能會(huì)重載 OpenID 提供者配置中的 ?jwks_uri?,使之指向公網(wǎng)上可用的末端地址,而不是 API 服務(wù)器的地址。 這時(shí)需要向 API 服務(wù)器傳遞 ?--service-account-jwks-uri? 參數(shù)。 與分發(fā)者 URL 類(lèi)似,此 JWKS URI 也需要使用 ?https ?模式。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)