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

مشروع: إطار السياسة كرمز

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

مشروع: إطار السياسة كرمز

غطّت الدروس التسعة السابقة المفاهيم والأدوات والأنماط الفردية للسياسة كرمز. يجمع هذا الدرس الختامي كل ذلك في إطار حواجز حماية متعدد الطبقات — من النوع الذي تصمّمه وتقدّمه في مراجعة هندسية من المستوى الأعلى قبل نشره عبر مؤسسة متعددة الفرق. في النهاية ستمتلك مخططاً يغطي ثلاث طائرات تطبيق: المؤسسة (مستوى حساب السحابة)، والكلاستر (قبول Kubernetes)، والأنبوب (بوابات CI في مرحلة مبكرة).

المبدأ التصميمي الأساسي هو الحماية بالعمق للسياسة. لا توجد طبقة واحدة مثالية، لذا يُطبَّق كل ضابط حرج مرتين على الأقل في نقاط مختلفة من دورة التسليم. لا يستطيع المطوّر تجاوز بوابة الأنبوب بالدفع إلى فرع ميزة، ولا تجاوز بوابة الكلاستر بالدفع مباشرة إلى السجل دون أن يفشل أيضاً في التحقق من صحة الموارد على مستوى المؤسسة.

الطبقة الأولى — حواجز المؤسسة (مستوى مستوى التحكم السحابي)

في طبقة المؤسسة، تعمل السياسات في مستوى التحكم السحابي نفسه. لا يمكن توفير أي شيء يفشل في هذه السياسات، بصرف النظر عما يطلبه Terraform أو ما يصل إلى الكلاستر. في AWS هذا هو Service Control Policies (SCPs) المرتبطة على مستوى الوحدة التنظيمية (OU). في GCP هو قيود Organization Policy. في Azure هو Azure Policy على مستوى مجموعة الإدارة.

مجموعة SCPs القياسية التي يجب أن تحملها كل وحدة إنتاجية:

  • رفض استخدام حساب الجذر — شرط على aws:PrincipalArn المطابق لـ *:root، تأثير Deny على جميع الإجراءات.
  • اشتراط MFA للإجراءات في وحدة التحكم — الرفض عندما يكون aws:MultiFactorAuthPresent خطأً لمستخدمي IAM البشريين.
  • قفل المنطقة الجغرافية — رفض الإجراءات التي لا تكون aws:RequestedRegion فيها ضمن قائمتك المعتمدة. يمنع أحمال العمل الظلية في مناطق غير مراقبة.
  • رفض تعطيل حظر الوصول العام لـ S3 — رفض s3:PutBucketPublicAccessBlock الذي سيوقف الحظر.
  • اشتراط التشفير أثناء الراحة — رفض إنشاء مجلد EBS وحالة RDS عندما تكون علامة التشفير خاطئة.
# scp-deny-unencrypted-storage.json # الإرفاق عند الوحدة الإنتاجية عبر AWS Organizations → Policies { "Version": "2012-10-17", "Statement": [ { "Sid": "DenyUnencryptedEBS", "Effect": "Deny", "Action": ["ec2:CreateVolume", "ec2:RunInstances"], "Resource": "*", "Condition": { "Bool": { "ec2:Encrypted": "false" } } }, { "Sid": "DenyUnencryptedRDS", "Effect": "Deny", "Action": "rds:CreateDBInstance", "Resource": "*", "Condition": { "Bool": { "rds:StorageEncrypted": "false" } } }, { "Sid": "DenyNonApprovedRegions", "Effect": "Deny", "NotAction": [ "iam:*", "sts:*", "route53:*", "cloudfront:*", "waf:*", "support:*" ], "Resource": "*", "Condition": { "StringNotEquals": { "aws:RequestedRegion": ["us-east-1", "us-west-2", "eu-west-1"] } } } ] }
تُعدّ SCPs آلية رفض فقط تتقاطع مع سياسات IAM. لا تمنح أذونات. SCP يقول Allow * لا يفعل شيئاً بمفرده — فهو ببساطة لا يضيف رفضاً، لذا تحكم سياسة IAM. دائماً صمّم SCPs كحواجز حماية وليس كمنح.

الطبقة الثانية — حواجز الكلاستر (قبول Kubernetes)

تعترض طبقة قبول الكلاستر طلبات خادم API قبل استمرارها في etcd. هنا يطبّق Gatekeeper (OPA) أو Kyverno السياسة على مستوى الحاوية: لا ترقية للصلاحيات، لا hostNetwork، تسميات مطلوبة، سجلات صور معتمدة، وولايات حصص الموارد. لأن التحكم في webhook القبول، فهو ينطبق على كل فاعل — kubectl apply البشري، Helm، ArgoCD، Flux، وبوتات CI على حد سواء.

يجب أن يطبّق مجموعة سياسة الكلاستر الإنتاجية كحد أدنى:

  • السجل المعتمد — يُسمح فقط بالصور من سجلك الداخلي أو مرآة عامة تم فحصها. يمنع السحب من مستودعات Docker Hub عشوائية دون فحص صور.
  • لا حاويات ذات صلاحياتsecurityContext.privileged: true مرفوض. تمنح الحاويات ذات الصلاحيات فعلياً الجذر على العقدة.
  • نظام ملفات جذر للقراءة فقط — يجبر عمليات الكتابة على وحدات تخزين معلنة صراحةً، مما يجعل الاستمرار بعد الاختراق أصعب.
  • التسميات المطلوبة — يجب أن تكون app.kubernetes.io/name وapp.kubernetes.io/version وteam موجودة. هذا يجعل تحديد نسب التكلفة وتحديد نطاق الحوادث ممكناً على نطاق واسع.
  • حدود الموارد مطلوبة — يجب أن تحدد كل حاوية resources.limits.cpu وresources.limits.memory. يمنع pod واحد يعمل بشكل عشوائي من تجويع عقدة.
# kyverno-require-labels.yaml # ClusterPolicy يحجب أحمال العمل التي تفتقد التسميات الإلزامية apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: require-team-labels annotations: policies.kyverno.io/title: Require Team Labels policies.kyverno.io/severity: medium policies.kyverno.io/description: > يجب أن تحمل Deployments وStatefulSets وDaemonSets تسمية 'team' لتحديد نسب التكلفة وتوجيه المناوبة. spec: validationFailureAction: Enforce # وضع Audit أولاً في staging؛ Enforce في الإنتاج background: true rules: - name: check-team-label match: any: - resources: kinds: [Deployment, StatefulSet, DaemonSet] validate: message: > يجب أن يحتوي المورد على تسمية 'team' مضبوطة على قيمة معروفة. أضف: metadata.labels.team: <slug-فريقك> pattern: metadata: labels: team: "?*" # سلسلة غير فارغة --- # kyverno-approved-registry.yaml apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: restrict-image-registry spec: validationFailureAction: Enforce background: false # القبول فقط — الـ pods الموجودة مستثناة rules: - name: validate-registry match: any: - resources: kinds: [Pod] validate: message: "يجب أن تكون الصور من registry.example.internal أو public.ecr.aws" pattern: spec: containers: - image: "registry.example.internal/* | public.ecr.aws/*"

الطبقة الثالثة — حواجز الأنبوب (بوابات CI في المرحلة المبكرة)

طبقة الأنبوب هي حلقة التغذية الراجعة الأرخص والأسرع. تعمل فحوصات السياسة في ثوانٍ خلال طلب سحب وتحجب الدمج إذا فشل أي ضابط — قبل وصول أي أرتيفاكت إلى الكلاستر أو حساب السحابة بفترة طويلة. هنا يعيش Conftest (يعمل بـ OPA، يقرأ Rego) وCheckov / tfsec (التحليل الثابت لـ Terraform).

ثلاث فئات بوابات تنتمي إلى كل أنبوب CI لتغييرات البنية التحتية:

  • سياسة خطة Terraform — تشغيل Conftest على Terraform plan JSON. الكشف عن حاويات S3 العامة والأحجام غير المشفرة وسياسات IAM الواسعة النطاق قبل apply.
  • فحص صورة الحاوية — تشغيل Trivy أو Grype على الصورة المبنية. الفشل على ثغرات CRITICAL أو وجود مستخدم جذر في نقطة دخول الصورة.
  • فحص بيان Kubernetes — تشغيل Kyverno CLI أو kubeconform على البيانات المعروضة من Helm/Kustomize. نفس السياسات التي تطبّقها عند القبول يجب أن تعمل أيضاً في CI ضد المستودع، حتى يحصل المطورون على تغذية راجعة محلياً.
# .github/workflows/policy-gates.yml name: Policy-as-Code Gates on: pull_request: paths: - 'infra/**' - 'k8s/**' - 'Dockerfile' jobs: terraform-policy: name: Terraform Plan + Conftest runs-on: ubuntu-latest permissions: id-token: write contents: read steps: - uses: actions/checkout@v4 - uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::123456789012:role/TerraformPlanReadOnly aws-region: us-east-1 - uses: hashicorp/setup-terraform@v3 - name: Terraform Init & Plan run: | terraform init -input=false terraform plan -out=tfplan.binary -input=false terraform show -json tfplan.binary > tfplan.json working-directory: ./infra - name: Conftest — Terraform Policy run: | docker run --rm \ -v "$PWD/infra:/project" \ -v "$PWD/policy:/policy" \ openpolicyagent/conftest:latest \ test /project/tfplan.json \ --policy /policy/terraform \ --namespace terraform image-scan: name: Container Image Scan (Trivy) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build image run: docker build -t app:${{ github.sha }} . - name: Trivy — CRITICAL CVEs uses: aquasecurity/trivy-action@master with: image-ref: app:${{ github.sha }} severity: CRITICAL exit-code: '1' ignore-unfixed: true k8s-manifest-policy: name: Kyverno CLI — Manifest Policy runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Render Helm manifests run: | helm template my-app ./charts/my-app \ --values ./charts/my-app/values-prod.yaml \ > /tmp/rendered.yaml - name: Kyverno CLI apply run: | kyverno apply ./policy/kyverno/ \ --resource /tmp/rendered.yaml \ --detailed-results

البنية متعددة الطبقات في نظرة واحدة

Three-layer policy-as-code guardrail framework Layered Policy-as-Code Guardrail Framework LAYER 1 — Organization / Cloud Control Plane AWS SCPs · GCP Org Policies · Azure Policy Region Lock Encrypt-at-Rest Deny Root Usage Require MFA Block Public S3 LAYER 2 — Kubernetes Cluster (Admission Webhooks) Kyverno · Gatekeeper / OPA · Pod Security Standards Approved Registry No Privileged Pods Resource Limits Required Labels Read-Only FS LAYER 3 — CI/CD Pipeline (Shift-Left Gates) Conftest · Checkov / tfsec · Trivy · Kyverno CLI TF Plan Policy Image Scan Manifest Lint IaC SAST (tfsec) Secret Scan
إطار الحواجز ثلاثي الطبقات: تحجب SCPs التنظيمية موارد السحابة السيئة، ويحجب قبول الكلاستر أحمال العمل السيئة، وتحجب بوابات الأنبوب الكود السيئ قبل شحنه.

استراتيجية الطرح — المراجعة قبل التطبيق

أخطر خطأ عند نشر إطار سياسة هو تفعيل وضع Enforce في اليوم الأول عبر مؤسسة حية. ستعطّل الإنتاج. يتبع الطرح الصحيح نمطاً ثلاثي المراحل مستخدماً في كل نشر واسع النطاق:

  1. وضع المراجعة في كل مكان (الأسبوع 1-2): نشر جميع سياسات Kyverno كـ validationFailureAction: Audit وجميع SCPs كـ Deny لكن تستهدف الوحدة التجريبية فقط. جمع سجلات الانتهاكات من الطبقات الثلاث دون حجب أي شيء.
  2. الإصلاح والتطبيق في بيئة التدريج (الأسبوع 2-4): تحليل نتائج المراجعة، فتح طلبات إصلاح لكل انتهاك، والتبديل إلى Enforce في التدريج. السماح بجولة كاملة من التطوير العادي للتأكد من عدم وجود إيجابيات كاذبة.
  3. الطرح الإنتاجي بالوحدة التنظيمية (الأسبوع 4+): تفعيل Enforce وحدة تنظيمية واحدة في كل مرة، بدءاً من أقل الخدمات أهمية. مراقبة لوحات الانتهاكات. إبقاء عملية الفتح الطارئ موثقة — أي SCPs يمكن تعليقها، من قِبَل من، ولكم من الوقت.
خزّن جميع حزم Rego وبيانات Kyverno وملفات SCP JSON في مستودع Git مخصص policy/ بأنبوب CI خاص به وإصدارات ذات رقم نسخة. أشر إلى السياسات في كلاسترك وCI بعلامة semver الخاصة بها، وليس بـ main. هذا يجعل التراجع عن تغيير سياسة في دقائق ممكناً عندما يسبب حجباً إيجابياً كاذباً في الإنتاج — بنفس الطريقة التي تتراجع بها عن صورة حاوية معطوبة.

إمكانية المراقبة: جعل إطار السياسة مرئياً

إطار السياسة الذي لا يستطيع أحد مراقبته هو إطار سيُوقَف أول مرة يسبب احتكاكاً. يجب أن تُرسل كل طبقة إشارات منظمة تُغذّي مجموعة المراقبة الموجودة لديك:

  • Kyverno: يُرسل Kubernetes Events وموارد PolicyReport / ClusterPolicyReport المخصصة. استخرجها بمُصدِّر policy-reporter وصوّرها في Grafana. ابنِ لوحة تعرض عدد الانتهاكات حسب السياسة وحسب namespace وحسب الفريق عبر الزمن.
  • AWS Config Rules: تُغذّي أعداد الموارد غير المتوافقة في مقاييس CloudWatch. اضبط تنبيهاً على أي نقاط امتثال أقل من 100% للحسابات الإنتاجية.
  • بوابات CI: صدّر أعداد النجاح/الفشل للبوابات إلى نظام تحليلات البناء لديك. تتبّع متوسط وقت إصلاح انتهاك السياسة تماماً كما تتبّع متوسط وقت التعافي من الحوادث.
استثناءات السياسة تحتاج حوكمة أيضاً. كل إطار سيواجه في نهاية المطاف طلباً لإعفاء حمل عمل من سياسة. بدون عملية استثناء رسمية، تنمو قائمة الاستثناءات بلا حدود وتصبح السياسة بلا معنى. وثّق الاستثناءات في Git (دليل exceptions/ مع ملف YAML لكل استثناء)، اشترط موافقة اثنين، حدّد تاريخ انتهاء، وأرسل تنبيهاً تلقائياً عند اقتراب الانتهاء. تعامل مع الاستثناء كدَين تقني يجب سداده.

الجمع معاً

أصبح لديك الآن المخطط الكامل: تُقفل SCPs مستوى التحكم السحابي حتى لا يمكن توفير أي مورد مُخطأ في التكوين؛ وتضمن سياسات Kyverno عند القبول أن كل حمل عمل يعمل على كلاسترك يلتزم بمعايير الأمان والتشغيل لديك؛ وتمنح بوابات CI المطورين تغذية راجعة سريعة قبل مغادرة تغييراتهم مرحلة طلب السحب. انتهاكات السياسة في أي طبقة قابلة للمراقبة ومنسوبة لفريق وتُغذّي سير عمل الإصلاح.

هذه هي نفس البنية المستخدمة من قِبَل المؤسسات الهندسية الناضجة أمنياً التي تشغّل أحمال عمل منظَّمة للامتثال على نطاق واسع. تتغير الأدوات بمرور الوقت — قد يُستبدل Gatekeeper بـ Kyverno، وCheckov ببديل من بائع — لكن نمط الطبقات الثلاث وانضباط الطرح القائم على المراجعة قبل التطبيق هما ممارسات هندسية راسخة ستخدمك خلال كل تطور في سلسلة الأدوات.