什么是Admission Webhooks
Admission Controllers(准入控制器)
中有两个特殊的 controllers
: MutatingAdmissionWebhook
和 ValidatingAdmissionWebhook
.
MutatingAdmissionWebhook
会 依次调用 匹配请求的 MutatingWebhookConfiguration
ValidatingAdmissionWebhook
并行调用 匹配请求的 ValidatingWebhookConfiguration
Admission Webhooks
就是 MutatingWebhookConfiguration
和 ValidatingWebhookConfiguration
中指定的 service
Admission Webhooks
实质上是集群的 控制面
, 所以在编写和部署的时候要及其小心. 需要通过 k8s e2e test
MutatingWebhookConfiguration
和 ValidatingWebhookConfiguration
中定义 rules
和 clientConfig
, 以及 admissionReviewVersions
、 sideEffects
、 timeoutSeconds
创建 Configuration
后,系统将花费几秒钟来接受新配置
然后当 apiserver 接收到 匹配任意rules的请求时 , apiserver 就会发送 admissionReview 请求
给 clientConfig
指定的 webhook
admissionReview 请求
就是 apiserver 发送给 webhook server
的 POST 请求
, Content-Type: application/json
, JSON body
是 apiVersion: 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 body
是 apiVersion: admission.k8s.io/? kind: AdmissionReview
对象, AdmissionReview 对象
的 apiVersion
和 接收到的对象的 apiVersion
相同
webhook server
返回的 Json body
至少应包含如下2个字段:
-
uid
: 复制request.uid
-
allowed
:true
orfalse
当拒绝请求时, webhook server
可以自定义返回给用户的 http code
和 message
, 如下所示:
{
"apiVersion": "admission.k8s.io/v1",
"kind": "AdmissionReview",
"response": {
"uid": "",
"allowed": false,
"status": {
"code": 403,
"message": "You cannot do this because it is Tuesday and your name starts with A"
}
}
}
当允许请求时, mutating webhook
可能会修改传入的对象. 这通过 response
中的 patch
或 patchType
字段表示.
当前支持的 patchType
只有 JSONPatch
对于 patchType: JSONPatch
, patch
字段内容为 JSON patch operations
列表, 并使用 base64-encoded
, 如下例所示:
{
"apiVersion": "admission.k8s.io/v1",
"kind": "AdmissionReview",
"response": {
"uid": "",
"allowed": true,
"patchType": "JSONPatch",
"patch": "W3sib3AiOiAiYWRkIiwgInBhdGgiOiAiL3NwZWMvcmVwbGljYXMiLCAidmFsdWUiOiAzfV0="
}
}
Webhook Configuration
通过创建 MutatingWebhookConfiguration
or ValidatingWebhookConfiguration
API对象注册 admission webhook
.
Configuration
的 name
必须是有效的 DNS subdomain name
每个 Configuration
可以包含 一个或多个webhooks, 每个webhook需要指定唯一的名称
webhook
中定义如下的事情:
(1) rules : 用于如何匹配请求
包括 operations
、 apiGroups
、 apiVersions
、 resources
、 scope
-
operations
: 可以是CREATE
、UPDATE
、DELETE
、CONNECT
或*
-
apiGroups
:""(空字符串)
表示core API group
,*
表示所有 -
apiVersions
:*
表示所有 -
resources
:-
*
表示所有resources
, 但是不包括subresources
-
*/*
表示所有resources
和subresources
-
pods/*
表示pods
的所有subresources
-
*/status
表示所有status subresources
-
-
scope
: 可以是Cluster
、Namespaced
、*
,subresources
使用其parent resource
的scope
, 默认为*
-
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
newObject
和 oldObject
中有一个匹配了 objectSelector
都认为是 匹配
null object
(例如 create operation
中的 oldObject
和 delete operation
中的 newObject
) 被认定为不匹配
同样, 不可能包含 label
的对象(例如 DeploymentRollback
或 PodProxyOptions
)也被认定为不匹配
示例:
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
限制哪些请求被拦截, 它基于对象的 namespace
的 labels
对 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
允许使用多个 apiGroups
和 apiVersions
操作对象, 例如 Deployment
可以通过 extensions/v1beta1
、 apps/v1beta1
、 apps/v1beta2
和 apps/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
尝试使用 user
或 basic 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......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
的枚举值只有 None
和 NoneOnDryRun
示例:
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 auth
、 bearer token
或 cert
向 webhook server
认证自己为合法的 client
要完成这个配置,需要 3个步骤:
https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#authenticate-apiservers