新聞中心
使用 Gatekeeper 進行 OPA 策略管理
作者:陽明 2022-03-28 07:33:13
云計算
云原生 Gatekeeper(v3.0) 準(zhǔn)入控制器集成了 OPA Constraint Framework,以執(zhí)行基于 CRD 的策略,并允許聲明式配置的策略可靠地共享,使用 kubebuilder 構(gòu)建,它提供了驗證和修改準(zhǔn)入控制和審計功能。

網(wǎng)站設(shè)計制作、成都網(wǎng)站設(shè)計的關(guān)注點不是能為您做些什么網(wǎng)站,而是怎么做網(wǎng)站,有沒有做好網(wǎng)站,給創(chuàng)新互聯(lián)公司一個展示的機會來證明自己,這并不會花費您太多時間,或許會給您帶來新的靈感和驚喜。面向用戶友好,注重用戶體驗,一切以用戶為中心。
前面我們介紹了使用 kube-mgmt 這個 sidecar 容器來完成 OPA 策略的自動同步,此外還有另外一個更加高級的工具 Gatekeeper,相比于之前的模式,Gatekeeper(v3.0) 準(zhǔn)入控制器集成了 OPA Constraint Framework,以執(zhí)行基于 CRD 的策略,并允許聲明式配置的策略可靠地共享,使用 kubebuilder 構(gòu)建,它提供了驗證和修改準(zhǔn)入控制和審計功能。這允許為 Rego 策略創(chuàng)建策略模板,將策略創(chuàng)建為 CRD,并在策略 CRD 上存儲審計結(jié)果,這個項目是谷歌、微軟、紅帽和 Styra 一起合作實現(xiàn)的。
直接使用下面的命令即可安裝 Gatekeeper:
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/release-3.7/deploy/gatekeeper.yaml
默認(rèn)會將 Gatekeeper 安裝到 gatekeeper-system 命名空間下面,同樣會安裝幾個相關(guān)的 CRD:
kubectl get pods -n gatekeeper-system
NAME READY STATUS RESTARTS AGE
gatekeeper-audit-5cf4b9686-glndv 1/1 Running 0 2m2s
gatekeeper-controller-manager-77b7dc99fb-dvkvp 1/1 Running 0 2m2s
gatekeeper-controller-manager-77b7dc99fb-gk4gr 1/1 Running 0 2m2s
gatekeeper-controller-manager-77b7dc99fb-mt5wn 1/1 Running 0 2m2s
kubectl get crd |grep gate
assign.mutations.gatekeeper.sh 2022-03-27T06:47:24Z
assignmetadata.mutations.gatekeeper.sh 2022-03-27T06:47:24Z
configs.config.gatekeeper.sh 2022-03-27T06:47:24Z
constraintpodstatuses.status.gatekeeper.sh 2022-03-27T06:47:24Z
constrainttemplatepodstatuses.status.gatekeeper.sh 2022-03-27T06:47:24Z
constrainttemplates.templates.gatekeeper.sh 2022-03-27T06:47:24Z
modifyset.mutations.gatekeeper.sh 2022-03-27T06:47:24Z
mutatorpodstatuses.status.gatekeeper.sh 2022-03-27T06:47:25Z
providers.externaldata.gatekeeper.sh 2022-03-27T06:47:25Z
Gatekeeper 使用 OPA 約束框架來描述和執(zhí)行策略,在定義約束之前必須首先定義一個 ConstraintTemplate 對象,它描述了強制執(zhí)行約束的 Rego 和約束的模式。約束的模式允許管理員對約束的行為進行微調(diào),就像函數(shù)的參數(shù)一樣。
如下所示是一個約束模板,描述了驗證的對象必須要有標(biāo)簽存在:
# k8srequiredlabels_template.yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
openAPIV3Schema: # Schema for the `parameters` field
type: object
description: Describe K8sRequiredLabels crd parameters
properties:
labels:
type: array
items:
type: string
description: A label string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredlabels
violation[{"msg": msg, "details": {"missing_labels": missing}}] {
provided := {label | input.review.object.metadata.labels[label]}
required := {label | label := input.parameters.labels[_]}
missing := required - provided
count(missing) > 0
msg := sprintf("you must provide labels: %v", [missing])
}
直接應(yīng)用上面的 ConstraintTemplate 資源清單:
kubectl apply -f k8srequiredlabels_template.yaml
constrainttemplate.templates.gatekeeper.sh/k8srequiredlabels created
kubectl get ConstraintTemplate
NAME AGE
k8srequiredlabels 68s
上面我們的定義的 ConstraintTemplate 對象就是一個模板,其中的 crd 部分描述了我們定義的 CRD 模板,比如類型叫 K8sRequiredLabels,需要和模板的名稱保持一致,然后通過下面的 validation 定義了我們的 CRD 的屬性 Schema,比如有一個 labels 的屬性參數(shù),類似是字符串?dāng)?shù)據(jù)類型:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
openAPIV3Schema: # Schema for the `parameters` field
type: object
description: Describe K8sRequiredLabels crd parameters
properties:
labels:
type: array
items:
type: string
description: A label string
然后下面的 targets 部分就是定義的約束目標(biāo),使用 Rego 進行編寫。
- 首先通過 provided := {label | input.review.object.metadata.labels[label]} 獲取到創(chuàng)建對象的所有 label 標(biāo)簽。
- 然后通過 required := {label | label := input.parameters.labels[_]} 獲取到需要提供的 label 標(biāo)簽。
- 將上面兩個標(biāo)簽集合相減(rego語言支持該操作),得到未滿足的 label。
- 斷言未滿足的label數(shù)量>0,如果大于0,說明條件滿足,violation 為 true,說明違反了約束,返回錯誤。
上面的約束模板創(chuàng)建完成后,實際上相當(dāng)于創(chuàng)建了一個名為的 K8sRequiredLabels 對象,我們定義的屬性位于 spec.parameters 屬性下面:
kubectl get K8sRequiredLabels
No resources found
kubectl explain K8sRequiredLabels.spec.parameters.labels
KIND: K8sRequiredLabels
VERSION: constraints.gatekeeper.sh/v1beta1
FIELD: labels <[]string>
DESCRIPTION:
A label string
現(xiàn)在我們就可以使用上面的 K8sRequiredLabels 這個約束模板來定義策略了,比如我們要求在所有命名空間上都定義一個 gatekeeper 的標(biāo)簽,則可以創(chuàng)建如下所示的對象:
# all_ns_must_have_gatekeeper.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: ns-must-have-gk
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Namespace"] # 表示這個約束會在創(chuàng)建命名空間的時候被應(yīng)用,可以使用 namespaceSelector、namespaces等進行過濾
parameters:
labels: ["gatekeeper"] # 根據(jù)schema規(guī)范定義
注意 match 字段,它定義了將應(yīng)用給定約束的對象的范圍,其中 kinds: ["Namespace"] 表示這個約束會在創(chuàng)建命名空間的時候被應(yīng)用,此外它還支持其他匹配器:
- kind 接受帶有 apiGroups 和 kind 字段的對象列表,這些字段列出了約束將應(yīng)用到的對象的組/種類。如果指定了多個組/種類對象,則資源在范圍內(nèi)只需要一個匹配項。
- scope 接受 、Cluster 或 Namespaced 決定是否選擇集群范圍和/或命名空間范圍的資源。(默認(rèn)為)
- namespaces 是命名空間名稱的列表。如果已定義,則約束僅適用于列出的命名空間中的資源。命名空間還支持基于前綴的 glob。例如,namespaces: [kube-*] 匹配 kube-system 和 kube-public。
- excludeNamespaces 是命名空間名稱的列表。如果已定義,則約束僅適用于不在列出的命名空間中的資源。ExcludedNamespaces 還支持基于前綴的 glob,例如,excludedNamespaces: [kube-*] 匹配 kube-system 和 kube-public。
- labelSelector 是標(biāo)準(zhǔn)的 Kubernetes 標(biāo)簽選擇器。
- namespaceSelector 是針對對象的包含名稱空間或?qū)ο蟊旧淼臉?biāo)簽選擇器,如果對象是名稱空間。name 是對象的名稱。如果已定義,則匹配具有指定名稱的對象。Name 還支持基于前綴的 glob。例如,名稱:pod-* 匹配 pod-a 和 pod-b。
下面的 parameters.labels 就是根據(jù)上面的 CRD 規(guī)范定義的屬性,該值是傳遞給 opa 的參數(shù),此處表示一個 key 為 labels,value 為一個列表的字典,與 ConstraintTemplate 里的 properties 要匹配上,此處表示要創(chuàng)建的對象需要含有 gatekeeper 的 label。
直接應(yīng)用上面的這個資源對象即可:
kubectl apply -f all_ns_must_have_gatekeeper.yaml
k8srequiredlabels.constraints.gatekeeper.sh/ns-must-have-gk created
創(chuàng)建完成后可以查看到這個 constraints 對象:
kubectl get k8srequiredlabels
NAME AGE
ns-must-have-gk 73s
kubectl get constraints # 和上面對象一樣
NAME AGE
ns-must-have-gk 81s
由于 Gatekeeper 具有審計功能,可以根據(jù)集群中執(zhí)行的約束條件對資源進行定期評估,以檢測預(yù)先存在的錯誤配置,Gatekeeper 將審計結(jié)果存儲為相關(guān)約束條件的 status 字段中列出違規(guī)行為。我們可以查看 K8sRequiredLabels 對象的 status 字段來查看不符合約束的行為:
kubectl get constraints ns-must-have-gk -o yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
......
status:
auditTimestamp: "2022-03-27T07:42:38Z"
......
totalViolations: 11
violations:
- enforcementAction: deny
kind: Namespace
message: 'you must provide labels: {"gatekeeper"}'
name: apisix
- enforcementAction: deny
kind: Namespace
message: 'you must provide labels: {"gatekeeper"}'
name: default
......
比如現(xiàn)在我們創(chuàng)建一個如下所示的 Namespace:
# test-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: ns-test
labels:
a: b
#gatekeeper: abc
此時不給命名空間添加 key 為 gatekeeper 的 label,創(chuàng)建的時候就會報錯:
Error from server ([ns-must-have-gk] you must provide labels: {"gatekeeper"}): error when creating "test-namespace.yaml": admission webhook "validation.gatekeeper.sh" denied the request: [ns-must-have-gk] you must provide labels: {"gatekeeper"}然后把 gatekeeper: abc 這行的注釋打開,則能成功創(chuàng)建了,這就是 Gatekeeper 的基本用法。
從上面我們可以知道定義約束模板的策略會經(jīng)常從 input 對象中獲取數(shù)據(jù),但是如果需要創(chuàng)建自己的約束,但是不知道傳入的參數(shù)即 input 是什么,有一種簡單方法是使用拒絕所有請求并將請求對象作為其拒絕消息輸出的約束/模板。我們可以在創(chuàng)建模板時在 violation 中只保留一行 msg := sprintf("input: %v", [input]),此時創(chuàng)建對象時必定會失敗,然后獲取到輸出的錯誤信息,里面即包含所有 input 信息,之后再通過 Rego 語法去獲取需要的數(shù)據(jù)即可。
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sdenyall
spec:
crd:
spec:
names:
kind: K8sDenyAll
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sdenyall
violation[{"msg": msg}] {
msg := sprintf("input: %v", [input])
}
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sDenyAll
metadata:
name: deny-all-namespaces
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Namespace"]
由于約束模板或者說策略庫具有一定的通用性,所以 OPA Gatekeeper 社區(qū)提供了一個通用的策略庫:https://github.com/open-policy-agent/gatekeeper-library,該倉庫中包含了大量通用的約束模板。
每個模板庫下面都包含一個 template.yaml 文件用來描述約束模板,samples 目錄下面就包含具體的約束對象和示例資源清單,這些策略也是我們?nèi)W(xué)習(xí) Rego 語言的很好的案例。
網(wǎng)站名稱:使用Gatekeeper進行OPA策略管理
當(dāng)前地址:http://m.fisionsoft.com.cn/article/dhcdcio.html


咨詢
建站咨詢
