الامتثال والسياسات ككود

Gatekeeper و Kyverno

18 دقيقة الدرس 5 من 27

Gatekeeper & Kyverno

كل كلاستر Kubernetes هو سطح لتطبيق السياسات. بدون حواجز حماية، يمكن للمطورين نشر حاويات تعمل بصلاحيات الجذر (root)، أو صور مسحوبة من سجلات غير موثوقة، أو أحمال عمل لا تحدد حدوداً للموارد فتُجوّع الـ pods الأخرى. آلية admission controller في Kubernetes صُممت تحديداً لهذا الغرض: كل طلب يصل إلى خادم API يمر عبر سلسلة من webhooks الـ admission قبل أن يُخزَّن في etcd. مشروعان يهيمنان على تطبيق السياسات في الإنتاج عند هذه الطبقة — OPA Gatekeeper (مبني على محرك Open Policy Agent) وKyverno (مصمم خصيصاً لـ Kubernetes بدون لغة سياسة منفصلة). معرفة متى تستخدم كلاً منهما، وأوضاع الفشل لكليهما، أمر ضروري على نطاق المؤسسات الكبرى.

كيف يعمل Admission في Kubernetes

عندما يصل kubectl apply إلى خادم API، يمر الطلب عبر المصادقة (Authentication)، ثم التفويض (RBAC)، ثم فئتين من webhooks الـ admission: Mutating (يمكنه إعادة كتابة الكائن) وValidating (يمكنه فقط السماح أو الرفض). كل من Gatekeeper وKyverno يسجل نفسه كـ webhooks من هذا النوع. إذا كان الـ webhook غير متاح وكانت failurePolicy مضبوطة على Fail، يُرفض الكائن — وهذا هو الإعداد الآمن في الإنتاج. إذا كانت مضبوطة على Ignore، يُتجاوَز الـ webhook بصمت عند انقطاعه، اختر بعناية.

Kubernetes admission controller request flow kubectl apply API Server Authn / Authz Admission Mutating Webhooks Validating Webhooks etcd persisted OPA Gatekeeper ConstraintTemplate + Rego Kyverno ClusterPolicy (YAML) Deny → 403 to caller failurePolicy: Fail (آمن) / Ignore (خطر التجاوز)
مسار طلب الـ admission في Kubernetes: تعمل Mutating webhooks أولاً، ثم Validating. يسجل كل من Gatekeeper وKyverno نفسيهما كـ validating webhooks؛ كما يسجل Kyverno mutating webhook لقواعد التعديل.

OPA Gatekeeper — ConstraintTemplates والـ Constraints

يُوسّع Gatekeeper نظام Kubernetes بنوعين من الكائنات المخصصة. يُعرّف ConstraintTemplate مخطط سياسة قابل لإعادة الاستخدام مدعوماً بقاعدة Rego. أما Constraint فهو نسخة من ذلك القالب تُطبَّق على أنواع موارد ونطاقات اسم محددة. هذا الفصل يعني أن فرق المنصة تمتلك القوالب، بينما يمكن لفرق المنتج إنشاء constraints بمعاملات مختلفة.

ثبّت Gatekeeper باستخدام Helm وطبّق constraint يمنع الحاويات من العمل كمستخدم root:

# تثبيت Gatekeeper helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts helm install gatekeeper gatekeeper/gatekeeper \ --namespace gatekeeper-system --create-namespace \ --set replicas=3 \ --set controllerManager.resources.requests.memory=512Mi # ConstraintTemplate: يُعرّف قاعدة Rego ومخطط CRD cat <<'EOF' | kubectl apply -f - apiVersion: templates.gatekeeper.sh/v1 kind: ConstraintTemplate metadata: name: k8snoroot spec: crd: spec: names: kind: K8sNoRoot targets: - target: admission.k8s.gatekeeper.sh rego: | package k8snoroot violation[{"msg": msg}] { container := input.review.object.spec.containers[_] not container.securityContext.runAsNonRoot msg := sprintf("Container %v must set runAsNonRoot: true", [container.name]) } violation[{"msg": msg}] { container := input.review.object.spec.containers[_] container.securityContext.runAsUser == 0 msg := sprintf("Container %v must not run as UID 0", [container.name]) } EOF # Constraint: تطبيق القالب على جميع الـ pods خارج نطاقات النظام cat <<'EOF' | kubectl apply -f - apiVersion: constraints.gatekeeper.sh/v1beta1 kind: K8sNoRoot metadata: name: deny-root-containers spec: enforcementAction: deny match: kinds: - apiGroups: [""] kinds: ["Pod"] excludedNamespaces: - kube-system - gatekeeper-system EOF
أوضاع enforcementAction: يحجب deny الطلب؛ يسمح warn به لكنه يُعيد تحذيراً في استجابة الـ API (مفيد أثناء الطرح التدريجي)؛ يسجّل dryrun الانتهاكات دون حجب (قابل للمشاهدة عبر kubectl get constraint deny-root-containers -o yaml تحت status.violations). ابدأ دائماً بـ dryrun في الإنتاج، تحقق من انخفاض عدد الانتهاكات إلى صفر، ثم انتقل إلى deny.

Kyverno — سياسات مصممة لـ Kubernetes

يتعامل Kyverno مع كائنات Kubernetes باعتبارها لغة السياسة نفسها. السياسات هي وثائق YAML تُطابق الكائنات الواردة باستخدام كتل match/exclude، ثم تُطبّق قواعد validate أو mutate أو generate. المهندسون الذين يعرفون كائنات Kubernetes يستطيعون قراءة سياسات Kyverno وكتابتها دون تعلم Rego، مما يخفض الحاجز بشكل كبير لفرق المنصة.

# تثبيت Kyverno helm repo add kyverno https://kyverno.github.io/kyverno/ helm install kyverno kyverno/kyverno \ --namespace kyverno --create-namespace \ --set replicaCount=3 # ClusterPolicy: التحقق من أن جميع الـ pods تحدد حدوداً للموارد cat <<'EOF' | kubectl apply -f - apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: require-resource-limits annotations: policies.kyverno.io/title: Require Resource Limits policies.kyverno.io/severity: medium spec: validationFailureAction: Enforce # Audit = تحذير فقط background: true # فحص الموارد الموجودة أيضاً rules: - name: check-limits match: any: - resources: kinds: [Pod] exclude: any: - resources: namespaces: [kube-system, kyverno] validate: message: "يجب أن تُعرّف جميع الحاويات حدوداً للـ CPU والذاكرة." pattern: spec: containers: - name: "*" resources: limits: memory: "?*" cpu: "?*" EOF # تعديل Kyverno: حقن سياق أمان افتراضي إن غاب cat <<'EOF' | kubectl apply -f - apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: add-default-securitycontext spec: rules: - name: add-secctx match: any: - resources: kinds: [Pod] mutate: patchStrategicMerge: spec: containers: - (name): "*" securityContext: +(runAsNonRoot): true +(allowPrivilegeEscalation): false +(readOnlyRootFilesystem): true EOF

صيغة +(field) في تعديلات Kyverno تعني "أضف هذا الحقل فقط إن لم يكن موجوداً" — لن يُلغي القيم التي يضبطها المطور صراحةً. هذا يجعل التعديلات آمنة للتطبيق على مستوى الأسطول دون كسر التطبيقات التي تُهيّئ سياقات الأمان بشكل صحيح مسبقاً.

Gatekeeper مقابل Kyverno — متى تختار كلاً منهما

كلا المشروعين من CNCF وكلاهما جاهز للإنتاج. الاختيار الصحيح يعتمد على فريقك وحالة الاستخدام:

  • اختر Gatekeeper إذا كنت تستخدم OPA بالفعل في بنيتك (Terraform، تفويض التطبيقات)، أو تريد لغة سياسة موحدة عبر جميع نقاط التطبيق، أو تحتاج منطقاً معقداً جداً يستفيد من تقييم Rego بأسلوب datalog. كما أن الفصل بين constraint template والـ constraint يتناسب جيداً مع نموذج "فريق المنصة يمتلك السياسة، فريق المنتج يُنشئ النسخ".
  • اختر Kyverno إذا أراد فريق منصتك سياسات يستطيع قراءتها وتعديلها أي مهندس يعرف Kubernetes، أو إذا كنت تحتاج قدرات تعديل وتوليد مدمجة دون كتابة webhook منفصل. كما يتضمن Kyverno مكتبة سياسات تحتوي أكثر من 200 سياسة جاهزة للاستخدام على kyverno.io/policies.
إعداد HA في الإنتاج: كلا الأداتين تتطلبان نسخاً متعددة خلف Kubernetes Service. webhook سياسة بنسخة واحدة هو نقطة فشل واحدة على مستوى الكلاستر — إذا تعطل الـ pod أثناء نشر وfailurePolicy: Fail مضبوطة، يُحجب كل pod جديد في الكلاستر. شغّل على الأقل 3 نسخ موزعة عبر العقد باستخدام podAntiAffinity، واستخدم PodDisruptionBudget مع minAvailable: 2 للحماية من استنزاف العقد.

وضع المراجعة والاستثناءات

تدعم كلتا الأداتين فحص الموارد الموجودة (ليس فقط الجديدة) مقابل السياسات. في Gatekeeper، اضبط enforcementAction: dryrun واستعلم عن الانتهاكات بـ kubectl get constraint -o jsonpath='{.items[*].status.violations}'. في Kyverno، اضبط validationFailureAction: Audit وتحقق من كائنات PolicyReport (معيار CNCF): kubectl get polr -A.

عندما يحتاج حمل عمل محدد لاستثناء مشروع — كتطبيق قديم يجب فعلاً أن يعمل كـ root — توفر كلتا الأداتين آليات استثناء محددة النطاق. في Gatekeeper، أضف إلى spec.match.excludedNamespaces أو استخدم spec.match.labelSelector. في Kyverno، استخدم كتلة exclude مع محدد تسمية. وثّق كل استثناء في تعليق داخل ملف YAML للسياسة، اربطه بـ git، وراجع الاستثناءات كل ربع سنة — الاستثناءات غير المراقبة تتراكم لتصبح مسؤولية امتثال.

مهلة الـ webhook خطر انقطاع خدمة في الإنتاج: تبلغ المهلة الافتراضية لـ webhooks كلا من Gatekeeper وKyverno 10 ثواني. إذا كانت pods الـ webhook تحت حمل ثقيل وتجاوز وقت الاستجابة هذا الحد، يعامله خادم API كفشل ويُطبق failurePolicy. في كلاستر تحت ضغط أثناء نشر، يمكن أن يتصاعد هذا: لا يمكن بدء pods جديدة، مما يزيد الحمل على الـ pods الموجودة، مما يزيد زمن استجابة الـ webhook. راقب زمن استجابة p99 للـ webhook (gatekeeper_webhook_duration_seconds / kyverno_admission_requests_total) واضبط طلبات الموارد عالياً بما يكفي لمنع تقييد pods الـ webhook.