Admission Webhook 花式玩法,騷得很

項(xiàng)目由來(lái)
使用 kubernetes 的同學(xué)可能或多或少會(huì)有以下的實(shí)際業(yè)務(wù)或者需求場(chǎng)景:
為確保安全性,需要對(duì)某些資源進(jìn)行刪除保護(hù),例如不允許刪除 namespace、crd 定義等; 根據(jù)服務(wù)畫(huà)像為不同的服務(wù)設(shè)置不同的屬性,這些屬性基本是業(yè)務(wù)無(wú)感的,例如設(shè)置不同的超售比、設(shè)置不同的 Label 以及調(diào)度特性從而實(shí)現(xiàn) io 敏感型與 io 密集型服務(wù)的反親和調(diào)度等; 針對(duì)同一個(gè) workload 生成 per pod per config 的配置,例如為特定的業(yè)務(wù)容器設(shè)置 debug 開(kāi)關(guān)、特權(quán)模式、日志路徑等; 集群里面每引入一個(gè)組件,可能就會(huì)同時(shí)引入一個(gè)甚至多個(gè) admission webhook,久而久之,集群里面會(huì)存在眾多的 admission webhook,實(shí)現(xiàn)方式、關(guān)注的資源都不同,管理起來(lái)比較復(fù)雜; 雖然使用一些工具例如 kube-builder、controller-runtime 等可以快速的創(chuàng)建 admission webhook 的框架,但開(kāi)發(fā)整個(gè)功能也需要一定的開(kāi)發(fā)工作量,往往需要開(kāi)發(fā)的業(yè)務(wù)邏輯比較簡(jiǎn)單,基本是根據(jù)一些規(guī)則進(jìn)行一些決策; admission webhook 里的業(yè)務(wù)邏輯的改動(dòng)需要升級(jí) wehook 來(lái)實(shí)現(xiàn),變更就有可能引入線(xiàn)上穩(wěn)定性風(fēng)險(xiǎn);
可以大致歸為三類(lèi):集群資源管理、admission webhok 自身管理、業(yè)務(wù)資源定制?;谝陨系男枨髨?chǎng)景,一個(gè)通用的可編程的 webhook 規(guī)則引擎的想法誕生了。
項(xiàng)目介紹
Kinitiras[1] 為希臘語(yǔ),意思為發(fā)動(dòng)機(jī)、引擎,貼合 rule engine 的概念。項(xiàng)目通過(guò)抽象出來(lái)三種策略來(lái)實(shí)現(xiàn)集群資源的 mutate 和 ?validate 的邏輯,支持通過(guò) CUE 配置業(yè)務(wù)邏輯,從而支持了動(dòng)態(tài)編程能力,可以在不變更程序的前提下通過(guò)對(duì)策略的操作實(shí)現(xiàn)所需的能力。
能力介紹
Mutate
內(nèi)置了 OverridePolicy 和 ClusterOverridePolicy ?來(lái)支持 Mutate 能力,前者是 Namespace 級(jí)別生效,即只能修改同 Namespace 下的資源對(duì)象,后者是 Cluster ?級(jí)別生效,可修改資源對(duì)象不受 Namespace ?限制。策略?xún)?nèi)置一些篩選條件來(lái)對(duì)目標(biāo)資源對(duì)象進(jìn)行篩選,對(duì)于同一個(gè)資源對(duì)象,可以有多條策略與之匹配,其生效順序針對(duì)不同類(lèi)型策略?xún)?yōu)先使用 ClusterOverridePolicy,同一種類(lèi)型的策略則按照字母順序依次生效。
例:
kind:?ClusterOverridePolicy
apiVersion:?policy.kcloudlabs.io/v1alpha1
metadata:
??name:?add-anno-cop-cue
spec:
??resourceSelectors:
????-?apiVersion:?v1
??????kind:?Pod
??????labelSelector:
????????matchLabels:
??????????kinitiras.kcloudlabs.io/webhook:?enabled
??overrideRules:
????-?targetOperations:
????????-?CREATE
??????overriders:
????????cue:?|-
??????????object:?_?@tag(object)
??????????patches:?[
????????????if?object.metadata.annotations?==?_|_?{
??????????????{
????????????????op:?"add"
????????????????path:?"/metadata/annotations"
????????????????value:?{}
??????????????}
????????????},
????????????{
??????????????op:?"add"
??????????????path:?"/metadata/annotations/added-by"
??????????????value:?"cue"
????????????}
??????????]??????????
---
kind:?OverridePolicy
apiVersion:?policy.kcloudlabs.io/v1alpha1
metadata:
??name:?add-anno-op-plaintext
??namespace:?default
spec:
??resourceSelectors:
????-?apiVersion:?v1
??????kind:?Pod
??????labelSelector:
????????matchLabels:
??????????kinitiras.kcloudlabs.io/webhook:?enabled
??overrideRules:
????-?targetOperations:
????????-?CREATE
??????overriders:
????????plaintext:
??????????-?path:?/metadata/annotations/added-by
????????????op:?add
????????????value:?op
上述例子中定義了兩種類(lèi)型的策略,通過(guò) resourceSelector 進(jìn)行目標(biāo)資源對(duì)象的篩選,對(duì)于篩選出來(lái)的資源對(duì)象,將會(huì)繼續(xù)使用 overrideRules 里面定義的規(guī)則進(jìn)行判斷,如果規(guī)則的 targetOperations 中包含本次操作類(lèi)型,則將使用規(guī)則內(nèi)的 ``overriders生成最終對(duì)象,對(duì)比原始對(duì)象和最終對(duì)象生成 json-patch 所需的 patches 數(shù)組返回給kube-apiserver. 支持兩種類(lèi)的 overriders`:plaintext、cue,前者適用于一些簡(jiǎn)單場(chǎng)景,后者適用于需要根據(jù)傳入數(shù)據(jù)進(jìn)行額外邏輯處理才能得到預(yù)期結(jié)果的場(chǎng)景,能力相對(duì)前者會(huì)更強(qiáng)。
cue 腳本約定了輸入輸出參數(shù),必須包含這些參數(shù)腳本才能成功執(zhí)行。輸入?yún)?shù)只有一個(gè):object,即要操作的資源對(duì)象,輸出參數(shù)為 patches 數(shù)組,定義如下:
object:?_?@tag(object)
patch:?{
?op:?string
?path:?string
?value:?string
}
//?for?mutating?result
patches:?[...patch]?
具體數(shù)據(jù)結(jié)構(gòu)如下:
//?ResourceSelector?the?resources?will?be?selected.
type?ResourceSelector?struct?{
?//?APIVersion?represents?the?API?version?of?the?target?resources.
?//?+required
?APIVersion?string?`json:"apiVersion"`
?//?Kind?represents?the?Kind?of?the?target?resources.
?//?+required
?Kind?string?`json:"kind"`
?//?Namespace?of?the?target?resource.
?//?Default?is?empty,?which?means?inherit?from?the?parent?object?scope.
?//?+optional
?Namespace?string?`json:"namespace,omitempty"`
?//?Name?of?the?target?resource.
?//?Default?is?empty,?which?means?selecting?all?resources.
?//?+optional
?Name?string?`json:"name,omitempty"`
?//?A?label?query?over?a?set?of?resources.
?//?If?name?is?not?empty,?labelSelector?will?be?ignored.
?//?+optional
?LabelSelector?*metav1.LabelSelector?`json:"labelSelector,omitempty"`
}
//?Overriders?offers?various?alternatives?to?represent?the?override?rules.
//
//?If?more?than?one?alternatives?exist,?they?will?be?applied?with?following?order:
//?-?Cue
//?-?Plaintext
type?Overriders?struct?{
?//?Plaintext?represents?override?rules?defined?with?plaintext?overriders.
?//?+optional
?Plaintext?[]PlaintextOverrider?`json:"plaintext,omitempty"`
?//?Cue?represents?override?rules?defined?with?cue?code.
?//?+optional
?Cue?string?`json:"cue,omitempty"`
}
上述例子的效果是對(duì)于任意 Namespace 的 Pod,只要其攜帶 kinitiras.kcloudlabs.io/webhook: enabled Label,則會(huì)修改其 annotation 為 added-by: cue,針對(duì) default 下的 Pod,只要其攜帶 kinitiras.kcloudlabs.io/webhook: enabled Label,則會(huì)修改其 annotation 為 added-by: op。如果兩個(gè)策略同時(shí) apply 到集群中,同時(shí)在 default ?下創(chuàng)建一個(gè) Pod 并攜帶上述 Label,則最終創(chuàng)建的 Pod annotation 將會(huì)是 added-by: op,因?yàn)?OverridePolicy 后執(zhí)行,覆蓋了 ClusterOverridePolicy 的修改。
Validate
內(nèi)置了 ClusterValidatePolicy, 集群級(jí)別生效。針對(duì)同一個(gè)資源對(duì)象,同樣可能存在多條匹配的策略,順序在這里不重要,需要全部策略都通過(guò)之后才算整體校驗(yàn)通過(guò),任意一個(gè)策略校驗(yàn)失敗后將會(huì)拒絕請(qǐng)求。
例:
apiVersion:?policy.kcloudlabs.io/v1alpha1
kind:?ClusterValidatePolicy
metadata:
??name:?test-delete-ns
spec:
??validateRules:
????-?cue:?|-
????????object:?_?@tag(object)
????????reject:?object.metadata.labels?!=?null?&&?object.metadata.labels["kinitiras.kcloudlabs.io/webhook"]?==?"enabled"
????????validate:?{
??????????if?reject{
??????????????????reason:?"operation?rejected"
??????????}
??????????if?!reject{
??????????????????reason:?""
??????????}
??????????valid:?!reject
????????}????????
??????targetOperations:
????????-?DELETE
??resourceSelectors:
????-?apiVersion:?v1
??????kind:?Namespace
通過(guò) resourceSelector 進(jìn)行目標(biāo)資源對(duì)象的篩選,對(duì)于篩選出來(lái)的資源對(duì)象,將會(huì)繼續(xù)使用 validateRules 里面定義的規(guī)則進(jìn)行判斷,如果規(guī)則的 targetOperations 中包含本次操作類(lèi)型,則將使用 cue 腳本進(jìn)行校驗(yàn),檢驗(yàn)結(jié)果返回給 kube-apiserver。與 Mutate 不同的是,Validate 只支持 cue 腳本校驗(yàn)。cue 腳本約定了輸入輸出參數(shù),必須包含這些參數(shù)腳本才能成功執(zhí)行。輸入?yún)?shù)有兩個(gè):object、oldObject,其中后者只有在校驗(yàn) UPDATE 操作時(shí)才需要,輸出參數(shù)為 validate 結(jié)果,定義如下:
object:?_?@tag(object)
oldObject:?_?@tag(oldObject)
//?for?validating?result
validate:?{?
?reason?:?string
?valid:?bool
}
上述例子的效果為阻止刪除帶有 kinitiras.kcloudlabs.io/webhook: enabled 標(biāo)簽的 namespace。
部署
部署 CRD 資源
$?kubectl?apply?-f?https://raw.githubusercontent.com/k-cloud-labs/pkg/main/charts/_crds/bases/policy.kcloudlabs.io_overridepolicies.yaml
$?kubectl?apply?-f?https://raw.githubusercontent.com/k-cloud-labs/pkg/main/charts/_crds/bases/policy.kcloudlabs.io_clusteroverridepolicies.yaml
$?kubectl?apply?-f?https://raw.githubusercontent.com/k-cloud-labs/pkg/main/charts/_crds/bases/policy.kcloudlabs.io_clustervalidatepolicies.yaml
部署應(yīng)用程序
在部署之前,需要先根據(jù)實(shí)際需求修改 webhook-configuration.yaml 文件,盡量縮小目標(biāo)資源對(duì)象的范圍,減少不必要的請(qǐng)求。調(diào)整完所有 yaml 文件之后,只需要執(zhí)行 apply 即可,如下
$?kubectl?apply?-f?deploy/
例子
在 examples 文件夾下內(nèi)置了上述出現(xiàn)過(guò)的三個(gè)策略,可以 apply 到集群進(jìn)行嘗試。
小結(jié)
上面對(duì)項(xiàng)目由來(lái),能力及使用方式進(jìn)行了簡(jiǎn)單介紹,核心還是利用了 admission webhook 來(lái)實(shí)現(xiàn)??赡苡械男』锇閷?duì) admission webhook 的穩(wěn)定性、性能比較謹(jǐn)慎,鑒于此,這里提供了另外一個(gè)項(xiàng)目 pidalio[2],通過(guò)擴(kuò)展 client-go Transport 來(lái)實(shí)現(xiàn),在客戶(hù)端生效,使用簡(jiǎn)單,代碼層面只需要引用對(duì)用的包,并為 rest.Config 設(shè)置自定義的 Transport 即可。如下
import(
?"github.com/k-cloud-labs/pidalio"
)
config.Wrap(pidalio.NewPolicyTransport(config,?stopCh).Wrap)
但 pidalio 存在一個(gè)限制,即只支持 Mutate 操作,且必須使用 client-go 訪問(wèn) kube-apiserver。
引用鏈接
Kinitiras: https://github.com/k-cloud-labs/kinitiras
[2]pidalio: https://github.com/k-cloud-labs/pidalio


你可能還喜歡
點(diǎn)擊下方圖片即可閱讀
2022-05-10
2022-05-09
2022-05-07
2022-05-05

云原生是一種信仰???
關(guān)注公眾號(hào)
后臺(tái)回復(fù)?k8s?獲取史上最方便快捷的 Kubernetes 高可用部署工具,只需一條命令,連 ssh 都不需要!


點(diǎn)擊?"閱讀原文"?獲取更好的閱讀體驗(yàn)!
發(fā)現(xiàn)朋友圈變“安靜”了嗎?

