認證
本頁面概述了 Kubernetes 中的身份驗證,重點是針對 Kubernetes API 的身份驗證。
Kubernetes 中的使用者
所有 Kubernetes 叢集都有兩類使用者:由 Kubernetes 管理的服務賬號和普通使用者。
假設一個叢集獨立的管理服務透過以下方式管理普通使用者
- 管理員分發私鑰
- 使用者儲存,如 Keystone 或 Google 賬號
- 包含使用者名稱和密碼列表的檔案
在這方面,Kubernetes 沒有代表普通使用者賬號的物件。 普通使用者無法透過 API 呼叫新增到叢集中。
儘管普通使用者無法透過 API 呼叫新增,但任何提供由叢集證書頒發機構 (CA) 簽名的有效證書的使用者都被視為已透過身份驗證。在此配置中,Kubernetes 從證書主題的通用名稱欄位(例如,“/CN=bob”)確定使用者名稱。然後,基於角色的訪問控制 (RBAC) 子系統將確定該使用者是否有權對資源執行特定操作。
相比之下,服務賬號是由 Kubernetes API 管理的使用者。它們繫結到特定的名稱空間,並由 API 伺服器自動建立或透過 API 呼叫手動建立。服務賬號與一組儲存為 Secrets
的憑據相關聯,這些憑據被掛載到 Pod 中,允許叢集內程序與 Kubernetes API 通訊。
API 請求要麼繫結到普通使用者,要麼繫結到服務賬號,要麼被視為 匿名請求。這意味著叢集內外的所有程序,從工作站上鍵入 kubectl
的人類使用者,到節點上的 kubelets
,再到控制平面的成員,在向 API 伺服器發出請求時都必須進行身份驗證,否則將被視為匿名使用者。
身份驗證策略
Kubernetes 使用客戶端證書、不記名令牌或身份驗證代理透過身份驗證外掛來驗證 API 請求。當 HTTP 請求傳送到 API 伺服器時,外掛會嘗試將以下屬性與請求關聯起來
- 使用者名稱:標識終端使用者的字串。常見值可能是
kube-admin
或jane@example.com
。 - UID:標識終端使用者的字串,並嘗試比使用者名稱更具一致性和唯一性。
- 組:一組字串,每個字串表示使用者所屬的命名邏輯使用者集合。常見值可能是
system:masters
或devops-team
。 - 額外欄位:一個從字串到字串列表的對映,其中包含授權器可能認為有用的附加資訊。
所有值對身份驗證系統都是不透明的,只有在 授權器 解釋時才具有意義。
您可以同時啟用多種身份驗證方法。通常應至少使用兩種方法
- 用於服務賬號的服務賬號令牌
- 至少一種其他使用者身份驗證方法。
當啟用多個身份驗證模組時,第一個成功驗證請求的模組會短路評估。API 伺服器不保證身份驗證器執行的順序。
system:authenticated
組包含在所有已驗證使用者的組列表中。
與其他身份驗證協議(LDAP、SAML、Kerberos、備用 x509 方案等)的整合可以透過使用 身份驗證代理 或 身份驗證 Webhook 來實現。
X509 客戶端證書
透過向 API 伺服器傳遞 --client-ca-file=SOMEFILE
選項來啟用客戶端證書身份驗證。引用的檔案必須包含一個或多個證書頒發機構,用於驗證提供給 API 伺服器的客戶端證書。如果提供了客戶端證書並經過驗證,則主題的通用名稱將用作請求的使用者名稱。從 Kubernetes 1.4 開始,客戶端證書還可以使用證書的組織欄位指示使用者的組成員身份。要為一個使用者包含多個組成員身份,請在證書中包含多個組織欄位。
例如,使用 openssl
命令列工具生成證書籤名請求
openssl req -new -key jbeda.pem -out jbeda-csr.pem -subj "/CN=jbeda/O=app1/O=app2"
這將為使用者“jbeda”建立 CSR,該使用者屬於“app1”和“app2”兩個組。
有關如何生成客戶端證書,請參閱 管理證書。
靜態令牌檔案
當命令列上給出 --token-auth-file=SOMEFILE
選項時,API 伺服器從檔案中讀取不記名令牌。目前,令牌無限期有效,並且在不重新啟動 API 伺服器的情況下無法更改令牌列表。
令牌檔案是一個 CSV 檔案,至少包含 3 列:令牌、使用者名稱、使用者 UID,後跟可選的組名。
注意
如果您的組不止一個,則該列必須用雙引號引起來,例如
token,user,uid,"group1,group2,group3"
在請求中放置不記名令牌
當從 HTTP 客戶端使用不記名令牌身份驗證時,API 伺服器期望一個 Authorization
標頭,其值為 Bearer
。不記名令牌必須是一個字元序列,可以使用 HTTP 的編碼和引用工具放入 HTTP 標頭值中,且不超過這些工具的能力。例如:如果不記名令牌是 31ada4fd-adec-460c-809a-9e56ceb75269
,則它將顯示在 HTTP 標頭中,如下所示。
Authorization: Bearer 31ada4fd-adec-460c-809a-9e56ceb75269
引導令牌
Kubernetes v1.18 [stable]
為了簡化新叢集的引導,Kubernetes 包含一種動態管理的不記名令牌型別,稱為 引導令牌。這些令牌作為 Secret 儲存在 kube-system
名稱空間中,可以在其中動態管理和建立。Controller Manager 包含一個 TokenCleaner 控制器,用於在引導令牌過期時將其刪除。
令牌的形式為 [a-z0-9]{6}.[a-z0-9]{16}
。第一個元件是令牌 ID,第二個元件是令牌金鑰。您可以在 HTTP 標頭中指定令牌,如下所示
Authorization: Bearer 781292.db7bc3a58fc5f07e
您必須在 API 伺服器上使用 --enable-bootstrap-token-auth
標誌啟用引導令牌身份驗證器。您必須透過 Controller Manager 上的 --controllers
標誌啟用 TokenCleaner 控制器。這可以透過類似 --controllers=*,tokencleaner
的方式完成。如果您正在使用 kubeadm
引導叢集,它將為您完成此操作。
身份驗證器以 system:bootstrap:
身份進行身份驗證。它包含在 system:bootstrappers
組中。名稱和組有意限制,以阻止使用者在引導後使用這些令牌。使用者名稱和組可用於(並由 kubeadm
使用)制定適當的授權策略以支援叢集引導。
有關引導令牌身份驗證器和控制器的深入文件以及如何使用 kubeadm
管理這些令牌,請參閱 引導令牌。
服務賬號令牌
服務賬號是一個自動啟用的身份驗證器,它使用簽名的不記名令牌來驗證請求。該外掛接受兩個可選標誌
--service-account-key-file
包含 PEM 編碼的 x509 RSA 或 ECDSA 私鑰或公鑰的檔案,用於驗證 ServiceAccount 令牌。指定的檔案可以包含多個金鑰,並且該標誌可以指定多次,使用不同的檔案。如果未指定,則使用 --tls-private-key-file。--service-account-lookup
如果啟用,從 API 刪除的令牌將被撤銷。
服務賬號通常由 API 伺服器自動建立,並透過 ServiceAccount
准入控制器 與叢集中執行的 Pod 相關聯。不記名令牌安裝在 Pod 的已知位置,並允許叢集內程序與 API 伺服器通訊。可以使用 PodSpec
的 serviceAccountName
欄位將賬號顯式與 Pod 關聯。
注意
通常會省略serviceAccountName
,因為這是自動完成的。apiVersion: apps/v1 # this apiVersion is relevant as of Kubernetes 1.9
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
spec:
replicas: 3
template:
metadata:
# ...
spec:
serviceAccountName: bob-the-bot
containers:
- name: nginx
image: nginx:1.14.2
服務賬號不記名令牌在叢集外部使用完全有效,可用於為希望與 Kubernetes API 通訊的長期執行作業建立身份。要手動建立服務賬號,請使用 kubectl create serviceaccount (NAME)
命令。這會在當前名稱空間中建立一個服務賬號。
kubectl create serviceaccount jenkins
serviceaccount/jenkins created
建立關聯的令牌
kubectl create token jenkins
eyJhbGciOiJSUzI1NiIsImtp...
建立的令牌是一個簽名的 JSON Web 令牌 (JWT)。
簽名的 JWT 可以用作不記名令牌,以給定服務賬號的身份進行身份驗證。有關令牌如何包含在請求中,請參閱 上文。通常,這些令牌被掛載到 Pod 中,用於叢集內訪問 API 伺服器,但也可以在叢集外部使用。
服務賬號使用使用者名稱 system:serviceaccount:(NAMESPACE):(SERVICEACCOUNT)
進行身份驗證,並分配給組 system:serviceaccounts
和 system:serviceaccounts:(NAMESPACE)
。
警告
由於服務賬號令牌也可以儲存在 Secret API 物件中,任何對 Secret 具有寫入訪問許可權的使用者都可以請求令牌,任何對這些 Secret 具有讀取訪問許可權的使用者都可以以服務賬號的身份進行身份驗證。在授予服務賬號許可權以及 Secret 的讀取或寫入能力時要謹慎。OpenID Connect 令牌
OpenID Connect 是一種 OAuth2 風格,受某些 OAuth2 提供商(尤其是 Microsoft Entra ID、Salesforce 和 Google)支援。該協議對 OAuth2 的主要擴充套件是隨訪問令牌返回的一個附加欄位,稱為 ID 令牌。此令牌是一個 JSON Web 令牌 (JWT),包含眾所周知的欄位,例如使用者電子郵件,並由伺服器簽名。
為了識別使用者,身份驗證器使用 OAuth2 令牌響應 中的 id_token
(而不是 access_token
)作為不記名令牌。有關令牌如何包含在請求中,請參閱 上文。
id_token, and refresh_token deactivate idp activate user user ->> kube: 3. Call kubectl
with --token being the id_token
OR add tokens to .kube/config deactivate user activate kube kube ->> api: 4. Authorization: Bearer... deactivate kube activate api api ->> api: 5. Is JWT signature valid? api ->> api: 6. Has the JWT expired? (iat+exp) api ->> api: 7. User authorized? api -->> kube: 8. Authorized: Perform
action and return result deactivate api activate kube kube --x user: 9. Return result deactivate kube
登入到您的身份提供商
您的身份提供商將為您提供
access_token
、id_token
和refresh_token
使用
kubectl
時,將您的id_token
與--token
標誌一起使用,或將其直接新增到您的kubeconfig
kubectl
將您的id_token
透過名為 Authorization 的標頭髮送到 API 伺服器API 伺服器將確保 JWT 簽名有效
檢查以確保
id_token
未過期如果使用
AuthenticationConfiguration
配置了 CEL 表示式,則執行宣告和/或使用者驗證。確保使用者已獲得授權
授權後,API 伺服器將響應返回給
kubectl
kubectl
向用戶提供反饋
由於驗證您身份所需的所有資料都在 id_token
中,Kubernetes 不需要“打電話回家”給身份提供商。在每個請求都是無狀態的模型中,這為身份驗證提供了一個高度可擴充套件的解決方案。它確實帶來了一些挑戰
- Kubernetes 沒有“Web 介面”來觸發身份驗證過程。沒有瀏覽器或介面來收集憑據,這就是您需要首先向身份提供商進行身份驗證的原因。
id_token
無法撤銷,它就像證書一樣,因此它應該是短期的(只有幾分鐘),因此每隔幾分鐘就必須獲取一個新令牌可能會非常煩人。- 要向 Kubernetes 控制面板進行身份驗證,您必須使用
kubectl proxy
命令或注入id_token
的反向代理。
配置 API 伺服器
使用標誌
要啟用該外掛,請在 API 伺服器上配置以下標誌
引數 | 描述 | 示例 | 必需 |
---|---|---|---|
--oidc-issuer-url | 提供商的 URL,允許 API 伺服器發現公共簽名金鑰。只接受使用 https:// 方案的 URL。這通常是提供商的發現 URL,更改為具有空路徑。 | 如果發行者的 OIDC 發現 URL 是 https://accounts.provider.example/.well-known/openid-configuration ,則該值應為 https://accounts.provider.example | 是 |
--oidc-client-id | 所有令牌必須為其頒發的客戶端 ID。 | kubernetes | 是 |
--oidc-username-claim | 用作使用者名稱的 JWT 宣告。預設為 sub ,它應該是終端使用者的唯一識別符號。管理員可以選擇其他宣告,例如 email 或 name ,具體取決於其提供商。但是,除了 email 之外的宣告將以發行者 URL 為字首,以防止與其他外掛發生名稱衝突。 | sub | 否 |
--oidc-username-prefix | 新增到使用者名稱宣告的字首,以防止與現有名稱(例如 system: 使用者)衝突。例如,值 oidc: 將建立類似 oidc:jane.doe 的使用者名稱。如果未提供此標誌,並且 --oidc-username-claim 的值不是 email ,則字首預設為 ( Issuer URL )# ,其中 ( Issuer URL ) 是 --oidc-issuer-url 的值。值 - 可用於停用所有字首。 | oidc | 否 |
--oidc-groups-claim | 用作使用者組的 JWT 宣告。如果宣告存在,它必須是字串陣列。 | groups | 否 |
--oidc-groups-prefix | 新增到組宣告的字首,以防止與現有名稱(例如 system: 組)衝突。例如,值 oidc: 將建立類似 oidc:engineering 和 oidc:infra 的組名。 | oidc | 否 |
--oidc-required-claim | 描述 ID 令牌中所需宣告的鍵=值對。如果設定,將驗證 ID 令牌中是否存在具有匹配值的宣告。重複此標誌以指定多個宣告。 | claim=value | 否 |
--oidc-ca-file | 您的身份提供商 Web 證書籤名 CA 的證書路徑。預設為主機的根 CA。 | /etc/kubernetes/ssl/kc-ca.pem | 否 |
--oidc-signing-algs | 接受的簽名演算法。預設為 RS256。允許的值為:RS256、RS384、RS512、ES256、ES384、ES512、PS256、PS384、PS512。這些值由 RFC 7518 https://tools.ietf.org/html/rfc7518#section-3.1 定義。 | RS512 | 否 |
透過檔案進行身份驗證配置
Kubernetes v1.34 [穩定]
(預設啟用:true)JWT 身份驗證器是一種用於使用符合 JWT 的令牌對 Kubernetes 使用者進行身份驗證的身份驗證器。身份驗證器將嘗試解析原始 ID 令牌,驗證其是否已由配置的頒發者簽名。用於驗證簽名的公鑰透過 OIDC 發現從頒發者的公共端點中發現。
最小有效 JWT 負載必須包含以下宣告
{
"iss": "https://example.com", // must match the issuer.url
"aud": ["my-app"], // at least one of the entries in issuer.audiences must match the "aud" claim in presented JWTs.
"exp": 1234567890, // token expiration as Unix time (the number of seconds elapsed since January 1, 1970 UTC)
"<username-claim>": "user" // this is the username claim configured in the claimMappings.username.claim or claimMappings.username.expression
}
配置檔案方法允許您配置多個 JWT 身份驗證器,每個身份驗證器都有唯一的 issuer.url
和 issuer.discoveryURL
。配置檔案甚至允許您指定 CEL 表示式以將宣告對映到使用者屬性,並驗證宣告和使用者資訊。當配置檔案修改時,API 伺服器還會自動重新載入身份驗證器。您可以使用 apiserver_authentication_config_controller_automatic_reload_last_timestamp_seconds
指標來監視 API 伺服器上次重新載入配置的時間。
您必須使用 API 伺服器上的 --authentication-config
標誌指定身份驗證配置檔案的路徑。如果您想使用命令列標誌而不是配置檔案,這些標誌將繼續按原樣工作。要訪問新功能,例如配置多個身份驗證器,為頒發者設定多個受眾,請切換到使用配置檔案。
對於 Kubernetes v1.34,結構化身份驗證配置檔案格式為 Beta 級別,使用該配置的機制也為 Beta 級別。如果您沒有特意為您的叢集停用 StructuredAuthenticationConfiguration
功能門,您可以透過為 kube-apiserver 指定 --authentication-config
命令列引數來啟用結構化身份驗證。下面顯示了結構化身份驗證配置檔案的示例。
注意
如果您同時指定--authentication-config
和任何 --oidc-*
命令列引數,則這是配置錯誤。在這種情況下,API 伺服器會報告錯誤,然後立即退出。如果要切換到使用結構化身份驗證配置,則必須刪除 --oidc-*
命令列引數,並改用配置檔案。Kubernetes v1.34 [beta]
(預設啟用:true)JWT 頒發者配置中的 egressSelectorType 欄位允許您指定應使用哪個出口選擇器來發送與頒發者相關的所有流量(發現、JWKS、分散式宣告等)。此功能需要啟用 StructuredAuthenticationConfigurationEgressSelector
功能門。
---
#
# CAUTION: this is an example configuration.
# Do not use this for your own cluster!
#
apiVersion: apiserver.config.k8s.io/v1
kind: AuthenticationConfiguration
# list of authenticators to authenticate Kubernetes users using JWT compliant tokens.
# the maximum number of allowed authenticators is 64.
jwt:
- issuer:
# url must be unique across all authenticators.
# url must not conflict with issuer configured in --service-account-issuer.
url: https://example.com # Same as --oidc-issuer-url.
# discoveryURL, if specified, overrides the URL used to fetch discovery
# information instead of using "{url}/.well-known/openid-configuration".
# The exact value specified is used, so "/.well-known/openid-configuration"
# must be included in discoveryURL if needed.
#
# The "issuer" field in the fetched discovery information must match the "issuer.url" field
# in the AuthenticationConfiguration and will be used to validate the "iss" claim in the presented JWT.
# This is for scenarios where the well-known and jwks endpoints are hosted at a different
# location than the issuer (such as locally in the cluster).
# discoveryURL must be different from url if specified and must be unique across all authenticators.
discoveryURL: https://discovery.example.com/.well-known/openid-configuration
# PEM encoded CA certificates used to validate the connection when fetching
# discovery information. If not set, the system verifier will be used.
# Same value as the content of the file referenced by the --oidc-ca-file flag.
certificateAuthority: <PEM encoded CA certificates>
# audiences is the set of acceptable audiences the JWT must be issued to.
# At least one of the entries must match the "aud" claim in presented JWTs.
audiences:
- my-app # Same as --oidc-client-id.
- my-other-app
# this is required to be set to "MatchAny" when multiple audiences are specified.
audienceMatchPolicy: MatchAny
# egressSelectorType is an indicator of which egress selection should be used for sending all traffic related
# to this issuer (discovery, JWKS, distributed claims, etc). If unspecified, no custom dialer is used.
# When specified, the valid choices are "controlplane" and "cluster". These correspond to the associated
# values in the --egress-selector-config-file.
# - controlplane: for traffic intended to go to the control plane.
# - cluster: for traffic intended to go to the system being managed by Kubernetes.
egressSelectorType: <egress-selector-type>
# rules applied to validate token claims to authenticate users.
claimValidationRules:
# Same as --oidc-required-claim key=value.
- claim: hd
requiredValue: example.com
# Instead of claim and requiredValue, you can use expression to validate the claim.
# expression is a CEL expression that evaluates to a boolean.
# all the expressions must evaluate to true for validation to succeed.
- expression: 'claims.hd == "example.com"'
# Message customizes the error message seen in the API server logs when the validation fails.
message: the hd claim must be set to example.com
- expression: 'claims.exp - claims.nbf <= 86400'
message: total token lifetime must not exceed 24 hours
claimMappings:
# username represents an option for the username attribute.
# This is the only required attribute.
username:
# Same as --oidc-username-claim. Mutually exclusive with username.expression.
claim: "sub"
# Same as --oidc-username-prefix. Mutually exclusive with username.expression.
# if username.claim is set, username.prefix is required.
# Explicitly set it to "" if no prefix is desired.
prefix: ""
# Mutually exclusive with username.claim and username.prefix.
# expression is a CEL expression that evaluates to a string.
#
# 1. If username.expression uses 'claims.email', then 'claims.email_verified' must be used in
# username.expression or extra[*].valueExpression or claimValidationRules[*].expression.
# An example claim validation rule expression that matches the validation automatically
# applied when username.claim is set to 'email' is 'claims.?email_verified.orValue(true) == true'.
# By explicitly comparing the value to true, we let type-checking see the result will be a boolean, and
# to make sure a non-boolean email_verified claim will be caught at runtime.
# 2. If the username asserted based on username.expression is the empty string, the authentication
# request will fail.
expression: 'claims.username + ":external-user"'
# groups represents an option for the groups attribute.
groups:
# Same as --oidc-groups-claim. Mutually exclusive with groups.expression.
claim: "sub"
# Same as --oidc-groups-prefix. Mutually exclusive with groups.expression.
# if groups.claim is set, groups.prefix is required.
# Explicitly set it to "" if no prefix is desired.
prefix: ""
# Mutually exclusive with groups.claim and groups.prefix.
# expression is a CEL expression that evaluates to a string or a list of strings.
expression: 'claims.roles.split(",")'
# uid represents an option for the uid attribute.
uid:
# Mutually exclusive with uid.expression.
claim: 'sub'
# Mutually exclusive with uid.claim
# expression is a CEL expression that evaluates to a string.
expression: 'claims.sub'
# extra attributes to be added to the UserInfo object. Keys must be domain-prefix path and must be unique.
extra:
# key is a string to use as the extra attribute key.
# key must be a domain-prefix path (e.g. example.org/foo). All characters before the first "/" must be a valid
# subdomain as defined by RFC 1123. All characters trailing the first "/" must
# be valid HTTP Path characters as defined by RFC 3986.
# k8s.io, kubernetes.io and their subdomains are reserved for Kubernetes use and cannot be used.
# key must be lowercase and unique across all extra attributes.
- key: 'example.com/tenant'
# valueExpression is a CEL expression that evaluates to a string or a list of strings.
valueExpression: 'claims.tenant'
# validation rules applied to the final user object.
userValidationRules:
# expression is a CEL expression that evaluates to a boolean.
# all the expressions must evaluate to true for the user to be valid.
- expression: "!user.username.startsWith('system:')"
# Message customizes the error message seen in the API server logs when the validation fails.
message: 'username cannot used reserved system: prefix'
- expression: "user.groups.all(group, !group.startsWith('system:'))"
message: 'groups cannot used reserved system: prefix'
宣告驗證規則表示式
jwt.claimValidationRules[i].expression
表示將由 CEL 評估的表示式。CEL 表示式可以訪問令牌負載的內容,這些內容組織到claims
CEL 變數中。claims
是一個從宣告名稱(字串)到宣告值(任何型別)的對映。使用者驗證規則表示式
jwt.userValidationRules[i].expression
表示將由 CEL 評估的表示式。CEL 表示式可以訪問userInfo
的內容,這些內容組織到user
CEL 變數中。有關user
的模式,請參閱 UserInfo API 文件。宣告對映表示式
jwt.claimMappings.username.expression
、jwt.claimMappings.groups.expression
、jwt.claimMappings.uid.expression
jwt.claimMappings.extra[i].valueExpression
表示將由 CEL 評估的表示式。CEL 表示式可以訪問令牌負載的內容,這些內容組織到claims
CEL 變數中。claims
是一個從宣告名稱(字串)到宣告值(任何型別)的對映。要了解更多資訊,請參閱 CEL 文件
以下是使用不同令牌負載的
AuthenticationConfiguration
示例。apiVersion: apiserver.config.k8s.io/v1 kind: AuthenticationConfiguration jwt: - issuer: url: https://example.com audiences: - my-app claimMappings: username: expression: 'claims.username + ":external-user"' groups: expression: 'claims.roles.split(",")' uid: expression: 'claims.sub' extra: - key: 'example.com/tenant' valueExpression: 'claims.tenant' userValidationRules: - expression: "!user.username.startsWith('system:')" # the expression will evaluate to true, so validation will succeed. message: 'username cannot used reserved system: prefix'
TOKEN=eyJhbGciOiJSUzI1NiIsImtpZCI6ImY3dF9tOEROWmFTQk1oWGw5QXZTWGhBUC04Y0JmZ0JVbFVpTG5oQkgxdXMiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJrdWJlcm5ldGVzIiwiZXhwIjoxNzAzMjMyOTQ5LCJpYXQiOjE3MDExMDcyMzMsImlzcyI6Imh0dHBzOi8vZXhhbXBsZS5jb20iLCJqdGkiOiI3YzMzNzk0MjgwN2U3M2NhYTJjMzBjODY4YWMwY2U5MTBiY2UwMmRkY2JmZWJlOGMyM2I4YjVmMjdhZDYyODczIiwibmJmIjoxNzAxMTA3MjMzLCJyb2xlcyI6InVzZXIsYWRtaW4iLCJzdWIiOiJhdXRoIiwidGVuYW50IjoiNzJmOTg4YmYtODZmMS00MWFmLTkxYWItMmQ3Y2QwMTFkYjRhIiwidXNlcm5hbWUiOiJmb28ifQ.TBWF2RkQHm4QQz85AYPcwLxSk-VLvQW-mNDHx7SEOSv9LVwcPYPuPajJpuQn9C_gKq1R94QKSQ5F6UgHMILz8OfmPKmX_00wpwwNVGeevJ79ieX2V-__W56iNR5gJ-i9nn6FYk5pwfVREB0l4HSlpTOmu80gbPWAXY5hLW0ZtcE1JTEEmefORHV2ge8e3jp1xGafNy6LdJWabYuKiw8d7Qga__HxtKB-t0kRMNzLRS7rka_SfQg0dSYektuxhLbiDkqhmRffGlQKXGVzUsuvFw7IGM5ZWnZgEMDzCI357obHeM3tRqpn5WRjtB8oM7JgnCymaJi-P3iCd88iu1xnzA
其中令牌負載為
{ "aud": "kubernetes", "exp": 1703232949, "iat": 1701107233, "iss": "https://example.com", "jti": "7c337942807e73caa2c30c868ac0ce910bce02ddcbfebe8c23b8b5f27ad62873", "nbf": 1701107233, "roles": "user,admin", "sub": "auth", "tenant": "72f988bf-86f1-41af-91ab-2d7cd011db4a", "username": "foo" }
具有上述
AuthenticationConfiguration
的令牌將生成以下UserInfo
物件併成功驗證使用者。{ "username": "foo:external-user", "uid": "auth", "groups": [ "user", "admin" ], "extra": { "example.com/tenant": ["72f988bf-86f1-41af-91ab-2d7cd011db4a"] } }
apiVersion: apiserver.config.k8s.io/v1 kind: AuthenticationConfiguration jwt: - issuer: url: https://example.com audiences: - my-app claimValidationRules: - expression: 'claims.hd == "example.com"' # the token below does not have this claim, so validation will fail. message: the hd claim must be set to example.com claimMappings: username: expression: 'claims.username + ":external-user"' groups: expression: 'claims.roles.split(",")' uid: expression: 'claims.sub' extra: - key: 'example.com/tenant' valueExpression: 'claims.tenant' userValidationRules: - expression: "!user.username.startsWith('system:')" # the expression will evaluate to true, so validation will succeed. message: 'username cannot used reserved system: prefix'
TOKEN=eyJhbGciOiJSUzI1NiIsImtpZCI6ImY3dF9tOEROWmFTQk1oWGw5QXZTWGhBUC04Y0JmZ0JVbFVpTG5oQkgxdXMiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJrdWJlcm5ldGVzIiwiZXhwIjoxNzAzMjMyOTQ5LCJpYXQiOjE3MDExMDcyMzMsImlzcyI6Imh0dHBzOi8vZXhhbXBsZS5jb20iLCJqdGkiOiI3YzMzNzk0MjgwN2U3M2NhYTJjMzBjODY4YWMwY2U5MTBiY2UwMmRkY2JmZWJlOGMyM2I4YjVmMjdhZDYyODczIiwibmJmIjoxNzAxMTA3MjMzLCJyb2xlcyI6InVzZXIsYWRtaW4iLCJzdWIiOiJhdXRoIiwidGVuYW50IjoiNzJmOTg4YmYtODZmMS00MWFmLTkxYWItMmQ3Y2QwMTFkYjRhIiwidXNlcm5hbWUiOiJmb28ifQ.TBWF2RkQHm4QQz85AYPcwLxSk-VLvQW-mNDHx7SEOSv9LVwcPYPuPajJpuQn9C_gKq1R94QKSQ5F6UgHMILz8OfmPKmX_00wpwwNVGeevJ79ieX2V-__W56iNR5gJ-i9nn6FYk5pwfVREB0l4HSlpTOmu80gbPWAXY5hLW0ZtcE1JTEEmefORHV2ge8e3jp1xGafNy6LdJWabYuKiw8d7Qga__HxtKB-t0kRMNzLRS7rka_SfQg0dSYektuxhLbiDkqhmRffGlQKXGVzUsuvFw7IGM5ZWnZgEMDzCI357obHeM3tRqpn5WRjtB8oM7JgnCymaJi-P3iCd88iu1xnzA
其中令牌負載為
{ "aud": "kubernetes", "exp": 1703232949, "iat": 1701107233, "iss": "https://example.com", "jti": "7c337942807e73caa2c30c868ac0ce910bce02ddcbfebe8c23b8b5f27ad62873", "nbf": 1701107233, "roles": "user,admin", "sub": "auth", "tenant": "72f988bf-86f1-41af-91ab-2d7cd011db4a", "username": "foo" }
具有上述
AuthenticationConfiguration
的令牌將無法驗證,因為hd
宣告未設定為example.com
。API 伺服器將返回401 Unauthorized
錯誤。apiVersion: apiserver.config.k8s.io/v1 kind: AuthenticationConfiguration jwt: - issuer: url: https://example.com audiences: - my-app claimValidationRules: - expression: 'claims.hd == "example.com"' message: the hd claim must be set to example.com claimMappings: username: expression: '"system:" + claims.username' # this will prefix the username with "system:" and will fail user validation. groups: expression: 'claims.roles.split(",")' uid: expression: 'claims.sub' extra: - key: 'example.com/tenant' valueExpression: 'claims.tenant' userValidationRules: - expression: "!user.username.startsWith('system:')" # the username will be system:foo and expression will evaluate to false, so validation will fail. message: 'username cannot used reserved system: prefix'
TOKEN=eyJhbGciOiJSUzI1NiIsImtpZCI6ImY3dF9tOEROWmFTQk1oWGw5QXZTWGhBUC04Y0JmZ0JVbFVpTG5oQkgxdXMiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJrdWJlcm5ldGVzIiwiZXhwIjoxNzAzMjMyOTQ5LCJoZCI6ImV4YW1wbGUuY29tIiwiaWF0IjoxNzAxMTEzMTAxLCJpc3MiOiJodHRwczovL2V4YW1wbGUuY29tIiwianRpIjoiYjViMDY1MjM3MmNkMjBlMzQ1YjZmZGZmY2RjMjE4MWY0YWZkNmYyNTlhYWI0YjdlMzU4ODEyMzdkMjkyMjBiYyIsIm5iZiI6MTcwMTExMzEwMSwicm9sZXMiOiJ1c2VyLGFkbWluIiwic3ViIjoiYXV0aCIsInRlbmFudCI6IjcyZjk4OGJmLTg2ZjEtNDFhZi05MWFiLTJkN2NkMDExZGI0YSIsInVzZXJuYW1lIjoiZm9vIn0.FgPJBYLobo9jnbHreooBlvpgEcSPWnKfX6dc0IvdlRB-F0dCcgy91oCJeK_aBk-8zH5AKUXoFTlInfLCkPivMOJqMECA1YTrMUwt_IVqwb116AqihfByUYIIqzMjvUbthtbpIeHQm2fF0HbrUqa_Q0uaYwgy8mD807h7sBcUMjNd215ff_nFIHss-9zegH8GI1d9fiBf-g6zjkR1j987EP748khpQh9IxPjMJbSgG_uH5x80YFuqgEWwq-aYJPQxXX6FatP96a2EAn7wfPpGlPRt0HcBOvq5pCnudgCgfVgiOJiLr_7robQu4T1bis0W75VPEvwWtgFcLnvcQx0JWg
其中令牌負載為
{ "aud": "kubernetes", "exp": 1703232949, "hd": "example.com", "iat": 1701113101, "iss": "https://example.com", "jti": "b5b0652372cd20e345b6fdffcdc2181f4afd6f259aab4b7e35881237d29220bc", "nbf": 1701113101, "roles": "user,admin", "sub": "auth", "tenant": "72f988bf-86f1-41af-91ab-2d7cd011db4a", "username": "foo" }
具有上述
AuthenticationConfiguration
的令牌將生成以下UserInfo
物件{ "username": "system:foo", "uid": "auth", "groups": [ "user", "admin" ], "extra": { "example.com/tenant": ["72f988bf-86f1-41af-91ab-2d7cd011db4a"] } }
這將導致使用者驗證失敗,因為使用者名稱以
system:
開頭。API 伺服器將返回401 Unauthorized
錯誤。
限制
- 分散式宣告不透過 CEL 表示式工作。
Kubernetes 不提供 OpenID Connect 身份提供商。您可以使用現有的公共 OpenID Connect 身份提供商或執行您自己的支援 OpenID Connect 協議的身份提供商。
為了使身份提供商與 Kubernetes 協同工作,它必須
用於驗證簽名的公鑰透過 OIDC 發現從頒發者的公共端點中發現。如果您使用身份驗證配置檔案,身份提供商不需要公開暴露發現端點。您可以在與頒發者不同的位置(例如叢集本地)託管發現端點,並在配置檔案中指定
issuer.discoveryURL
。在 TLS 中執行,使用非過時密碼
擁有 CA 簽名的證書(即使 CA 不是商業 CA 或自簽名)
關於上述要求 #3,即需要 CA 簽名證書的說明。如果您部署自己的身份提供商,您必須讓您的身份提供商的 Web 伺服器證書由設定了 CA
標誌為 TRUE
的證書籤名,即使它是自簽名的。這是因為 GoLang 的 TLS 客戶端實現對證書驗證的標準非常嚴格。如果您手頭沒有 CA,您可以使用標準證書生成工具建立簡單的 CA 和簽名的證書和金鑰對。
使用 kubectl
選項 1 - OIDC 身份驗證器
第一個選項是使用 kubectl oidc
身份驗證器,它將 id_token
設定為所有請求的不記名令牌,並在令牌過期後重新整理令牌。登入到提供商後,使用 kubectl 新增您的 id_token
、refresh_token
、client_id
和 client_secret
來配置外掛。
重新整理令牌響應中不返回 id_token
的提供商不受此外掛支援,應使用下面的“選項 2”。
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 )
例如,在向身份提供商進行身份驗證後執行以下命令
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=id-token=eyJraWQiOiJDTj1vaWRjaWRwLnRyZW1vbG8ubGFuLCBPVT1EZW1vLCBPPVRybWVvbG8gU2VjdXJpdHksIEw9QXJsaW5ndG9uLCBTVD1WaXJnaW5pYSwgQz1VUy1DTj1rdWJlLWNhLTEyMDIxNDc5MjEwMzYwNzMyMTUyIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL29pZGNpZHAudHJlbW9sby5sYW46ODQ0My9hdXRoL2lkcC9PaWRjSWRQIiwiYXVkIjoia3ViZXJuZXRlcyIsImV4cCI6MTQ4MzU0OTUxMSwianRpIjoiMm96US15TXdFcHV4WDlHZUhQdy1hZyIsImlhdCI6MTQ4MzU0OTQ1MSwibmJmIjoxNDgzNTQ5MzMxLCJzdWIiOiI0YWViMzdiYS1iNjQ1LTQ4ZmQtYWIzMC0xYTAxZWU0MWUyMTgifQ.w6p4J_6qQ1HzTG9nrEOrubxIMb9K5hzcMPxc9IxPx2K4xO9l-oFiUw93daH3m5pluP6K7eOE6txBuRVfEcpJSwlelsOsW8gb8VJcnzMS9EnZpeA0tW_p-mnkFc3VcfyXuhe5R3G7aa5d8uHv70yJ9Y3-UhjiN9EhpMdfPAoEB9fYKKkJRzF7utTTIPGrSaSU6d2pcpfYKaxIwePzEkT4DfcQthoZdy9ucNvvLoi1DIC-UocFD8HLs8LYKEqSxQvOcvnThbObJ9af71EwmuE21fO5KzMW20KtAeget1gnldOosPtz1G5EwvaQ401-RPQzPGMVBld0_zMCAwZttJ4knw
這將產生以下配置
users:
- name: mmosley
user:
auth-provider:
config:
client-id: kubernetes
client-secret: 1db158f6-177d-4d9c-8a8b-d36869918ec5
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
和 client_secret
重新整理您的 id_token
,並將 refresh_token
和 id_token
的新值儲存在您的 .kube/config
中。
選項 2 - 使用 --token
選項
kubectl
命令允許您使用 --token
選項傳入令牌。將 id_token
複製並貼上到此選項中
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 令牌身份驗證
Webhook 身份驗證是用於驗證不記名令牌的鉤子。
--authentication-token-webhook-config-file
描述如何訪問遠端 Webhook 服務的配置檔案。--authentication-token-webhook-cache-ttl
身份驗證決策的快取時間。預設為兩分鐘。--authentication-token-webhook-version
確定是使用authentication.k8s.io/v1beta1
還是authentication.k8s.io/v1
TokenReview
物件來從 Webhook 傳送/接收資訊。預設為v1beta1
。
配置檔案使用 kubeconfig 檔案格式。在檔案中,clusters
指的是遠端服務,users
指的是 API 伺服器 Webhook。例如
# Kubernetes API version
apiVersion: v1
# kind of the API object
kind: Config
# 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. 'https' recommended for production.
# 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-server
name: webhook
當客戶端嘗試使用如 上文 所述的不記名令牌向 API 伺服器進行身份驗證時,身份驗證 Webhook 將包含該令牌的 JSON 序列化 TokenReview
物件 POST 到遠端服務。
請注意,Webhook API 物件受與其他 Kubernetes API 物件相同的 版本相容性規則 約束。實現者應檢查請求的 apiVersion
欄位以確保正確反序列化,並且 必須 使用與請求相同版本的 TokenReview
物件進行響應。
注意
Kubernetes API 伺服器預設為向後相容性發送authentication.k8s.io/v1beta1
令牌審查。要選擇接收 authentication.k8s.io/v1
令牌審查,API 伺服器必須使用 --authentication-token-webhook-version=v1
啟動。{
"apiVersion": "authentication.k8s.io/v1",
"kind": "TokenReview",
"spec": {
# Opaque bearer token sent to the API server
"token": "014fbff9a07c...",
# Optional list of the audience identifiers for the server the token was presented to.
# Audience-aware token authenticators (for example, OIDC token authenticators)
# should verify the token was intended for at least one of the audiences in this list,
# and return the intersection of this list and the valid audiences for the token in the response status.
# This ensures the token is valid to authenticate to the server it was presented to.
# If no audiences are provided, the token should be validated to authenticate to the Kubernetes API server.
"audiences": ["https://myserver.example.com", "https://myserver.internal.example.com"]
}
}
{
"apiVersion": "authentication.k8s.io/v1beta1",
"kind": "TokenReview",
"spec": {
# Opaque bearer token sent to the API server
"token": "014fbff9a07c...",
# Optional list of the audience identifiers for the server the token was presented to.
# Audience-aware token authenticators (for example, OIDC token authenticators)
# should verify the token was intended for at least one of the audiences in this list,
# and return the intersection of this list and the valid audiences for the token in the response status.
# This ensures the token is valid to authenticate to the server it was presented to.
# If no audiences are provided, the token should be validated to authenticate to the Kubernetes API server.
"audiences": ["https://myserver.example.com", "https://myserver.internal.example.com"]
}
}
遠端服務應填寫請求的 status
欄位以指示登入是否成功。響應主體的 spec
欄位被忽略,可以省略。遠端服務必須使用其收到的相同 TokenReview
API 版本返回響應。不記名令牌的成功驗證將返回
{
"apiVersion": "authentication.k8s.io/v1",
"kind": "TokenReview",
"status": {
"authenticated": true,
"user": {
# Required
"username": "janedoe@example.com",
# Optional
"uid": "42",
# Optional group memberships
"groups": ["developers", "qa"],
# Optional additional information provided by the authenticator.
# This should not contain confidential data, as it can be recorded in logs
# or API objects, and is made available to admission webhooks.
"extra": {
"extrafield1": [
"extravalue1",
"extravalue2"
]
}
},
# Optional list audience-aware token authenticators can return,
# containing the audiences from the `spec.audiences` list for which the provided token was valid.
# If this is omitted, the token is considered to be valid to authenticate to the Kubernetes API server.
"audiences": ["https://myserver.example.com"]
}
}
{
"apiVersion": "authentication.k8s.io/v1beta1",
"kind": "TokenReview",
"status": {
"authenticated": true,
"user": {
# Required
"username": "janedoe@example.com",
# Optional
"uid": "42",
# Optional group memberships
"groups": ["developers", "qa"],
# Optional additional information provided by the authenticator.
# This should not contain confidential data, as it can be recorded in logs
# or API objects, and is made available to admission webhooks.
"extra": {
"extrafield1": [
"extravalue1",
"extravalue2"
]
}
},
# Optional list audience-aware token authenticators can return,
# containing the audiences from the `spec.audiences` list for which the provided token was valid.
# If this is omitted, the token is considered to be valid to authenticate to the Kubernetes API server.
"audiences": ["https://myserver.example.com"]
}
}
不成功的請求將返回
{
"apiVersion": "authentication.k8s.io/v1",
"kind": "TokenReview",
"status": {
"authenticated": false,
# Optionally include details about why authentication failed.
# If no error is provided, the API will return a generic Unauthorized message.
# The error field is ignored when authenticated=true.
"error": "Credentials are expired"
}
}
{
"apiVersion": "authentication.k8s.io/v1beta1",
"kind": "TokenReview",
"status": {
"authenticated": false,
# Optionally include details about why authentication failed.
# If no error is provided, the API will return a generic Unauthorized message.
# The error field is ignored when authenticated=true.
"error": "Credentials are expired"
}
}
身份驗證代理
API 伺服器可以配置為從請求頭值(例如 X-Remote-User
)識別使用者。它旨在與設定請求頭值的身份驗證代理結合使用。
--requestheader-username-headers
必需,不區分大小寫。按順序檢查使用者身份的頭部名稱。第一個包含值的頭部用作使用者名稱。--requestheader-group-headers
1.6+。可選,不區分大小寫。“X-Remote-Group”建議使用。按順序檢查使用者組的頭部名稱。所有指定頭部中的所有值都用作組名稱。--requestheader-extra-headers-prefix
1.6+。可選,不區分大小寫。“X-Remote-Extra-”建議使用。查詢頭部字首以確定有關使用者的額外資訊(通常由配置的授權外掛使用)。任何以指定字首開頭的頭部都會刪除字首。頭部名稱的其餘部分轉換為小寫並進行 百分比解碼,成為額外部索引鍵,頭部值是額外值。
注意
在 1.11.3 之前(以及 1.10.7、1.9.11),額外部索引鍵只能包含 HTTP 頭部標籤中合法的 字元。例如,使用此配置
--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-Acme.com%2Fproject: some-project
X-Remote-Extra-Scopes: openid
X-Remote-Extra-Scopes: profile
將導致此使用者資訊
name: fido
groups:
- dogs
- dachshunds
extra:
acme.com/project:
- some-project
scopes:
- openid
- profile
為了防止頭部欺騙,在檢查請求頭之前,身份驗證代理需要向 API 伺服器提供有效的客戶端證書,以根據指定的 CA 進行驗證。警告:**不要**重複使用在不同上下文中使用的 CA,除非您瞭解風險和保護 CA 使用的機制。
--requestheader-client-ca-file
必需。PEM 編碼的證書包。在檢查請求頭以獲取使用者名稱之前,必須提供並驗證有效的客戶端證書與指定檔案中的證書頒發機構。--requestheader-allowed-names
可選。通用名稱 (CN) 值列表。如果設定,在檢查請求頭以獲取使用者名稱之前,必須提供具有指定列表中 CN 的有效客戶端證書。如果為空,則允許任何 CN。
匿名請求
當啟用時,未被其他配置的身份驗證方法拒絕的請求被視為匿名請求,並被賦予使用者名稱 system:anonymous
和組 system:unauthenticated
。
例如,在配置了令牌身份驗證並啟用了匿名訪問的伺服器上,提供無效不記名令牌的請求將收到 401 Unauthorized
錯誤。不提供不記名令牌的請求將被視為匿名請求。
在 1.5.1-1.5.x 中,匿名訪問預設停用,可以透過向 API 伺服器傳遞 --anonymous-auth=true
選項來啟用。
在 1.6+ 中,如果使用除 AlwaysAllow
之外的授權模式,匿名訪問預設啟用,並且可以透過向 API 伺服器傳遞 --anonymous-auth=false
選項來停用。從 1.6 開始,ABAC 和 RBAC 授權器要求明確授權 system:anonymous
使用者或 system:unauthenticated
組,因此授予 *
使用者或 *
組訪問許可權的舊策略規則不包括匿名使用者。
匿名身份驗證器配置
Kubernetes v1.34 [穩定]
(預設啟用:true)AuthenticationConfiguration
可用於配置匿名身份驗證器。如果您在 AuthenticationConfiguration
檔案中設定匿名欄位,則不能設定 --anonymous-auth
標誌。
使用身份驗證配置檔案配置匿名身份驗證器的主要優點是,除了啟用和停用匿名身份驗證之外,您還可以配置哪些端點支援匿名身份驗證。
下面是一個示例身份驗證配置檔案
---
#
# CAUTION: this is an example configuration.
# Do not use this for your own cluster!
#
apiVersion: apiserver.config.k8s.io/v1
kind: AuthenticationConfiguration
anonymous:
enabled: true
conditions:
- path: /livez
- path: /readyz
- path: /healthz
在上述配置中,只有 /livez
、/readyz
和 /healthz
端點可以透過匿名請求訪問。即使 RBAC 配置允許其他端點,也無法訪問。
使用者模擬
使用者可以透過模擬頭部充當另一個使用者。這些允許請求手動覆蓋請求認證的使用者資訊。例如,管理員可以使用此功能除錯授權策略,透過臨時模擬另一個使用者並檢視請求是否被拒絕。
模擬請求首先以請求使用者身份進行身份驗證,然後切換到被模擬的使用者資訊。
- 使用者使用其憑據 和 模擬頭部進行 API 呼叫。
- API 伺服器對使用者進行身份驗證。
- API 伺服器確保已認證的使用者具有模擬許可權。
- 請求使用者資訊被模擬值替換。
- 請求被評估,授權作用於被模擬的使用者資訊。
以下 HTTP 頭部可用於執行模擬請求
Impersonate-User
:要充當的使用者名稱。Impersonate-Group
:要充當的組名。可以多次提供以設定多個組。可選。需要“Impersonate-User”。Impersonate-Extra-( extra name )
:用於將額外欄位與使用者關聯的動態頭部。可選。需要“Impersonate-User”。為了保持一致,( extra name )
必須是小寫,並且任何不是 HTTP 頭部標籤中合法的 字元必須是 utf8 並進行 百分比編碼。Impersonate-Uid
:表示被模擬使用者的唯一識別符號。可選。需要“Impersonate-User”。Kubernetes 對此字串不強制任何格式要求。
注意
Impersonate-Uid
僅在 1.22.0 及更高版本中可用。模擬使用者組時使用的模擬頭部的示例
Impersonate-User: jane.doe@example.com
Impersonate-Group: developers
Impersonate-Group: admins
模擬具有 UID 和額外欄位的使用者時使用的模擬頭部的示例
Impersonate-User: jane.doe@example.com
Impersonate-Extra-dn: cn=jane,ou=engineers,dc=example,dc=com
Impersonate-Extra-acme.com%2Fproject: some-project
Impersonate-Extra-scopes: view
Impersonate-Extra-scopes: development
Impersonate-Uid: 06f6ce97-e2c5-4ab8-7ba5-7654dd08d52b
使用 kubectl
時,設定 --as
標誌以配置 Impersonate-User
頭部,設定 --as-group
標誌以配置 Impersonate-Group
頭部。
kubectl drain mynode
Error from server (Forbidden): User "clark" cannot get nodes at the cluster scope. (get nodes mynode)
設定 --as
和 --as-group
標誌
kubectl drain mynode --as=superman --as-group=system:masters
node/mynode cordoned
node/mynode drained
注意
kubectl
無法模擬額外欄位或 UID。要模擬使用者、組、使用者識別符號 (UID) 或額外欄位,模擬使用者必須能夠對被模擬屬性的型別(“user”、“group”、“uid”等)執行“impersonate”動詞。對於啟用了 RBAC 授權外掛的叢集,以下 ClusterRole 包含了設定使用者和組模擬頭部所需的規則
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: impersonator
rules:
- apiGroups: [""]
resources: ["users", "groups", "serviceaccounts"]
verbs: ["impersonate"]
對於模擬,額外欄位和被模擬 UID 都屬於“authentication.k8s.io” apiGroup
。額外欄位被評估為資源“userextras”的子資源。為了允許使用者將模擬頭部用於額外欄位“scopes”和 UID,應授予使用者以下角色
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: scopes-and-uid-impersonator
rules:
# Can set "Impersonate-Extra-scopes" header and the "Impersonate-Uid" header.
- apiGroups: ["authentication.k8s.io"]
resources: ["userextras/scopes", "uids"]
verbs: ["impersonate"]
模擬頭部的值也可以透過限制資源可以採用的 resourceNames
集合來限制。
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"]
# Can impersonate the uid "06f6ce97-e2c5-4ab8-7ba5-7654dd08d52b"
- apiGroups: ["authentication.k8s.io"]
resources: ["uids"]
verbs: ["impersonate"]
resourceNames: ["06f6ce97-e2c5-4ab8-7ba5-7654dd08d52b"]
注意
模擬使用者或組允許您執行任何操作,就像您是該使用者或組一樣;因此,模擬不屬於名稱空間範圍。如果您希望使用 Kubernetes RBAC 允許模擬,這需要使用ClusterRole
和 ClusterRoleBinding
,而不是 Role
和 RoleBinding
。client-go 憑證外掛
k8s.io/client-go
以及使用它的工具(例如 kubectl
和 kubelet
)能夠執行外部命令以接收使用者憑據。
此功能旨在用於與 k8s.io/client-go
不原生支援的身份驗證協議(LDAP、Kerberos、OAuth2、SAML 等)的客戶端整合。該外掛實現了協議特定的邏輯,然後返回不透明的憑據以供使用。幾乎所有憑據外掛用例都需要一個支援 Webhook 令牌身份驗證器 的伺服器端元件來解釋客戶端外掛生成的憑據格式。
注意
早期版本的kubectl
包含了對 AKS 和 GKE 身份驗證的內建支援,但現在已不再提供。示例用例
在一個假設的用例中,一個組織將執行一個外部服務,該服務將 LDAP 憑據交換為使用者特定的簽名令牌。該服務還將能夠響應 Webhook 令牌身份驗證器 請求以驗證令牌。使用者需要在其工作站上安裝憑據外掛。
針對 API 進行身份驗證
- 使用者發出
kubectl
命令。 - 憑據外掛提示使用者輸入 LDAP 憑據,將憑據與外部服務交換以獲取令牌。
- 憑據外掛將令牌返回給 client-go,client-go 將其用作針對 API 伺服器的不記名令牌。
- API 伺服器使用 Webhook 令牌身份驗證器 向外部服務提交
TokenReview
。 - 外部服務驗證令牌上的簽名並返回使用者的使用者名稱和組。
配置
憑據外掛透過 kubectl 配置檔案 配置,作為使用者欄位的一部分。
apiVersion: v1
kind: Config
users:
- name: my-user
user:
exec:
# Command to execute. Required.
command: "example-client-go-exec-plugin"
# API version to use when decoding the ExecCredentials resource. Required.
#
# The API version returned by the plugin MUST match the version listed here.
#
# To integrate with tools that support multiple versions (such as client.authentication.k8s.io/v1beta1),
# set an environment variable, pass an argument to the tool that indicates which version the exec plugin expects,
# or read the version from the ExecCredential object in the KUBERNETES_EXEC_INFO environment variable.
apiVersion: "client.authentication.k8s.io/v1"
# Environment variables to set when executing the plugin. Optional.
env:
- name: "FOO"
value: "bar"
# Arguments to pass when executing the plugin. Optional.
args:
- "arg1"
- "arg2"
# Text shown to the user when the executable doesn't seem to be present. Optional.
installHint: |
example-client-go-exec-plugin is required to authenticate
to the current cluster. It can be installed:
On macOS: brew install example-client-go-exec-plugin
On Ubuntu: apt-get install example-client-go-exec-plugin
On Fedora: dnf install example-client-go-exec-plugin
...
# Whether or not to provide cluster information, which could potentially contain
# very large CA data, to this exec plugin as a part of the KUBERNETES_EXEC_INFO
# environment variable.
provideClusterInfo: true
# The contract between the exec plugin and the standard input I/O stream. If the
# contract cannot be satisfied, this plugin will not be run and an error will be
# returned. Valid values are "Never" (this exec plugin never uses standard input),
# "IfAvailable" (this exec plugin wants to use standard input if it is available),
# or "Always" (this exec plugin requires standard input to function). Required.
interactiveMode: Never
clusters:
- name: my-cluster
cluster:
server: "https://172.17.4.100:6443"
certificate-authority: "/etc/kubernetes/ca.pem"
extensions:
- name: client.authentication.k8s.io/exec # reserved extension name for per cluster exec config
extension:
arbitrary: config
this: can be provided via the KUBERNETES_EXEC_INFO environment variable upon setting provideClusterInfo
you: ["can", "put", "anything", "here"]
contexts:
- name: my-cluster
context:
cluster: my-cluster
user: my-user
current-context: my-cluster
apiVersion: v1
kind: Config
users:
- name: my-user
user:
exec:
# Command to execute. Required.
command: "example-client-go-exec-plugin"
# API version to use when decoding the ExecCredentials resource. Required.
#
# The API version returned by the plugin MUST match the version listed here.
#
# To integrate with tools that support multiple versions (such as client.authentication.k8s.io/v1),
# set an environment variable, pass an argument to the tool that indicates which version the exec plugin expects,
# or read the version from the ExecCredential object in the KUBERNETES_EXEC_INFO environment variable.
apiVersion: "client.authentication.k8s.io/v1beta1"
# Environment variables to set when executing the plugin. Optional.
env:
- name: "FOO"
value: "bar"
# Arguments to pass when executing the plugin. Optional.
args:
- "arg1"
- "arg2"
# Text shown to the user when the executable doesn't seem to be present. Optional.
installHint: |
example-client-go-exec-plugin is required to authenticate
to the current cluster. It can be installed:
On macOS: brew install example-client-go-exec-plugin
On Ubuntu: apt-get install example-client-go-exec-plugin
On Fedora: dnf install example-client-go-exec-plugin
...
# Whether or not to provide cluster information, which could potentially contain
# very large CA data, to this exec plugin as a part of the KUBERNETES_EXEC_INFO
# environment variable.
provideClusterInfo: true
# The contract between the exec plugin and the standard input I/O stream. If the
# contract cannot be satisfied, this plugin will not be run and an error will be
# returned. Valid values are "Never" (this exec plugin never uses standard input),
# "IfAvailable" (this exec plugin wants to use standard input if it is available),
# or "Always" (this exec plugin requires standard input to function). Optional.
# Defaults to "IfAvailable".
interactiveMode: Never
clusters:
- name: my-cluster
cluster:
server: "https://172.17.4.100:6443"
certificate-authority: "/etc/kubernetes/ca.pem"
extensions:
- name: client.authentication.k8s.io/exec # reserved extension name for per cluster exec config
extension:
arbitrary: config
this: can be provided via the KUBERNETES_EXEC_INFO environment variable upon setting provideClusterInfo
you: ["can", "put", "anything", "here"]
contexts:
- name: my-cluster
context:
cluster: my-cluster
user: my-user
current-context: my-cluster
相對命令路徑被解釋為相對於配置檔案的目錄。如果 KUBECONFIG 設定為 /home/jane/kubeconfig
並且 exec 命令是 ./bin/example-client-go-exec-plugin
,則將執行二進位制檔案 /home/jane/bin/example-client-go-exec-plugin
。
- name: my-user
user:
exec:
# Path relative to the directory of the kubeconfig
command: "./bin/example-client-go-exec-plugin"
apiVersion: "client.authentication.k8s.io/v1"
interactiveMode: Never
輸入和輸出格式
執行的命令將 ExecCredential
物件列印到 stdout
。k8s.io/client-go
使用 status
中返回的憑據對 Kubernetes API 進行身份驗證。執行的命令透過 KUBERNETES_EXEC_INFO
環境變數作為輸入傳遞 ExecCredential
物件。此輸入包含有用的資訊,例如返回的 ExecCredential
物件的預期 API 版本以及外掛是否可以使用 stdin
與使用者互動。
在互動式會話(即終端)中執行時,stdin
可以直接暴露給外掛。外掛應使用 KUBERNETES_EXEC_INFO
環境變數中輸入 ExecCredential
物件的 spec.interactive
欄位來確定是否已提供 stdin
。外掛的 stdin
要求(即,stdin
是可選、嚴格必需還是從不使用才能成功執行外掛)透過 kubeconfig 中的 user.exec.interactiveMode
欄位宣告(有效值見下表)。user.exec.interactiveMode
欄位在 client.authentication.k8s.io/v1beta1
中是可選的,在 client.authentication.k8s.io/v1
中是必需的。
interactiveMode 值 | 含義 |
---|---|
Never | 此執行外掛從不需要使用標準輸入,因此無論標準輸入是否可用於使用者輸入,此執行外掛都將執行。 |
如果可用 | 此執行外掛希望在可用時使用標準輸入,但即使標準輸入不可用,它仍可執行。因此,無論標準輸入是否可用於使用者輸入,此執行外掛都將執行。如果標準輸入可用於使用者輸入,則將提供給此執行外掛。 |
Always | 此執行外掛需要標準輸入才能執行,因此僅當標準輸入可用於使用者輸入時,此執行外掛才會執行。如果標準輸入不可用於使用者輸入,則執行外掛將不執行,並且執行外掛執行程式將返回錯誤。 |
要使用不記名令牌憑據,外掛將在 ExecCredential
的狀態中返回令牌
{
"apiVersion": "client.authentication.k8s.io/v1",
"kind": "ExecCredential",
"status": {
"token": "my-bearer-token"
}
}
{
"apiVersion": "client.authentication.k8s.io/v1beta1",
"kind": "ExecCredential",
"status": {
"token": "my-bearer-token"
}
}
或者,可以返回 PEM 編碼的客戶端證書和金鑰以使用 TLS 客戶端身份驗證。如果外掛在後續呼叫中返回不同的證書和金鑰,k8s.io/client-go
將關閉與伺服器的現有連線以強制進行新的 TLS 握手。
如果指定,clientKeyData
和 clientCertificateData
都必須存在。
clientCertificateData
可能包含要傳送到伺服器的其他中間證書。
{
"apiVersion": "client.authentication.k8s.io/v1",
"kind": "ExecCredential",
"status": {
"clientCertificateData": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
"clientKeyData": "-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"
}
}
{
"apiVersion": "client.authentication.k8s.io/v1beta1",
"kind": "ExecCredential",
"status": {
"clientCertificateData": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
"clientKeyData": "-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"
}
}
可選地,響應可以包含憑據的有效期,格式為 RFC 3339 時間戳。
有效期的存在或缺失具有以下影響
- 如果包含有效期,則不記名令牌和 TLS 憑據將快取到有效期屆滿,或者伺服器響應 401 HTTP 狀態程式碼,或者程序退出。
- 如果省略有效期,則不記名令牌和 TLS 憑據將快取直到伺服器響應 401 HTTP 狀態程式碼或程序退出。
{
"apiVersion": "client.authentication.k8s.io/v1",
"kind": "ExecCredential",
"status": {
"token": "my-bearer-token",
"expirationTimestamp": "2018-03-05T17:30:20-08:00"
}
}
{
"apiVersion": "client.authentication.k8s.io/v1beta1",
"kind": "ExecCredential",
"status": {
"token": "my-bearer-token",
"expirationTimestamp": "2018-03-05T17:30:20-08:00"
}
}
要使 exec 外掛能夠獲取特定於叢集的資訊,請在 kubeconfig 中的 user.exec
欄位上設定 provideClusterInfo
。然後,外掛將透過 KUBERNETES_EXEC_INFO
環境變數獲取此特定於叢集的資訊。此環境變數中的資訊可用於執行特定於叢集的憑據獲取邏輯。以下 ExecCredential
清單描述了一個叢集資訊示例。
{
"apiVersion": "client.authentication.k8s.io/v1",
"kind": "ExecCredential",
"spec": {
"cluster": {
"server": "https://172.17.4.100:6443",
"certificate-authority-data": "LS0t...",
"config": {
"arbitrary": "config",
"this": "can be provided via the KUBERNETES_EXEC_INFO environment variable upon setting provideClusterInfo",
"you": ["can", "put", "anything", "here"]
}
},
"interactive": true
}
}
{
"apiVersion": "client.authentication.k8s.io/v1beta1",
"kind": "ExecCredential",
"spec": {
"cluster": {
"server": "https://172.17.4.100:6443",
"certificate-authority-data": "LS0t...",
"config": {
"arbitrary": "config",
"this": "can be provided via the KUBERNETES_EXEC_INFO environment variable upon setting provideClusterInfo",
"you": ["can", "put", "anything", "here"]
}
},
"interactive": true
}
}
客戶端訪問身份驗證資訊的 API
Kubernetes v1.28 [stable]
如果您的叢集啟用了 API,您可以使用 SelfSubjectReview
API 瞭解您的 Kubernetes 叢集如何對映您的身份驗證資訊以將您標識為客戶端。無論您是以使用者(通常代表真實人員)還是 ServiceAccount 身份進行身份驗證,這都有效。
SelfSubjectReview
物件沒有任何可配置的欄位。收到請求後,Kubernetes API 伺服器將使用者屬性填充到狀態中,並將其返回給使用者。
請求示例(主體將是一個 SelfSubjectReview
)
POST /apis/authentication.k8s.io/v1/selfsubjectreviews
{
"apiVersion": "authentication.k8s.io/v1",
"kind": "SelfSubjectReview"
}
響應示例
{
"apiVersion": "authentication.k8s.io/v1",
"kind": "SelfSubjectReview",
"status": {
"userInfo": {
"name": "jane.doe",
"uid": "b6c7cfd4-f166-11ec-8ea0-0242ac120002",
"groups": [
"viewers",
"editors",
"system:authenticated"
],
"extra": {
"provider_id": ["token.company.example"]
}
}
}
}
為了方便,提供了 kubectl auth whoami
命令。執行此命令將產生以下輸出(但會顯示不同的使用者屬性)
簡單輸出示例
ATTRIBUTE VALUE Username jane.doe Groups [system:authenticated]
包含額外屬性的複雜示例
ATTRIBUTE VALUE Username jane.doe UID b79dbf30-0c6a-11ed-861d-0242ac120002 Groups [students teachers system:authenticated] Extra: skills [reading learning] Extra: subjects [math sports]
透過提供輸出標誌,還可以列印結果的 JSON 或 YAML 表示
{
"apiVersion": "authentication.k8s.io/v1",
"kind": "SelfSubjectReview",
"status": {
"userInfo": {
"username": "jane.doe",
"uid": "b79dbf30-0c6a-11ed-861d-0242ac120002",
"groups": [
"students",
"teachers",
"system:authenticated"
],
"extra": {
"skills": [
"reading",
"learning"
],
"subjects": [
"math",
"sports"
]
}
}
}
}
apiVersion: authentication.k8s.io/v1
kind: SelfSubjectReview
status:
userInfo:
username: jane.doe
uid: b79dbf30-0c6a-11ed-861d-0242ac120002
groups:
- students
- teachers
- system:authenticated
extra:
skills:
- reading
- learning
subjects:
- math
- sports
當 Kubernetes 叢集中使用複雜的身份驗證流時,此功能非常有用,例如,如果您使用 Webhook 令牌身份驗證 或 身份驗證代理。
注意
Kubernetes API 伺服器在應用所有身份驗證機制(包括 模擬)後填充userInfo
。如果您或身份驗證代理使用模擬進行 SelfSubjectReview,您將看到被模擬使用者的使用者詳細資訊和屬性。預設情況下,當 APISelfSubjectReview
功能啟用時,所有已認證的使用者都可以建立 SelfSubjectReview
物件。這由 system:basic-user
叢集角色允許。
注意
您只能在以下情況下發出 SelfSubjectReview
請求
下一步
- 要了解如何為使用者頒發證書,請閱讀 使用 CertificateSigningRequest 為 Kubernetes API 客戶端頒發證書
- 閱讀 客戶端身份驗證參考 (v1)
- 閱讀 客戶端身份驗證參考 (v1beta1)