概念:动态准入控制


什么是Admission Webhooks

Admission Controllers(准入控制器) 中有两个特殊的 controllers : MutatingAdmissionWebhookValidatingAdmissionWebhook .
MutatingAdmissionWebhook依次调用 匹配请求的 MutatingWebhookConfiguration
ValidatingAdmissionWebhook 并行调用 匹配请求的 ValidatingWebhookConfiguration

Admission Webhooks 就是 MutatingWebhookConfigurationValidatingWebhookConfiguration 中指定的 service
Admission Webhooks 实质上是集群的 控制面 , 所以在编写和部署的时候要及其小心. 需要通过 k8s e2e test

MutatingWebhookConfigurationValidatingWebhookConfiguration 中定义 rulesclientConfig , 以及 admissionReviewVersionssideEffectstimeoutSeconds

创建 Configuration 后,系统将花费几秒钟来接受新配置

然后当 apiserver 接收到 匹配任意rules的请求时 , apiserver 就会发送 admissionReview 请求clientConfig 指定的 webhook

admissionReview 请求 就是 apiserver 发送给 webhook serverPOST 请求 , Content-Type: application/json , JSON bodyapiVersion: admission.k8s.io/? kind: AdmissionReview 对象

可以在 Configuration 中通过 admissionReviewVersions 指定可接受的 apiVersion , 例如 admissionReviewVersions: ["v1", "v1beta1"]
apiserver 使用可接受的versions列表中的第一个apiserver支持的version,
如果没有apiserver支持的version, 那么 Configuration 不会被允许创建.
如果 Configuration 是之前创建的, 而现在 apiserver 不支持其声明的versions了,那么请求会按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",
    # 太长,就不记录了...
  }
}

然后 webhook server 返回 HTTP状态码200 , Content-Type: application/json , JSON bodyapiVersion: admission.k8s.io/? kind: AdmissionReview 对象, AdmissionReview 对象apiVersion 和 接收到的对象的 apiVersion 相同

webhook server 返回的 Json body 至少应包含如下2个字段:

  • uid : 复制 request.uid
  • allowed : true or false

当拒绝请求时, 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"
    }
  }
}

当允许请求时, mutating webhook 可能会修改传入的对象. 这通过 response 中的 patchpatchType 字段表示.
当前支持的 patchType 只有 JSONPatch
对于 patchType: JSONPatch , patch 字段内容为 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

通过创建 MutatingWebhookConfiguration or ValidatingWebhookConfiguration API对象注册 admission webhook .
Configurationname 必须是有效的 DNS subdomain name
每个 Configuration 可以包含 一个或多个webhooks, 每个webhook需要指定唯一的名称

webhook 中定义如下的事情:
(1) rules : 用于如何匹配请求

包括 operationsapiGroupsapiVersionsresourcesscope

  • operations : 可以是 CREATEUPDATEDELETECONNECT*
  • apiGroups : ""(空字符串) 表示 core API group , * 表示所有
  • apiVersions : * 表示所有
  • resources :
    • * 表示所有 resources , 但是不包括 subresources
    • */* 表示所有 resourcessubresources
    • pods/* 表示 pods 的所有 subresources
    • */status 表示所有 status subresources
  • scope : 可以是 ClusterNamespaced* , subresources 使用其 parent resourcescope , 默认为 *
    • 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 : 用于如何匹配请求
v1.15+ 之后, webhooks 可以可选地使用 objectSelector 限制哪些请求被拦截, 它基于对象的 labels
newObjectoldObject 中有一个匹配了 objectSelector 都认为是 匹配
null object (例如 create operation 中的 oldObjectdelete operation 中的 newObject ) 被认定为不匹配
同样, 不可能包含 label 的对象(例如 DeploymentRollbackPodProxyOptions )也被认定为不匹配
示例:

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 : 用于如何匹配请求
webhooks 可以可选地使用 namespaceSelector 限制哪些请求被拦截, 它基于对象的 namespacelabels
Namespace 对象的操作也会被考虑匹配, 使用其 .metadata.labels
如果对象是 cluster scoped resource 则该限制对其无效
示例:

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 : 用于如何匹配请求
因为 apiserver 允许使用多个 apiGroupsapiVersions 操作对象, 例如 Deployment 可以通过 extensions/v1beta1apps/v1beta1apps/v1beta2apps/v1 创建
如果 webhook 只指定了 apiGroups:["apps"], apiVersions:["v1","v1beta1"] , 那么 extensions/v1beta1 的请求就不会被认定为匹配

v1.15+ 之后, webhooks 可以可选地使用 matchPolicy 定义其 rules 如何匹配请求
matchPolicy 的枚举值有

  • Exact :
  • Equivalent : 默认值

顾名思义, 如果 webhook 指定了 matchPolicy: Equivalent , 则上面的示例中,请求会被认定为匹配

示例:

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 默认为 /
      path: /my-path
      # port 默认为 443
      port: 1234
  ...

(6) sideEffects
webhooks 一般只操作 AdmissionReview 中的内容.
但是有一些 webhooks 需要执行 out-of-band changes , 即 sideEffects
sideEffects 的枚举值有:

  • Unknown : 默认值.
    dryRun: true 的请求 会触发 webhook 声明 的调用, 然后请求会失败, 而且 webhook server 不会被调用.
  • None :
  • Some : dryRun: true 的请求 会触发 webhook 声明 的调用, 然后请求会失败, 而且 webhook server 不会被调用.
  • NoneOnDryRun : dryRun: true 的请求 会触发 webhook 声明 的调用, 然后 webhook server 被调用(由 webhook server 保证不要产生 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
如果超时, 请求按 failure policy 处理
如果使用 apiVersion: admissionregistration.k8s.io/v1 , 则 timeoutSeconds 的默认值为 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 定义 不识别的错误和超时错误 如何被处理.
failurePolicy 的枚举值包含:

  • Ignore :
  • Fail : 默认值

示例:

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

监控 admission webhooks

apiserver 提供了监控 admission webhooks 行为的方法. 这些监控机制帮助集群管理员回答如下问题:

  • 哪个 mutating webhook 更改了对象?
  • mutating webhook 对对象进行了哪些更改?
  • 哪个 webhook 在频繁地拒绝 API请求 ? 因为什么原因拒绝?

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


如何使用mTLS认证apiservers

如果不指定 ClientAuth , 则默认为 NoClientAuth , 这意味着 webhook server 无法认证其 clients , 也就是 apiserver .
如果你需要 mTLS或其他方式认证 clients , 你可以配置 apiserver 使用 basic authbearer tokencertwebhook server 认证自己为合法的 client
要完成这个配置,需要 3个步骤:
https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#authenticate-apiservers

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 229,362评论 6 537
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,013评论 3 423
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 177,346评论 0 382
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,421评论 1 316
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,146评论 6 410
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,534评论 1 325
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,585评论 3 444
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 42,767评论 0 289
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,318评论 1 335
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,074评论 3 356
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,258评论 1 371
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 38,828评论 5 362
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,486评论 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 34,916评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,156评论 1 290
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 51,993评论 3 395
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,234评论 2 375

推荐阅读更多精彩内容