Kubernetes Güvenliği ve Uyumluluğu Sağlamak İçin Open Policy Agent ve Gatekeeper

Cahit Yusuf KAFADAR ( CKAD | CKA )
riseconsulting
Published in
4 min readSep 11, 2023

Kubernetes Gatekeeper, OPA’nın Kubernetes ortamında kullanımını sağlayan bir proje olarak ortaya çıkar. Bu araç, Kubernetes kaynaklarını denetlemek ve belirli güvenlik ve uyumluluk politikalarına uymalarını sağlamak için OPA’yı kullanır. Örneğin, Gatekeeper sayesinde bir Kubernetes kaynağı, tanımlanan politikalara uymadığında oluşturulamaz veya güncellenemez. Bu, uygulama ve hizmetlerin güvenliğini ve uyumluluğunu sağlamak için önemlidir.

Kubernetes Gatekeeper, aşağıdaki temel bileşenlerden oluşur:

  • Admission Controller: Kubernetes API sunucusu ile etkileşimde bulunur ve gelen istekleri denetler. Politika kararlarını alır ve kaynakların kabul edilip edilmeyeceğine karar verir.
  • Constraint Templates: Bu şablonlar, belirli bir politikanın nasıl tanımlanacağını belirler. Özelleştirilmiş politikalar oluşturmak için kullanılırlar.
  • Constraints: Constraint Templates kullanılarak tanımlanan politikaları uygular. Her bir Constraint, kaynaklara uygulanan belirli bir politikayı temsil eder.

Open Policy Agent ve Kubernetes Gatekeeper, Kubernetes çevresinde güvenlik ve uyumluluk sağlamak için güçlü bir çözüm sunar. Bu araçlar, Kubernetes çevrenizi daha güvenli ve düzenli hale getirmenize yardımcı olabilir ve organizasyonunuzun politika gereksinimlerine uygunluğunu sağlayabilir.

Kubernetes dünyasına Open Policy Agent ve Kubernetes Gatekeeper’ın nasıl entegre edileceğine bir göz atalım ve bazı örnekler yapalım.

Kubernetes Gatekeeper kurumunu tek bir komut ile bir repo içinde bulunan tüm configurasyonları tek seferde çalıştırıp yapabilirsiniz.

kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/master/deploy/gatekeeper.yaml

Yada Helm chart olarak kurumunu gerçekleştirebilirisiniz.

helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm install gatekeeper/gatekeeper --name-template=gatekeeper --namespace gatekeeper-system --create-namespace

Kurulum sonucunda Cluster’da “gatekeeper-system” isimli bir namespacede 3 repilicadan oluşan “gatekeeper-controller-manager” isimli bir deployment ve tek replicadan oluşan “gatekeeper-audit” bir deployment oluşur.

Şimdi sıra bir “Constraint Templates” oluşturup bu template ile çalışan “Constraints” oluşturmakta.

“Constraint Templates” örneğimiz “k8srequiredlabels” isimli bir kısıtlama şablonu ile olacak.

apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
# Schema for the `parameters` field
openAPIV3Schema:
type: object
properties:
labels:
type: array
items:
type: 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])
}

Bu ConstraintTemplate configurasyonu ile çalışan “Constraints” yapılandırmaları “targets” altında bulunan kod parçacığını esas alarak bir hata üretir ve kısıt ihlali gerçekleşirse,

msg := sprintf("you must provide labels: %v", [missing])

kod parçacığı çalışır. ConstraintTemplate tanımlanan bu küçük kod parçacığını aşağıda satır satır açıklamaya çalışcağım.

rego: Bu bölüm, Rego adı verilen bir dil kullanarak kısıtlamanın kurallarını tanımlar. Bu Rego betiği, K8s kaynağının etiketlerini doğrular. Kurallar şunları içerir:

  • violation: Eğer bir ihlal (violation) gerçekleşirse, bu kural tetiklenir. İhlal gerçekleştiğinde, bir msg (mesaj) ve eksik etiketlerin bir listesi olan missing_labels ayrıntıları döndürülür.
  • provided: input.review.object.metadata.labels içindeki tüm etiketleri provided olarak tanımlar. Yani oluşacak olan kaynakta bulunan tüm etiketlerin bi listesiprovided olarak adlandırılır.
  • required: input.parameters.labels içinde belirtilen tüm etiketleri required olarak tanımlar. Aslında bu kısımda kaynakta olması gereken tüm Label’ları tanımlar.
  • missing: required etiketler kümesinden provided etiketler kümesini çıkararak eksik etiketleri bulur.
  • count(missing) > 0: Eğer eksik etiketlerin sayısı 0'dan büyükse, ihlal tetiklenir.
  • msg := sprintf("you must provide labels: %v", [missing]): İhlal tetiklendiğinde, bir hata mesajı oluşturulur. Bu mesaj, eksik etiketlerin listesini içerir.

Şimdi kod parçacığında bulunan “required” Label’lardan bir tanesini “Constraint” ile biz tanımlayalım.

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: ns-must-have-gk
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Namespace"]
parameters:
labels: ["gatekeeper-ns"]

“K8sRequiredLabels” tanımı ile“Namespace” kaynaklarında “gatekeeper-ns” Label’ının olması gerektiğini ifade ediyoruz.

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: pod-must-have-gk
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters:
labels: ["gatekeeper-pod"]

Bu “K8sRequiredLabels” tanımı ile“Pod” kaynaklarında “gatekeeper-pod” Label’ının olması gerektiğini ifade ediyoruz.

Şimdi sırası ile önce bir “ConstraintTemplate” uygulaması olan “k8srequiredlabels” daha sonra “Constraint” uygulaması olan ve Pod ve Namespace kaynaklarına bir Label ekleme zorunluluğunu bgetiren “K8sRequiredLabels” kaynaklarını çalıştıralım. Herşey yolunda gittiyse aşağıdaki çıktıyı göreceksiniz.

Şimdi test yapalım.

Görüldüğü gibi “Namespace” kaynağına “gatekeeper-ns” Label’ı “Pod” kaynağınada “gatekeeper-pod” eklemediğimiz için “msg := sprintf(“you must provide labels: %v”, [missing])” komut satırı çalıştı ve kaynaklar oluşmadı.

Şimdi oluşturmak istediğimiz kaynaklara ilgili Label’ları ekleyelim.

apiVersion: v1
kind: Namespace
metadata:
name: test-namespace
labels:
gatekeeper-ns: test
apiVersion: v1
kind: Pod
metadata:
labels:
run: nginx
gatekeeper-pod: test
name: nginx
spec:
containers:
- image: nginx
name: nginx
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}

Burada belirtilen Pod ve Namespace kaynaklarını oluşturmak istediğinizde artık başarılı olacaksınız.

Görüşmek dileğiyle.

--

--