在本文中,我們將演示如何使用OPA執(zhí)行最細(xì)粒度的安全策略。請(qǐng)注意,本文是一個(gè)系列的一部分,我們將基于“OPA作為代碼介紹”和“集成OPA到Kubernetes”中獲得的知識(shí)進(jìn)行。如果你還沒(méi)有這樣做,請(qǐng)瀏覽本系列中已發(fā)表的文章。
https://www.magalix.com/blog/introducing-policy-as-code-the-open-policy-agent-opa
https://www.magalix.com/blog/integrating-open-policy-agent-opa-with-kubernetes-a-deep-dive-tutorial
你可能已經(jīng)熟悉Pod安全策略,可以在其中對(duì)Pod應(yīng)用非常特定的安全控制。例如,使用Linux內(nèi)核功能,使用主機(jī)命名空間、網(wǎng)絡(luò)、端口或文件系統(tǒng),以及其他許多功能。使用OPA,你還可以對(duì)pods施加類似的控制,在本實(shí)驗(yàn)室中,我們將創(chuàng)建一個(gè)OPA策略,不允許在pods中創(chuàng)建有特權(quán)的容器。特權(quán)容器對(duì)主機(jī)的訪問(wèn)級(jí)別比非特權(quán)容器高。
為什么使用OPA而不是原生的Pod安全策略?
使用Pod安全策略來(lái)執(zhí)行我們的安全策略并沒(méi)有什么問(wèn)題。然而,根據(jù)定義,PSP只能應(yīng)用于pods。它們不能處理其他Kubernetes資源,如Ingresses、Deployments、Services等。OPA的強(qiáng)大之處在于它可以應(yīng)用于任何Kubernetes資源。OPA作為一個(gè)許可控制器部署到Kubernetes,它攔截發(fā)送到API服務(wù)器的API調(diào)用,并驗(yàn)證和/或修改它們。相應(yīng)地,你可以有一個(gè)統(tǒng)一的OPA策略,適用于系統(tǒng)的不同組件,而不僅僅是pods。例如,有一種策略,強(qiáng)制用戶在其服務(wù)中使用公司的域,并確保用戶只從公司的鏡像存儲(chǔ)庫(kù)中提取鏡像。請(qǐng)注意,我們使用的OPA是使用kube-mgmt部署的,而不是OPA Gatekeeper。
Rego的策略代碼
在本文中,我們假設(shè)你已經(jīng)熟悉了OPA和Rego語(yǔ)言。我們還假設(shè)你有一個(gè)正在運(yùn)行的Kubernetes集群,該集群部署了OPA和kube-mgmt容器。有關(guān)安裝說(shuō)明,請(qǐng)參閱我們的前一篇文章。我們的no-priv-pod.rego文件如下所示:
package kubernetes.admission
deny[msg] {
c := input_containers[_]
c.securityContext.privileged
msg := sprintf("Privileged container is not allowed: %v, securityContext: %v", [c.name, c.securityContext])
}
input_containers[c] {
c := input.request.object.spec.containers[_]
}
input_containers[c] {
c := input.request.object.spec.initContainers[_]
}
讓我們簡(jiǎn)要地瀏覽一下這個(gè)文件:
第1行:包含package。注意,你必須使用kubernetes.admission讓政策工作。
第2行:Deny是默認(rèn)對(duì)象,它將包含我們需要執(zhí)行的策略。如果所包含的代碼計(jì)算結(jié)果為true,則將違反策略。
第3行:我們定義了一個(gè)變量,它將容納pod中的所有容器,并從稍后定義的input_containers[c]接收值。
第4行:如果pod包含“privileged”屬性,則該語(yǔ)句為true。
第5行:當(dāng)用戶嘗試運(yùn)行特權(quán)容器時(shí)顯示給他們的消息。它包括容器名稱和違規(guī)的安全上下文。
第7-9行:input_containers[c]函數(shù)從請(qǐng)求對(duì)象中提取容器。注意,使用了_字符來(lái)遍歷數(shù)組中的所有容器。在Rego中,你不需要定義循環(huán)—下劃線字符將自動(dòng)為你完成此操作。
第10-12行:我們?cè)俅螢閕nit容器定義函數(shù)。請(qǐng)注意,在Rego中,可以多次定義同一個(gè)函數(shù)。這樣做是為了克服Rego函數(shù)中不能返回多個(gè)輸出的限制。當(dāng)調(diào)用函數(shù)名時(shí),將執(zhí)行兩個(gè)函數(shù),并使用AND操作符組合輸出。因此,在我們的例子中,在一個(gè)或多個(gè)位置中存在一個(gè)有特權(quán)的容器將違反策略。
部署策略
OPA會(huì)在opa命名空間的ConfigMaps中找到它的策略。要將我們的代碼應(yīng)用到ConfigMap中,我們運(yùn)行以下命令:
kubectl create configmap no-priv-pods --from-file=no-priv-pod.rego
kube-mgmt邊車(sidecar)容器在opa命名空間中持續(xù)監(jiān)視API服務(wù)器,以便你只需創(chuàng)建ConfigMap就可以部署策略。
運(yùn)行策略
讓我們通過(guò)嘗試部署一個(gè)特權(quán)容器來(lái)確保我們的策略是有效的:
kubectl -n default apply -f - <<EOT
apiVersion: v1
kind: Pod
metadata:
name: nginx-privileged
labels:
app: nginx-privileged
spec:
containers:
- name: nginx
image: nginx
securityContext:
privileged: true #false
EOT
Error from server (Privileged container is not allowed: nginx, securityContext: {"privileged": true}): error when creating "STDIN": admission webhook "validating-webhook.openpolicyagent.org" denied the request: Privileged container is not allowed: nginx, securityContext: {"privileged": true}
請(qǐng)注意,我們有意將pod部署到默認(rèn)命名空間,因?yàn)槲覀兊腶dmission webhook將忽略在opa命名空間或kube-system中創(chuàng)建的任何資源。
總結(jié)
OPA是一種通用的、平臺(tái)無(wú)感的策略實(shí)施工具,可以通過(guò)多種方式與Kubernetes集成。
你可以使用OPA策略來(lái)模擬Pod安全策略,以防止在集群上調(diào)度特權(quán)容器。
因?yàn)镺PA可以與其他Kubernetes資源一起工作,而不僅僅是Pods,所以建議使用它來(lái)創(chuàng)建跨越所有相關(guān)資源的集群級(jí)策略文檔。