Kubernetes · أمن الشبكات

Kubernetes NetworkPolicy: طبّق Default Deny دون كسر الإنتاج

تصميم إنتاجي متدرج لتقليل وصول Pods مع الحفاظ على DNS وIngress والفحوص والمراقبة واعتماديات الخدمات المعتمدة.

المسار المرتبطالسحابة وDevOps وKubernetes
رسم تقني أصلي يوضح Namespace في Kubernetes محمية بحد Default Deny مع مسارات صريحة تحفظ DNS وIngress والمراقبة واتصال قاعدة بيانات معتمد.
تصوّر بصري للفكرة — يتبعه شرح ومخطط تنفيذي داخل المقال.

سياسة Default Deny في Kubernetes NetworkPolicy هي خط أساس أمني على مستوى Namespace يمنع الاتصالات ما لم تحفظها قاعدة Allow صريحة. أهميتها أن اختراق Pod واحدة لا يجب أن يمنح المهاجم وصولًا تلقائيًا إلى كل Workload أو وجهة خارجية. ينبغي لفرق المنصة والأمن والتطبيقات تطبيقها كمشروع ترحيل لعقد المرور: إثبات أن CNI تنفّذ NetworkPolicy، وجرد المسارات الفعلية، والسماح الصريح لـDNS وIngress والمراقبة والاعتماديات، ثم تجربة Namespace واحدة واختبار الاتصالات المسموحة والممنوعة قبل التوسع.

توثق Kubernetes أن NetworkPolicy أداة Layer 3/4 للتحكم في المرور المتعلق بالـPods. ويوضح دليل NetworkPolicy الرسمي شرطًا حاسمًا: إنشاء الكائن لا يغيّر شيئًا إن لم تنفّذ Network Plugin عملية الإنفاذ. يفرّق هذا الدليل بين الدلالات الموثقة وتوصيات التشغيل. قد يختلف السلوك حول NAT وhostNetwork والاتصالات القائمة حسب التنفيذ، لذلك راجع وثائق CNI والمنصة المدارة التي تشغّلها.

افهم حدود التحكم قبل كتابة YAML

تختار NetworkPolicy Pods داخل Namespace السياسة. عزل Ingress وEgress مستقل. تبقى Pod غير معزولة في اتجاه ما إلى أن تختارها سياسة واحدة على الأقل لذلك الاتجاه؛ بعدها لا يبدأ إلا المرور المسموح به عبر اتحاد قواعد Allow المطابقة. القواعد تراكمية ولا توجد قاعدة أولى تربح. وفي اتصال Pod إلى Pod يجب أن تسمح Egress عند المصدر وIngress عند الوجهة معًا.

ليست هذه Firewall لكل كائنات Kubernetes. فهي لا تفوض طلب API، ولا تتحقق من هوية التطبيق، ولا تفهم HTTP Path، ولا تتخذ قرار TLS. تسرد الوثائق الرسمية قيودًا أخرى في الواجهة القياسية، منها غياب أولويات Explicit Deny وتسجيل أحداث الشبكة واستهداف Services بالاسم. استخدم RBAC وWorkload Identity للتفويض، وTLS أو Service Mesh لمصادقة الأطراف عند الحاجة، وTelemetry الخاصة بالـCNI لرؤية الاتصالات المقبولة والمحجوبة.

يطابق podSelector الفارغ كل Pods في Namespace. ومع قائمتَي ingress وegress فارغتين لا يُسمح بشيء في الاتجاهين. هذا يجعل خط Default Deny صغيرًا، لكنه ليس مكتفيًا بذاته؛ قيمته تظهر فقط بعد كتابة واختبار قواعد السماح المطلوبة.

ارسم عقد المرور قبل العزل

ابدأ بمصفوفة اعتماديات من Manifests وملكية الخدمات والمرور الملحوظ. لكل Workload سجّل هوية المصدر والوجهة والبروتوكول وDestination Port والاتجاه والغرض وحساسية البيانات والمالك. ضمّن سلوك البداية والمهام الخلفية، لا طلب HTTP الناجح فقط.

يشمل الجرد الأدنى DNS وIngress Controller أو Gateway، وخدمات داخل Namespace وعبر Namespaces، وقواعد البيانات والطوابير وIdentity Provider وObject Storage ونقاط الحزم أو الترخيص وMetrics Scraping وCollectors للـTraces والـLogs واعتماديات Sidecars وAdministrative Probes. سجّل هل للوجهة Labels ثابتة. Service ClusterIP عنوان افتراضي؛ تصف السياسة عادة Pods المختارة أو IP Block، وقد يختلف توقيت Address Translation بين تطبيقات الشبكات.

لا تحوّل Flow Export مباشرة إلى سياسة. قد تحتوي الملاحظة مرور مهاجم أو Debug مؤقتًا أو عميلًا قديمًا أو اعتمادًا عرضيًا. طابق كل Flow مع العقد المعلن من الفريق المالك. وفي المقابل، قد تفوّت نافذة مراقبة قصيرة Month-end Jobs وتجديد الشهادات ومسارات Failover وDisaster Recovery.

صمّم هويات ثابتة باستخدام Selectors

فضّل namespaceSelector وpodSelector على IP Ranges المتغيرة للاعتماديات داخل Cluster. تضيف Control Plane Label ثابتة kubernetes.io/metadata.name لكل Namespace، ويمكن استخدامها لاستهداف Namespace باسمها الحالي. كما تصنع Labels مملوكة للمؤسسة مثل security.nooryasser.com/zone=ingress وapp.kubernetes.io/name=checkout نية أوضح حين تحمي Admission وRBAC إسنادها.

تغيّر المسافات البادئة في YAML المعنى. عنصران منفصلان في from أو to بديلان. أما Peer واحدة تجمع namespaceSelector وpodSelector فتتطلب الشرطين معًا. يعرّف مرجع NetworkPolicy API عناصر Peers بعلاقة OR، بينما يجمع الحقلان داخل Peer واحدة Pods المطابقة داخل Namespaces المطابقة.

استخدم ipBlock لوجهات هي فعلًا Address Ranges مثل شبكة خاصة مضبوطة أو Endpoint خارجي ثابت. لا تفترض أنه سيحدد المرور دائمًا بعد ترجمة LoadBalancer أو Service أو Egress Gateway. وثّق هل ترى السياسة عناوين قبل NAT أم بعدها في CNI والتكامل السحابي الفعلي.

تغلق Default Deny كل مسار غير معلن، وتحفظ سياسات Allow المنفصلة مسارات DNS وIngress والمراقبة والاعتماديات المعتمدة فقط.
تغلق Default Deny كل مسار غير معلن، وتحفظ سياسات Allow المنفصلة مسارات DNS وIngress والمراقبة والاعتماديات المعتمدة فقط. اضغط لعرض أكبر

طبّق Default Deny كمشروع ترحيل

اختر Namespace منخفضة المخاطر بمالك معروف ومرور ممثل. أثبت الإنفاذ أولًا في Test Namespace مؤقتة: أنشئ Podين، وطبّق سياسة محدودة، وأثبت فشل اتصال كان يعمل ونجاح اتصال مسموح. قبول كائن Kubernetes ليس دليلًا أن Packets تُرشح.

أضف بعدها سياسات Allow دون عزل وراجع Selectors. لأن Pod غير المعزولة ما تزال تسمح بكل المرور، يمكن تجهيز هذه الكائنات بأمان، لكنها لا تثبت صحتها. فعّل Default-deny Ingress في Canary Namespace، وشغّل Connectivity Matrix، وراقب Error Rate وDNS Failures وResets وCNI Drop Telemetry. ثبّت Ingress قبل Default-deny Egress؛ فالاعتماديات الصادرة غالبًا أقل وضوحًا وأكثر تغيرًا.

توسع حسب Workload Class، لا حسب عدد Namespaces بلا تمييز. احتفظ بسجل Exceptions بإصدار ومالك وسبب ونطاق وتاريخ انتهاء. يجب أن يكون Rollback إزالة أو تضييق Isolation Policy المختارة عبر تغيير مراجع؛ لا تترك Allow-all دائمة تصبح خط الأساس الحقيقي. توضح Kubernetes أن الإنفاذ قد يتقارب بشكل غير متزامن وأن أثر التغيير على الاتصالات المفتوحة Implementation-defined، لذلك اختبر اتصالات جديدة ولا تعتمد على Connection Pool دافئة.

حافظ على DNS وIngress والفحوص والمراقبة

DNS أول عطل شائع بعد عزل Egress. اسمح بـUDP وTCP على Destination Port 53 إلى DNS Pods أو العناوين المستخدمة فعلًا. تختلف Labels حسب التوزيعة، وقد تضع NodeLocal DNSCache الـResolver على عنوان محلي للـNode. افحص resolv.conf داخل Pod وتصميم DNS للمنصة بدل نسخ kube-system selector بلا تحقق. يشرح دليل موثوقية DNS في Kubernetes تتبع مسار Resolver قبل تغييره.

يجب أن تسمح قواعد Ingress للمصدر الذي تراه Destination Pod فعلًا. قد يكون Ingress Controller Pod أو Gateway Data Plane أو Node Address أو Cloud Load Balancer Range أو مزيجًا بعد Source NAT. أثبت ذلك من CNI Flow Data. قاعدة تختار كل Pods في Ingress Namespace أوسع من Peer تتطلب أيضًا Label محمية للـController.

تنطلق HTTP وTCP وgRPC Probes من kubelet أو Node Path خاصة بالتنفيذ، لا من Monitoring Pod عادية. تسمح مواصفة NetworkPolicy دائمًا بالمرور من Node التي تستضيف Pod، لكن hostNetwork وعناوين Nodes لها فروق تنفيذية. اختبر Readiness وLiveness وStartup Probes بعد العزل في كل Node Pool. يفصل دليل موثوقية Kubernetes Probes بين قبول المرور وتعافي Process.

المراقبة ثنائية الاتجاه معماريًا حتى لو كان كل اتصال أحادي الاتجاه. قد تسحب Prometheus من Workload، بينما تستقبل OpenTelemetry Collector Egress منها. وقد تخرج Logs عبر Sidecar أو Node Agent. اكتب قواعد مستقلة للمبادر الحقيقي، وتأكد أن Dashboards ما تزال حديثة بعد السياسة. SLO خضراء مع فقد Security Telemetry ليست إطلاقًا ناجحًا.

ابنِ خط أساس صريحًا وقواعد سماح ضيقة

يعزل المثال التالي كل Pod في Namespace اسمها payments، ثم يعيد DNS عبر Labels يجب التحقق منها على Cluster المستهدفة، ويسمح HTTPS من Ingress Controller فقط، ويسمح لـAPI Pods بالوصول إلى PostgreSQL Pods في data. المثال توضيحي وليس Config قابلة للنسخ لكل منصة.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
  namespace: payments
spec:
  podSelector: {}
  policyTypes: [Ingress, Egress]
  ingress: []
  egress: []
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: payments-required-paths
  namespace: payments
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/name: payments-api
  policyTypes: [Ingress, Egress]
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: ingress-system
          podSelector:
            matchLabels:
              app.kubernetes.io/name: ingress-controller
      ports:
        - { protocol: TCP, port: 8443 }
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - { protocol: UDP, port: 53 }
        - { protocol: TCP, port: 53 }
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: data
          podSelector:
            matchLabels:
              app.kubernetes.io/name: postgres
      ports:
        - { protocol: TCP, port: 5432 }

لاحظ أن Ingress وEgress صريحتان، وأن Namespace وPod Selectors لكل Peer داخل List Item واحدة. تحقق من Labels عبر Policy-as-code. إذا استطاعت فرق التطبيقات تغيير Labels لأي Namespace أو Privileged Pod، يتحول Selector إلى Bypass ذاتية.

اختبر مسارات النجاح والمنع

يثبت Positive Test كل Edge مطلوبة: Ingress إلى المنفذ المعروض، وDNS عبر UDP وTCP، والوصول إلى Database، وتسليم Telemetry وواجهات خارجية معلنة. والـNegative Test مهم بالقدر نفسه: جرّب منفذًا خاطئًا وPod بلا Label وNamespace غير مرتبطة ووجهة إنترنت ممنوعة وLateral Connection غير متوقعة. شغّل المصفوفة من Pods جديدة حتى لا تخفي Existing Sockets وDNS Cache النتيجة.

راقب ثلاثة مستويات. يظهر التطبيق أثر المستخدم وأخطاء الاعتماديات. وتظهر CNI Drops والهوية أو القاعدة المرتبطة. وتثبت Synthetic Probes الرسم المقصود مستقلًا عن Production Traffic. أنشئ Alert للـDrops المستمرة المرتبطة بهدف خدمة، واحتفظ بعينة أدلة للتحقيق. لا توفر NetworkPolicy القياسية Logs لأحداث الشبكة، لذلك اجعل Observability متطلبًا عند اختيار CNI وتشغيلها.

اختبر حذف Policy وتغيير Selector وإعادة تشغيل Pod واستبدال Node وتعطل CNI Agent. تحذر وثائق Lifecycle من أن Network Plugin تعالج السياسة في النهاية؛ قد ترى Pod جديدة اتصالًا مختلفًا مؤقتًا عن الحالة النهائية المقصودة. يجب أن تعيد Workloads محاولة اعتماديات البداية بحدود، وأن تنتظر Release Checks اتصالًا حقيقيًا لا مجرد وجود API Object.

أفضل الممارسات والأخطاء الشائعة

اجعل لكل Policy غرضًا واحدًا واسمًا واضحًا. احمِ Namespace وWorkload Labels. راجع CIDRs الواسعة والـSelectors الفارغة. اطلب مالكًا وانتهاءً لكل Exception. افحص Manifests على الخادم واختبرها على إصدار CNI نفسه، وضع Connectivity Contract ضمن Release. عامل DNS وObservability وBreak-glass كاعتماديات مصممة، لا كإصلاح طارئ.

تجنب Policy ضخمة مولدة من كل Flow ملحوظة. وتجنب Allow-all Egress كحالة نهائية. لا تختر System Namespace كاملة حين يحتاج Controller واحد الوصول. لا تعتبر kubectl apply ناجحًا دليل إنفاذ. لا تفترض أن NetworkPolicy تصادق المتصل أو تفهم HTTP Route. ولا تجعل Policy Change أول لحظة يكتشف فيها الفريق اعتماديات التشغيل.

متى لا تكفي NetworkPolicy؟

NetworkPolicy مناسبة لتقليل Layer 3/4 Reachability بين Pods وNetwork Ranges. لا تكفي حين يعتمد القرار على User Identity أو HTTP Method أو API Object أو Certificate Identity أو Data Classification أو Business Authorization. أضف Application Authorization وmTLS أو Service Mesh وEgress Proxy وCloud Firewall أو Database Controls حسب الحد المطلوب.

قد يكون إنفاذ Egress مبكرًا أيضًا في Namespace مجهولة الاعتماديات وغير قابلة للمراقبة. أضف Instrumentation وOwnership أولًا؛ وإلا تصبح السياسة مولد Outage ثم Allow-all Exception دائمة. قد يكفي Ingress-only Baseline في Development Sandbox، لكن Production Namespaces التي تعالج بيانات حساسة يجب أن تتجه إلى عقود ثنائية صريحة. تساعد قائمة أمن Kubernetes على مراجعة RBAC وPod Security وSecrets وAudit إلى جانب الشبكة.

القاعدة التشغيلية بسيطة: Default Deny هي الوجهة وليست أول خطوة. أثبت الإنفاذ، وارسم ووافق على Edges المطلوبة، واحفظ Platform Traffic صراحة، وطبّق Canary لكل اتجاه، واختبر المنع بجدية النجاح نفسها، ثم توسع مع Rollback قابلة للملاحظة. هكذا تتحول NetworkPolicy من YAML Checkbox إلى عقد أمن إنتاجي تتم صيانته.

المراجع الرسمية

تدعم هذه المراجع سلوك الأدوات المذكورة. الأمثلة وقرارات التصميم توضيحية، ويجب تكييفها مع متطلبات المشروع وإصداراته.

إعداد: Noor Yasser

من القرار إلى التنفيذ

تعمل على تحدٍ تقني مشابه؟

أساعد الفرق على تحويل القرار المعماري إلى نطاق واضح وتنفيذ يمكن تشغيله ومراجعته بثقة.

احجز لقاءً لمدة ٣٠ دقيقةالخدمة المرتبطةتحسين الأداء والبنية السحابية والنشرمشروع من الأعمالمنصة اللوجستيات