السلسلة: هذا الدرس جزء من سلسلة شهادة CKS. للحصول على نظرة شاملة، اقرأ المقال الرئيسي أولاً.
مقدمة
المجال 4 «Minimize Microservice Vulnerabilities» يزن 20% من امتحان CKS. يختبر قدرتك على تطبيق سياسات قبول صارمة تحجب عند الإنشاء أي Pod لا تحترم معايير الأمان — capabilities مفرطة، runAsRoot، hostNetwork، mounts حساسة. أداتان لا غنى عنهما: Pod Security Standards (مدمَجة أصلياً في Kubernetes منذ 1.25) وOPA Gatekeeper (policies إعلانية بـ Rego، أكثر مرونة). هذا الدرس يطبّق الاثنتين على عنقود kind 1.34، يبيّن الفروق، ويضبط استراتيجية دفاع متعدّد الطبقات.
المتطلبات
- عنقود kind 1.34 شغّال
- 40 دقيقة
الخطوة 1 — تفعيل Pod Security Standards Restricted على namespace
Pod Security Standards (PSS) خليفة PodSecurityPolicy. يُفعَّل عبر labels على مستوى namespace، بلا تثبيت إضافي. ثلاث مستويات: Privileged (بلا قيود)، Baseline (مضاد للتصعيد)، Restricted (تحصين أقصى).
kubectl create namespace secure-zone
kubectl label namespace secure-zone \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/audit=restricted \
pod-security.kubernetes.io/warn=restricted
# اختبار بـ Pod غير مطابق
kubectl run nginx --image=nginx:1.27 -n secure-zone
# يجب أن يفشل: Restricted يطلب runAsNonRoot، capabilities drop، إلخ.
Pod nginx الكلاسيكية مرفوضة لأن الصورة تشتغل root افتراضياً. هذا السلوك المنتظر — يجب توفير manifest يلبّي قيود Restricted ليُقبَل.
الخطوة 2 — إنشاء Pod مطابقة Restricted
Pod مطابقة Restricted تتطلب: runAsNonRoot، runAsUser غير صفر، allowPrivilegeEscalation false، capabilities drop ALL، seccompProfile RuntimeDefault.
cat > /tmp/pod-restricted.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: secure-app
namespace: secure-zone
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: nginxinc/nginx-unprivileged:1.27
ports:
- containerPort: 8080
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
runAsNonRoot: true
EOF
kubectl apply -f /tmp/pod-restricted.yaml
kubectl get pod secure-app -n secure-zone
لاحظ استخدام nginxinc/nginx-unprivileged — صورة nginx الرسمية تشتغل root على المنفذ 80، بينما نسخة unprivileged تشتغل uid 101 على المنفذ 8080. لأحمال CKS، فضّل الصور المصمَّمة للتشغيل بلا امتيازات.
الخطوة 3 — تثبيت OPA Gatekeeper
OPA (Open Policy Agent) Gatekeeper يُوسّع Kubernetes بـ admission webhook يقيّم كل إنشاء/تعديل لمورد ضدّ policies Rego. أكثر مرونة من PSS المحدود بقيود معرَّفة سلفاً.
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/v3.22.0/deploy/gatekeeper.yaml
sleep 30
kubectl get pods -n gatekeeper-system
kubectl wait --for=condition=ready pod -l control-plane=controller-manager -n gatekeeper-system --timeout=120s
بمجرد تشغيل Gatekeeper، webhook يعترض كل طلبات API. بلا ConstraintTemplate ولا Constraint، يدع كل شيء يمرّ. الخطوة التالية تضيف القواعد.
الخطوة 4 — سياسة أولى — حظر الصور من Docker Hub
حالة استخدام كلاسيكية: فرض كل الصور لتأتي من registry داخلي (Harbor، ECR، GCR). نبدأ بـ ConstraintTemplate يعرّف المنطق بـ Rego، ثم نُجسّده عبر Constraint.
cat > /tmp/template-allowed-repos.yaml <<'EOF'
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sallowedrepos
spec:
crd:
spec:
names:
kind: K8sAllowedRepos
validation:
openAPIV3Schema:
type: object
properties:
repos:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sallowedrepos
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
satisfied := [good | repo = input.parameters.repos[_]; good = startswith(container.image, repo)]
not any(satisfied)
msg := sprintf("container image %v not allowed from repos %v", [container.image, input.parameters.repos])
}
EOF
kubectl apply -f /tmp/template-allowed-repos.yaml
cat > /tmp/constraint-allowed-repos.yaml <<'EOF'
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
name: only-corporate-registry
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
excludedNamespaces: ["kube-system","gatekeeper-system"]
parameters:
repos:
- "registry.example.com/"
- "ghcr.io/myorg/"
EOF
kubectl apply -f /tmp/constraint-allowed-repos.yaml
sleep 5
# اختبار: Pod nginx عامة يجب أن تُرفض
kubectl run test-block --image=nginx:1.27 -n default
# يجب أن يفشل مع انتهاك Gatekeeper
Pod مرفوضة برسالة صريحة «container image nginx:1.27 not allowed from repos». هذا تماماً السلوك المنتظر في الإنتاج: لا صورة غير مُتحقَّق منها يمكن أن تبلغ العنقود.
الخطوة 5 — سياسة حظر hostPath
volumes hostPath باب مفتوح: Pod مخترَقة تستطيع قراءة/كتابة على نظام ملفات العقدة. سياسة CKS جيدة تحجب hostPath إلا في حالات استثنائية موثَّقة.
cat > /tmp/template-no-hostpath.yaml <<'EOF'
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8snohostpath
spec:
crd:
spec:
names:
kind: K8sNoHostPath
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8snohostpath
violation[{"msg": msg}] {
volume := input.review.object.spec.volumes[_]
volume.hostPath
msg := sprintf("hostPath volumes are forbidden, found %v", [volume.name])
}
EOF
kubectl apply -f /tmp/template-no-hostpath.yaml
cat > /tmp/constraint-no-hostpath.yaml <<'EOF'
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sNoHostPath
metadata:
name: forbid-hostpath
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
excludedNamespaces: ["kube-system","gatekeeper-system"]
EOF
kubectl apply -f /tmp/constraint-no-hostpath.yaml
اختبار: حاول تطبيق Pod مع hostPath volume — تُرفض فوراً من Gatekeeper. هذه السياسة وحدها تحجب نحو 30% من escapes container الموثَّقة.
الخطوة 6 — وضع Audit للاكتشاف قبل التطبيق
قبل التحوّل إلى enforce، تبدأ كثير من الفرق في audit: Gatekeeper يُسجّل الانتهاكات دون حجبها، ما يسمح بقياس أثر سياسة جديدة.
# رؤية الانتهاكات المكتشفة (audit mode)
kubectl get k8snohostpath forbid-hostpath -o yaml | grep -A 20 status
كتلة status.violations تسرد كل الموارد المنتهكة. في وضع enforcement، تحجب هذه الانتهاكات الإنشاءات الجديدة لكنها لا تحذف Pods الموجودة — يجب تصحيحها واحدة واحدة.
الخطوة 7 — الجمع بين PSS وOPA Gatekeeper
PSS وGatekeeper متكاملان. PSS يدير القيود المعيارية لـ Kubernetes (security context، capabilities، host namespaces). Gatekeeper يدير قيود الأعمال (whitelist registry، labels إلزامية، ResourceQuotas مخصّصة). اجمع الاثنين: PSS على مستوى namespace، Gatekeeper للقواعد العالمية.
# تحقق من توافق النظامين على Pod اختباري
cat > /tmp/test-combined.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: combined-test
namespace: secure-zone
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: registry.example.com/nginx:1.27
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
EOF
kubectl apply -f /tmp/test-combined.yaml
# مرفوض من Gatekeeper (registry ليست في القائمة)
إن حاولنا بصورة registry معتمَدة (ghcr.io/myorg/nginx) ومع security context مطابق PSS، Pod تمرّ. هذا وضع الدفاع متعدّد الطبقات المطلوب.
الخطوة 8 — Sandbox runtime gVisor (تقديم)
gVisor هو runtime حاوية user-space يعزل أكثر من runc باعتراض syscalls. موصى به للأحمال غير الموثوقة. الإعداد الكامل يتطلب تعديل containerd config وإنشاء RuntimeClass.
cat > /tmp/runtimeclass-gvisor.yaml <<'EOF'
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: gvisor
handler: runsc
EOF
# Pod تستخدم gVisor:
cat > /tmp/pod-gvisor.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: untrusted-workload
spec:
runtimeClassName: gvisor
containers:
- name: app
image: nginx:1.27
EOF
لـ kind، gVisor ليس مُثبَّتاً مسبقاً. في الإنتاج، إنه خيار لاستضافة كود مستخدم أو أحمال غير مُتحقَّقة. يقع في المجال 4 كـ «sandbox runtime».
فهم الفرق Validating مقابل Mutating Admission Webhook
Kubernetes لها نوعان من webhooks القبول. Validating يقول نعم أو لا لإنشاء/تعديل — ما يستخدمه Gatekeeper. Mutating يستطيع تعديل المورد قبل تخزينه — ما تفعله Istio لحقن sidecars Envoy. الاثنان قد يتعايشان: Mutating يُنفَّذ أولاً (يحوّل المورد)، ثم Validating (يتحقق من النسخة النهائية).
OPA Gatekeeper يدعم الوضعين منذ v3.10. لـ CKS v1.34، توقّع أسئلة عن Validating أساساً، أحياناً عن Mutating لتحويل manifests.
أخطاء شائعة
| الخطأ | السبب | الحل |
|---|---|---|
| PSS Restricted يرفض Pods الموجودة | صور تشتغل root | هاجر إلى nginx-unprivileged، bitnami/postgresql إلخ |
| Gatekeeper يدع Pods تمرّ | ConstraintTemplate طُبِّق دون Constraint | كلاهما ضروري: Template ثم Constraint الذي يجسّده |
| سياسة Rego لا تتطابق أبداً | مسار خاطئ في input.review.object | اختبر عبر gator test محلياً قبل النشر |
| PSS وGatekeeper في تعارض | قواعد متكرّرة لكن غير متزامنة | وثّق مشاركة المسؤولية: PSS للمعايير K8s، Gatekeeper للأعمال |
| RuntimeClass gvisor غير موجودة | gVisor غير مُثبَّت على العقد | اتبع doc gvisor.dev/docs/user_guide/install لـ containerd |
دروس مرافقة
أسئلة شائعة
هل OPA Gatekeeper أم Kyverno؟
الاثنان صالحان. Gatekeeper يستخدم Rego (قوي لكن منحنى تعلّم)، Kyverno يستخدم YAML إعلانياً (أبسط). لـ CKS، Gatekeeper في المنهج الرسمي.
هل يمكن فعل كل شيء بـ PSS بلا Gatekeeper؟
لا. PSS يدير فقط قيود Kubernetes المعرَّفة سلفاً. للقواعد البيزنس (registry، labels، quotas مخصّصة)، admission webhook مطلوب.