概念:動(dòng)態(tài)準(zhǔn)入控制


什么是Admission Webhooks

Admission Controllers(準(zhǔn)入控制器) 中有兩個(gè)特殊的 controllers : MutatingAdmissionWebhookValidatingAdmissionWebhook .
MutatingAdmissionWebhook 會(huì) 依次調(diào)用 匹配請(qǐng)求的 MutatingWebhookConfiguration
ValidatingAdmissionWebhook 并行調(diào)用 匹配請(qǐng)求的 ValidatingWebhookConfiguration

Admission Webhooks 就是 MutatingWebhookConfigurationValidatingWebhookConfiguration 中指定的 service
Admission Webhooks 實(shí)質(zhì)上是集群的 控制面 , 所以在編寫和部署的時(shí)候要及其小心. 需要通過 k8s e2e test

MutatingWebhookConfigurationValidatingWebhookConfiguration 中定義 rulesclientConfig , 以及 admissionReviewVersions 、 sideEffects 、 timeoutSeconds

創(chuàng)建 Configuration 后,系統(tǒng)將花費(fèi)幾秒鐘來接受新配置

然后當(dāng) apiserver 接收到 匹配任意rules的請(qǐng)求時(shí) , apiserver 就會(huì)發(fā)送 admissionReview 請(qǐng)求clientConfig 指定的 webhook

admissionReview 請(qǐng)求 就是 apiserver 發(fā)送給 webhook serverPOST 請(qǐng)求 , Content-Type: application/json , JSON bodyapiVersion: admission.k8s.io/? kind: AdmissionReview 對(duì)象

可以在 Configuration 中通過 admissionReviewVersions 指定可接受的 apiVersion , 例如 admissionReviewVersions: ["v1", "v1beta1"]
apiserver 使用可接受的versions列表中的第一個(gè)apiserver支持的version,
如果沒有apiserver支持的version, 那么 Configuration 不會(huì)被允許創(chuàng)建.
如果 Configuration 是之前創(chuàng)建的, 而現(xiàn)在 apiserver 不支持其聲明的versions了,那么請(qǐng)求會(huì)按webhook的 failure policy 處理

AdmissionReview Json body 示例:
https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#webhook-request-and-response

{
  "apiVersion": "admission.k8s.io/v1",
  "kind": "AdmissionReview",
  "request": {
    # Random uid uniquely identifying this admission call
    "uid": "705ab4f5-6393-11e8-b7cc-42010a800002",
    # 太長(zhǎng),就不記錄了...
  }
}

然后 webhook server 返回 HTTP狀態(tài)碼200 , Content-Type: application/json , JSON bodyapiVersion: admission.k8s.io/? kind: AdmissionReview 對(duì)象, AdmissionReview 對(duì)象apiVersion 和 接收到的對(duì)象的 apiVersion 相同

webhook server 返回的 Json body 至少應(yīng)包含如下2個(gè)字段:

  • uid : 復(fù)制 request.uid
  • allowed : true or false

當(dāng)拒絕請(qǐng)求時(shí), webhook server 可以自定義返回給用戶的 http codemessage , 如下所示:

{
  "apiVersion": "admission.k8s.io/v1",
  "kind": "AdmissionReview",
  "response": {
    "uid": "<value from request.uid>",
    "allowed": false,
    "status": {
      "code": 403,
      "message": "You cannot do this because it is Tuesday and your name starts with A"
    }
  }
}

當(dāng)允許請(qǐng)求時(shí), mutating webhook 可能會(huì)修改傳入的對(duì)象. 這通過 response 中的 patchpatchType 字段表示.
當(dāng)前支持的 patchType 只有 JSONPatch
對(duì)于 patchType: JSONPatch , patch 字段內(nèi)容為 JSON patch operations 列表, 并使用 base64-encoded , 如下例所示:

{
  "apiVersion": "admission.k8s.io/v1",
  "kind": "AdmissionReview",
  "response": {
    "uid": "<value from request.uid>",
    "allowed": true,
    "patchType": "JSONPatch",
    "patch": "W3sib3AiOiAiYWRkIiwgInBhdGgiOiAiL3NwZWMvcmVwbGljYXMiLCAidmFsdWUiOiAzfV0="
  }
}

Webhook Configuration

通過創(chuàng)建 MutatingWebhookConfiguration or ValidatingWebhookConfiguration API對(duì)象注冊(cè) admission webhook .
Configurationname 必須是有效的 DNS subdomain name
每個(gè) Configuration 可以包含 一個(gè)或多個(gè)webhooks, 每個(gè)webhook需要指定唯一的名稱

webhook 中定義如下的事情:
(1) rules : 用于如何匹配請(qǐng)求

包括 operations 、 apiGroups 、 apiVersionsresources 、 scope

  • operations : 可以是 CREATEUPDATE 、 DELETECONNECT*
  • apiGroups : ""(空字符串) 表示 core API group , * 表示所有
  • apiVersions : * 表示所有
  • resources :
    • * 表示所有 resources , 但是不包括 subresources
    • */* 表示所有 resourcessubresources
    • pods/* 表示 pods 的所有 subresources
    • */status 表示所有 status subresources
  • scope : 可以是 Cluster 、 Namespaced 、 * , subresources 使用其 parent resourcescope , 默認(rèn)為 *
    • Cluster 表示只匹配 cluster-scoped resource
    • Namespaced 表示只匹配 namespaced-scoped resource
    • * 表示沒有 scope restrictions

示例:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: "pod-policy.example.com"
webhooks:
- name: "pod-policy.example.com"
  rules:
  - apiGroups:   [""]
    apiVersions: ["v1"]
    operations:  ["CREATE"]
    resources:   ["pods"]
    scope:       "Namespaced"
  clientConfig:
    service:
      namespace: "example-namespace"
      name: "example-service"
    caBundle: "Ci0tLS0tQk...<`caBundle` is a PEM encoded CA bundle which will be used to validate the webhook's server certificate.>...tLS0K"
  admissionReviewVersions: ["v1", "v1beta1"]
  sideEffects: None
  timeoutSeconds: 5

(2) objectSelector : 用于如何匹配請(qǐng)求
v1.15+ 之后, webhooks 可以可選地使用 objectSelector 限制哪些請(qǐng)求被攔截, 它基于對(duì)象的 labels
newObjectoldObject 中有一個(gè)匹配了 objectSelector 都認(rèn)為是 匹配
null object (例如 create operation 中的 oldObjectdelete operation 中的 newObject ) 被認(rèn)定為不匹配
同樣, 不可能包含 label 的對(duì)象(例如 DeploymentRollbackPodProxyOptions )也被認(rèn)定為不匹配
示例:

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  objectSelector:
    matchLabels:
      foo: bar
  rules:
  - operations: ["CREATE"]
    apiGroups: ["*"]
    apiVersions: ["*"]
    resources: ["*"]
    scope: "*"
  ...

(3) namespaceSelector : 用于如何匹配請(qǐng)求
webhooks 可以可選地使用 namespaceSelector 限制哪些請(qǐng)求被攔截, 它基于對(duì)象的 namespacelabels
對(duì) Namespace 對(duì)象的操作也會(huì)被考慮匹配, 使用其 .metadata.labels
如果對(duì)象是 cluster scoped resource 則該限制對(duì)其無效
示例:

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  namespaceSelector:
    matchExpressions:
    - key: runlevel
      operator: NotIn
      values: ["0","1"]
  rules:
  - operations: ["CREATE"]
    apiGroups: ["*"]
    apiVersions: ["*"]
    resources: ["*"]
    scope: "Namespaced"
  ...

(4) matchPolicy : 用于如何匹配請(qǐng)求
因?yàn)?apiserver 允許使用多個(gè) apiGroupsapiVersions 操作對(duì)象, 例如 Deployment 可以通過 extensions/v1beta1 、 apps/v1beta1 、 apps/v1beta2apps/v1 創(chuàng)建
如果 webhook 只指定了 apiGroups:["apps"], apiVersions:["v1","v1beta1"] , 那么 extensions/v1beta1 的請(qǐng)求就不會(huì)被認(rèn)定為匹配

v1.15+ 之后, webhooks 可以可選地使用 matchPolicy 定義其 rules 如何匹配請(qǐng)求
matchPolicy 的枚舉值有

  • Exact :
  • Equivalent : 默認(rèn)值

顧名思義, 如果 webhook 指定了 matchPolicy: Equivalent , 則上面的示例中,請(qǐng)求會(huì)被認(rèn)定為匹配

示例:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  matchPolicy: Equivalent
  rules:
  - operations: ["CREATE","UPDATE","DELETE"]
    apiGroups: ["apps"]
    apiVersions: ["v1"]
    resources: ["deployments"]
    scope: "Namespaced"
  ...

(5) clientConfig : 用于如何指定 webhook server

(5.1)使用URL指定webhook server
url的scheme 必須是 https
嘗試使用 userbasic auth (例如 user:pwd@ )是不被允許的.
Fragment ( #... ) 和 query parameters ( ?... ) 是不被允許的

示例:

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  clientConfig:
    url: "https://my-webhook.example.com:9443/my-webhook-path"
  ...

(5.2)使用Service reference指定webhook server

示例:

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  clientConfig:
    caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle containing the CA that signed the webhook's serving certificate>...tLS0K"
    service:
      namespace: my-service-namespace
      name: my-service-name
      # path 默認(rèn)為 /
      path: /my-path
      # port 默認(rèn)為 443
      port: 1234
  ...

(6) sideEffects
webhooks 一般只操作 AdmissionReview 中的內(nèi)容.
但是有一些 webhooks 需要執(zhí)行 out-of-band changes , 即 sideEffects
sideEffects 的枚舉值有:

  • Unknown : 默認(rèn)值.
    dryRun: true 的請(qǐng)求 會(huì)觸發(fā) webhook 聲明 的調(diào)用, 然后請(qǐng)求會(huì)失敗, 而且 webhook server 不會(huì)被調(diào)用.
  • None :
  • Some : dryRun: true 的請(qǐng)求 會(huì)觸發(fā) webhook 聲明 的調(diào)用, 然后請(qǐng)求會(huì)失敗, 而且 webhook server 不會(huì)被調(diào)用.
  • NoneOnDryRun : dryRun: true 的請(qǐng)求 會(huì)觸發(fā) webhook 聲明 的調(diào)用, 然后 webhook server 被調(diào)用(由 webhook server 保證不要產(chǎn)生 sideEffects ).

如果使用 apiVersion: admissionregistration.k8s.io/v1 , 則 sideEffects 的枚舉值只有 NoneNoneOnDryRun

示例:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  sideEffects: NoneOnDryRun
  ...

(7) timeoutSeconds
如果超時(shí), 請(qǐng)求按 failure policy 處理
如果使用 apiVersion: admissionregistration.k8s.io/v1 , 則 timeoutSeconds 的默認(rèn)值為 10s

示例:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  timeoutSeconds: 2
  ...

(7) reinvocationPolicy
https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#reinvocation-policy

(8) failurePolicy
failurePolicy 定義 不識(shí)別的錯(cuò)誤和超時(shí)錯(cuò)誤 如何被處理.
failurePolicy 的枚舉值包含:

  • Ignore :
  • Fail : 默認(rèn)值

示例:

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
...
webhooks:
- name: my-webhook.example.com
  failurePolicy: Fail
  ...

監(jiān)控 admission webhooks

apiserver 提供了監(jiān)控 admission webhooks 行為的方法. 這些監(jiān)控機(jī)制幫助集群管理員回答如下問題:

  • 哪個(gè) mutating webhook 更改了對(duì)象?
  • mutating webhook 對(duì)對(duì)象進(jìn)行了哪些更改?
  • 哪個(gè) webhook 在頻繁地拒絕 API請(qǐng)求 ? 因?yàn)槭裁丛蚓芙^?

https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#monitoring-admission-webhooks


如何使用mTLS認(rèn)證apiservers

如果不指定 ClientAuth , 則默認(rèn)為 NoClientAuth , 這意味著 webhook server 無法認(rèn)證其 clients , 也就是 apiserver .
如果你需要 mTLS或其他方式認(rèn)證 clients , 你可以配置 apiserver 使用 basic auth 、 bearer tokencertwebhook server 認(rèn)證自己為合法的 client
要完成這個(gè)配置,需要 3個(gè)步驟:
https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#authenticate-apiservers

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容