Kubernetes准入控制Admission Controller介紹
應用上雲,怎能沒有容器!點擊上方
容器魔方
關注我1.什麼是Admission Controller
Admission Controller(准入控制)
是Kubernetes API Server用於攔截請求的一種手段。Admission可以做到對請求的資源對象進行校驗,修改。
service mesh最近很火的項目Istio天生支持Kubernetes,利用的就是admission對服務實例自動注入sidecar。
假如對Kubernetes有一定的了解的話,應該會知道在Kubernetes中還有authn/authz,為什麼還會引入admission這種機制?
1)
authn/authz
是Kubernetes的認證鑒權,運行在filter中,只能獲取http請求essay-header以及證書,並不能獲取請求的body。所以authn/authz只能對客戶端進行認證和鑒權,不可以對請求的對象進行任何操作,因為這裡根本還獲取不到對象。
2)
Admission
運行在API Server的增刪改查handler中,可以自然地操作API resource。
下面將對Admission Controller工作流做一番詳解。
API Server
接收到客戶端請求後首先進行認證鑒權,認證鑒權通過後才會進行後續的
endpoint handler
處理。1)
當API Server接收到對象後首先根據http的路徑可以知道對象的版本號,然後將request body反序列化成versioned object.
2)
versioned object轉化為internal object,即沒有版本的內部類型,這種資源類型是所有versioned類型的超集。只有轉化為internal後才能適配所有的客戶端versioned object的校驗。
3)
Admission Controller具體的admit操作,可以通過這裡修改資源對象,例如為Pod掛載一個默認的Service Account等。
4)
API Server internal object validation,校驗某個資源對象數據和格式是否合法,例如:Service Name的字元個數不能超過63等。
5)
Admission Controller validate,可以自定義任何的對象校驗規則。
6)
internal object轉化為versioned object,並且持久化存儲到etcd。
註:
以上versioned object和internal object直接的轉換關係會在《深度剖析Kubernetes API Server三部曲 - part 2》詳細解釋,歡迎持續關注。
2.如何使用admission controller
Kubernetes 1.10
之前的版本可以使用
--admission-control
打開Admission Controller。同時
--admission-control
的順序決定Admission運行的先後。其實這種方式對於用戶來講其實是挺複雜的,因為這要求用戶對所有的Admission Controllers需要完全了解。
如果使用Kubernetes 1.10之後的版本,
--admission-control
已經廢棄,建議使用
--enable-admission-plugins --disable-admission-plugins
指定需要打開或者關閉的Admission Controller。 同時用戶指定的順序並不影響實際Admission Controllers的執行順序,對用戶來講非常友好。
值得一提的是,有些Admission Controller可能會使用Alpha版本的API,這時必須首先使能其使用的API版本。否則Admission Controller不能工作,可能會影響系統功能。
2.1 webhook admission
目前Kubernetes中已經有非常多的
Admission
插件, 但是並不能保證滿足所有開發者的需求。 眾所周知,Kbernetes之所以受到推崇,它的可擴展能力功不可沒。Admission也提供了一種webhook
的擴展機制。●
MutatingAdmissionWebhook:在對象持久化之前進行修改●
ValidatingAdmissionWebhook:在對象持久化之前進行可能有讀者接觸過另外一種動態可擴展的機制Initializers,不過至今還是Apha特性,社區討論有可能會把它移除。所以選擇動態Admission首選webhook。
2.2 如何使用webhook admission
Webhook Admission屬於同步調用,需要用戶部署自己的webhook server,創建自定義的配置資源對象: ValidatingWebhookConfiguration或MutatingWebhookConfiguration。
●
開發webhook server這裡我推薦參考
社區e2e測試用的server
,對細節源代碼感興趣的讀者可以自行參考
https://github.com/kubernetes/kubernetes/blob/v1.10.0-beta.1/test/images/webhook/main.go
,這裡面利用golang 標準庫實現的一個基本的http server,並註冊多個路由,同時服務於多種resource的准入控制。重點關注一下資源對象的decode過程,這是k8s apimachinery的高級功能。利用了apimachinery的scheme的能力,使用之前必須要將api註冊到scheme中,代碼詳見:
(https://github.com/kubernetes/kubernetes/blob/v1.10.0-beta.1/test/images/webhook/scheme.go)。
一個典型的webhook修改資源對象(Pod)的樣例代碼如下所示。
func
mutatePods
(
ar v1beta1
.
AdmissionReview
) *
v1beta1
.
AdmissionResponse
{
glog
.
V
(
2
).
Info
(
"mutating pods"
)
podResource
:=
metav1
.
GroupVersionResource
{
Group
:
""
,
Version
:
"v1"
,
Resource
:
"pods"
}
if
ar
.
Request
.
Resource
!=
podResource
{
glog
.
Errorf
(
"expect resource to be %s"
,
podResource
)
return
nil
}
raw
:=
ar
.
Request
.
Object
.
Raw
pod
:=
corev1
.
Pod
{}
deserializer
:=
codecs
.
UniversalDeserializer
()
// pod
的解碼,利用
apimachinery
if
_
,
_
,
err
:=
deserializer
.
Decode
(
raw
,
nil
,
&
pod
)
;
err
!=
nil
{
glog
.
Error
(
err
)
return
toAdmissionResponse
(
err
) }
reviewResponse
:=
v1beta1
.
AdmissionResponse
{}
reviewResponse
.
Allowed
=
true
if
pod
.
Name
==
"webhook-to-be-mutated"
{
reviewResponse
.
Patch
= []
byte
(
addInitContainerPatch
)
pt
:=
v1beta1
.
PatchTypeJSONPatch
reviewResponse
.
PatchType
= &
pt
}
return
&
reviewResponse
}
●
部署webhook server
# kubectl create –f webhook-server.yaml
apiVersion:
v1
kind:
Namespace
metadata: name:
e2e-tests-webhook-gbgt6
spec: finalizers:
- kubernetes---
apiVersion:
extensions/v1beta1
kind:
Deployment
metadata: labels: app:
sample-webhook
webhook:
"true"
name:
sample-webhook-deployment
namespace:
e2e-tests-webhook-gbgt6
spec: replicas:
1
selector: matchLabels: app:
sample-webhook
webhook:
"true"
template: metadata: labels: app:
sample-webhook
webhook:
"true"
spec: containers:
-
args:
- --tls-cert-file=/webhook.local.config/certificates/tls.crt - --tls-private-key-file=/webhook.local.config/certificates/tls.key - --alsologtostderr - -v=4 - 2>&1
image:
gcr.io/kubernetes-e2e-test-images/k8s-sample-admission-webhook-amd64:1.10v2
imagePullPolicy:
IfNotPresent
name:
sample-webhook
volumeMounts:
-
mountPath:
/webhook.local.config/certificates
name:
webhook-certs
readOnly:
true
volumes:
-
name:
webhook-certs
secret: defaultMode:
420
secretName:
sample-webhook-secret---
apiVersion:
v1
kind:
Service
metadata: labels: test:
webhook
name:
e2e-test-webhook
namespace:
e2e-tests-webhook-gbgt6
spec: ports:
-
port:
443
protocol:
TCP
targetPort:
443
selector: webhook:
"true"
sessionAffinity:
None
type:
ClusterIP
創建webhook server Deployment以及Service,供API Server調用。
●
創建MutatingWebhookConfiguration
# kubectl create –f webhook-config.yaml
apiVersion:
admissionregistration.k8s.io/v1beta1
kind:
MutatingWebhookConfiguration
metadata: name:
e2e-test-mutating-webhook-pod
webhooks:
-
clientConfig: caBundle:
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMyRENDQWNDZ0F3SUJBZ0lCQURBTkJna
3Foa2lHOXcwQkFRc0ZBREFkTVJzd0dRWURWUVFERXhKbE1tVXQKYzJWeWRtVnlMV05sY25RdFkyRXdIaGNOTVRnd056RTVNRGMwT1RJeFdoY05Namd3TnpFMk1EYzBPVEl4V2pBZApNUnN3R1FZRFZRUURFeEpsTW1VdGMyVnlkbVZ5TFdObGNuUXRZMkV3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBCkE0SUJEd0F3Z2dFS0FvSUJBUURFVVFEWVN6SGl3SUFHU1dHSWRBSmVBbnMrNFhaYjlZc3VuQlBVTkJPdHZqeFoKV3NSbUxydE0zVU9lcEszeGsvMzZCSS96RkdXdUNpMlJ0TWUxSWtEa2tVMzNEZE83K0ExVyt2NVZNVnFqL0lDTApsc29USml3TFhTcGowTHNwSUNVdGtqT1dlRjVhK3lJVHgyR01TMG9ZbWtuaHB0RXMrc2tKQjFMWm1uVTBaWFpzClRKak9Lb05ueHdVaTl4QnRUTXBQRWw2cVhmb3dCWlpvYjlkUzNtNzFLbjJCdU5Ec0s3YnVRcGJvdk9XdUQyNDAKdzNLQVJnT04xcjA4Vm4zd1I1MHVXS09tSkVsLzRUZ2JnSTRkaG85WHNIWUhUdnk4R3JRMXhYZE43ZEhSTlpHNQo5aDhmOUUzdjg1VWxwSEVWQThqUHB4RE5SSm9qRXVGQk9raFJEZEY1QWdNQkFBR2pJekFoTUE0R0ExVWREd0VCCi93UUVBd0lDcERBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFDWWl4VUsKYkhsRUpCK2t4THdqdktySDQ1OVVsNUJjb0VXZE1BNnArUC8yWXVZa2NuWC9GRVNjUFRxUS9vdkF3ejU1ZG1FUwpJTjVZOWd2ZlJxdWhZcEdWOHVFSWpzVkczTjdKQm1wM0NyclEyd3FYeHV3cndkVXV1dDltQSt2RkQ4Q2FQSE8xCmVad1J6NEkzTktFQ0xHMHJXQWxseEVvUm9tQ2UvaWZIUnRNRklTRk5sSnZVNlhIbzFDVWNFQ2FwOG9hYXN2cFcKT2JBQjVqQzc5WWJXN2lWVm54cjZGMnRvOG9oSEdNSEpXR1pwSTNKbVpNbGVOK01kVm5ySFdXSXBkOG9iS2E3TgpqSlZTczgzRmlDMzd4d2dqMUQyaTNHUnh5bHNKZEdJWTl4WVpQVmNNUTh6Z2FMMUpJUk1BdVZYbHczUkRzSDR0Cms5WmFybGY1NG9BOUN0Nk8KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
service: name:
e2e-test-webhook
namespace:
e2e-tests-webhook-gbgt6
path:
/mutating-pods
failurePolicy:
Ignore
name:
adding-init-container.k8s.io
namespaceSelector:
{}
rules:
-
apiGroups:
-
""
apiVersions:
- v1
operations:
- CREATE
resources:
- pods
rules
表示對於core/v1/pods資源對象創建的時候調用
mutating webhook
。server的地址及路徑通過clientConfig指明。
/mutating-pods
是指調用webhook server執行mutatePods,為pod增加init
initContainers
。
func
mutatePods
(
ar v1beta1
.
AdmissionReview
) *
v1beta1
.
AdmissionResponse
{
glog
.
V
(
2
).
Info
(
"mutating pods"
)
podResource
:=
metav1
.
GroupVersionResource
{
Group
:
""
,
Version
:
"v1"
,
Resource
:
"pods"
}
if
ar
.
Request
.
Resource
!=
podResource
{
glog
.
Errorf
(
"expect resource to be %s"
,
podResource
)
return
nil
}
raw
:=
ar
.
Request
.
Object
.
Raw
pod
:=
corev1
.
Pod
{}
deserializer
:=
codecs
.
UniversalDeserializer
()
if
_
,
_
,
err
:=
deserializer
.
Decode
(
raw
,
nil
,
&
pod
)
;
err
!=
nil
{
glog
.
Error
(
err
)
return
toAdmissionResponse
(
err
) }
reviewResponse
:=
v1beta1
.
AdmissionResponse
{}
reviewResponse
.
Allowed
=
true
if
pod
.
Name
==
"webhook-to-be-mutated"
{
reviewResponse
.
Patch
= []
byte
(
addInitContainerPatch
)
pt
:=
v1beta1
.
PatchTypeJSONPatch
reviewResponse
.
PatchType
= &
pt
}
return
&
reviewResponse
}
創建Pod
kubectl create –f pod.yaml
apiVersion:
v1
kind:
Pod
metadata: name:
webhook-to-be-mutated
namespace:
e2e-tests-webhook-gbgt6
spec: containers:
-
image:
k8s.gcr.io/pause:3.1
name:
example
查詢Pod
# kubectl get pod webhook-to-be-mutated –n e2e-tests-webhook-gbgt6 -oyaml
apiVersion:
v1
kind:
Pod
metadata: creationTimestamp:
2018-07-19T07:49:37Z
name:
webhook-to-be-mutated
namespace:
e2e-tests-webhook-gbgt6
resourceVersion:
"806"
selfLink:
/api/v1/namespaces/e2e-tests-webhook-gbgt6/pods/webhook-to-be-mutated
uid:
48d2e91d-8b28-11e8-b16d-286ed488dc10
spec: containers:
-
image:
k8s.gcr.io/pause:3.1
imagePullPolicy:
IfNotPresent
name:
example
resources:
{}
terminationMessagePath:
/dev/termination-log
terminationMessagePolicy:
File
volumeMounts:
-
mountPath:
/var/run/secrets/kubernetes.io/serviceaccount
name:
default-token-jhqlb
readOnly:
true
dnsPolicy:
ClusterFirst
initContainers:
-
image:
webhook-added-image
imagePullPolicy:
Always
name:
webhook-added-init-container
resources:
{}
terminationMessagePath:
/dev/termination-log
terminationMessagePolicy:
File
nodeName:
127.0.0.1
priority:
0
restartPolicy:
Always
schedulerName:
default-scheduler
securityContext:
{}
serviceAccount:
default
serviceAccountName:
default
terminationGracePeriodSeconds:
30
tolerations:
-
effect:
NoExecute
key:
node.kubernetes.io/not-ready
operator:
Exists
tolerationSeconds:
300 -
effect:
NoExecute
key:
node.kubernetes.io/unreachable
operator:
Exists
tolerationSeconds:
300
volumes:
-
name:
default-token-jhqlb
secret: defaultMode:
420
secretName:
default-token-jhqlb
可以看出,創建成功的pod已經多了一個名字為webhook-added-init-container的initContainers。
最後我們來總結下webhook Admission的優勢
●
webhook可動態擴展Admission能力,滿足自定義客戶的需求●
不需要重啟API Server,可通過創建webhook configuration熱載入webhook admission。參考:
1)https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/
2)https://www.slideshare.net/sttts/kubecon-eu-2018-sig-api-machinery-deep-dive
推薦閱讀
K8S上的分散式系統應用編排
Kubernetes網路一年發展動態與未來趨勢
點擊
閱讀原文,
回帖即可
報名
推薦閱讀: