مشروع التخرج: منصة إنتاج بمستوى الشركات الكبرى

طبقة الأمان والامتثال

18 دقيقة الدرس 7 من 30

طبقة الأمان والامتثال

تحمل شركة Arctiq Commerce نطاق PCI-DSS المستوى الثاني والتزامات اللائحة الأوروبية العامة لحماية البيانات (GDPR). سر واحد مسرَّب أو صورة حاوية غير مُرقَّعة تصل إلى الإنتاج ليست مجرد محرجة — إنها خرق قابل للإبلاغ يترتب عليه غرامات تنظيمية وتآكل في قاعدة العملاء وربما مسؤولية جنائية. على هذا النطاق، لا يمكن أن يكون الأمان قائمة مراجعة تُطبَّق في نهاية السبرينت؛ بل يجب أن يكون خاصية من خصائص المنصة يرثها فرق الهندسة تلقائياً. يبني هذا الدرس تلك الخاصية طبقة تلو طبقة: إدارة الأسرار، وأمان سلسلة الإمداد، والتحكم في القبول، والتطبيق أثناء التشغيل، وموقف الامتثال.

إدارة الأسرار: HashiCorp Vault على نطاق واسع

أكثر مصادر تسرب الاعتمادات شيوعاً في بيئات Kubernetes هو تخزين الأسرار بنص عادي في Git أو دمجها داخل صور الحاويات. لا يكفي kubectl create secret ولا sealed-secrets على مستوى التقنيات الكبرى لأنهما لا يوفران إصدار اعتمادات ديناميكياً، ولا إدارة دقيقة للمدد، ولا مسارات تدقيق لكل خدمة. Vault هو الإجابة المعيارية في الصناعة.

تُشغِّل Arctiq Vault في وضع HA على ثلاث نسخ EC2 مخصصة (خارج Kubernetes) لتجنب الاعتماد الدائري حيث تُحتاج الأسرار لتشغيل العنقود الذي يشغّل Vault. الطبقة الخلفية للتخزين هي DynamoDB مع تمكين استعادة النقطة في الزمن. إلغاء القفل التلقائي يستخدم AWS KMS حتى تعيد حجرات Vault تشغيلها بعد إخفاق عقدة دون تدخل بشري.

# vault-values.yaml (Helm chart for the Vault Agent Injector sidecar) injector: enabled: true replicas: 2 resources: requests: cpu: 50m memory: 64Mi limits: cpu: 250m memory: 128Mi # Enable Kubernetes auth in Vault (run once after cluster creation) vault auth enable kubernetes vault write auth/kubernetes/config \ kubernetes_host="https://$(kubectl get svc kubernetes -o jsonpath='{.spec.clusterIP}'):443" \ kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt \ token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" # Dynamic database credentials — 15-minute TTL vault secrets enable database vault write database/config/arctiq-aurora \ plugin_name=postgresql-database-plugin \ allowed_roles="app-readonly,app-readwrite" \ connection_url="postgresql://{{username}}:{{password}}@aurora-primary.cluster.internal:5432/arctiq" \ username="vault-root" \ password="$VAULT_DB_ROOT_PASS" vault write database/roles/app-readwrite \ db_name=arctiq-aurora \ creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \ default_ttl="15m" \ max_ttl="1h"

تستخدم حجرات التطبيق Vault Agent Injector عبر تعليقات توضيحية (annotations). تجلب الحاوية الجانبية اعتماداً ديناميكياً عند بدء تشغيل الحجرة، وتكتبه على وحدة تخزين tmpfs، وتجدده تلقائياً قبل انتهاء صلاحيته. يقرأ التطبيق من ملف فقط — لا يتصل بـ Vault مباشرة ولا يرى كلمة مرور طويلة الأجل قط.

# Deployment annotation for dynamic DB creds spec: template: metadata: annotations: vault.hashicorp.com/agent-inject: "true" vault.hashicorp.com/role: "order-service" vault.hashicorp.com/agent-inject-secret-db: "database/creds/app-readwrite" vault.hashicorp.com/agent-inject-template-db: | {{- with secret "database/creds/app-readwrite" -}} DATABASE_URL=postgres://{{ .Data.username }}:{{ .Data.password }}@aurora-primary:5432/arctiq {{- end }} vault.hashicorp.com/agent-inject-file-db: "/vault/secrets/.env"
في Google وMeta، تدور اعتمادات قاعدة البيانات تلقائياً كل 15 إلى 60 دقيقة. التطبيق الذي لا يستطيع التعامل مع دوران اعتماد في منتصف الطلب — عبر تحديث اعتمادات تجمع الاتصال — سيفشل في هذا النموذج. فرّض ذلك في مراجعة الكود: يجب أن تعيد تجمعات الاتصال تحميل الاعتمادات من مسار tmpfs وليس تخبئتها في الذاكرة عند بدء التشغيل.

أمان سلسلة الإمداد: SLSA المستوى 3

أثبتت حوادث SolarWinds وLog4Shell أن سطح الهجوم لا يقتصر على كودك — بل يشمل كل تبعية في رسم بيانات البناء الخاص بك. يتطلب PCI-DSS 6.3 الآن صراحةً قائمة مواد البرامج (SBOM) وأدلة على أن عمليات البناء مقاومة للتلاعب. SLSA المستوى 3 يعني: بناءات محكمة (hermetic builds)، وإثبات المصدر (provenance) الموقَّع، والتحقق وقت النشر.

Supply-Chain Security Pipeline Developer git push CI Build Hermetic (no network access) SBOM generated Cosign Sign SLSA provenance attached to OCI image digest ECR Private Image scan on push (Trivy) Admission Kyverno verifies signature before pod schedules يجب أن تحمل كل صورة توقيع Cosign صالحاً حتى يُسمح لها بالدخول إلى العنقود
خط أنابيب أمان سلسلة الإمداد: بناء محكم ← SBOM + توقيع Cosign ← فحص السجل ← التحقق عند القبول.
# GitHub Actions: keyless signing with Cosign + Sigstore (OIDC, no long-lived keys) - name: Sign image with Cosign env: COSIGN_EXPERIMENTAL: "1" run: | cosign sign --yes \ $ECR_REGISTRY/$ECR_REPO@$IMAGE_DIGEST # Generate SBOM and attest it - name: Generate and attest SBOM run: | syft $ECR_REGISTRY/$ECR_REPO@$IMAGE_DIGEST \ -o cyclonedx-json > sbom.json cosign attest --yes \ --predicate sbom.json \ --type cyclonedx \ $ECR_REGISTRY/$ECR_REPO@$IMAGE_DIGEST # Kyverno policy: require verified signature before scheduling apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: require-signed-images spec: validationFailureAction: Enforce rules: - name: check-image-signature match: any: - resources: kinds: [Pod] namespaces: ["*"] verifyImages: - imageReferences: - "123456789.dkr.ecr.us-east-1.amazonaws.com/*" attestors: - entries: - keyless: subject: "https://github.com/arctiq-commerce/*" issuer: "https://token.actions.githubusercontent.com"
لا تستخدم أبداً image: myapp:latest في بيانات الإنتاج. latest علامة قابلة للتغيير — يتغير مجمَّع (digest) الصورة بصمت مما يكسر توقيع cosign ويجعل التراجع مستحيلاً. دائماً ثبِّت المجمَّع غير القابل للتغيير: image: 123456789.dkr.ecr.us-east-1.amazonaws.com/order-service@sha256:abc123.... يتولى متحكم GitOps (Argo CD Image Updater) ترقية المجمَّع تلقائياً.

تطبيق السياسات: Kyverno عند القبول

يتحكم Kubernetes RBAC في من يستطيع استدعاء الـ API. تتحكم متحكمات القبول في ما يُسمح لهذه الاستدعاءات بإنشائه. تفرض سياسات Kyverno خط الأمان الأساسي عبر جميع الفرق الاثني عشر دون أن يُطلب منهم معرفة القواعد — الحجرة التي تنتهك السياسة تُرفض ببساطة عند التطبيق مع رسالة خطأ واضحة.

تفرض مجموعة سياسات Arctiq الأساسية: لا حاويات ذات امتيازات عالية، لا تثبيت host-network أو host-path، وجود حدود موارد على كل حاوية (يمنع حالات OOM بين المستأجرين)، أنظمة ملفات جذر للقراءة فقط، وملف seccomp محظور (restricted).

# kyverno-baseline.yaml — enforce resource limits and read-only rootfs apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: require-resource-limits spec: validationFailureAction: Enforce rules: - name: check-cpu-memory-limits match: any: - resources: kinds: [Pod] validate: message: "CPU and memory limits are required on all containers." pattern: spec: containers: - name: "*" resources: limits: cpu: "?*" memory: "?*" --- apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: readonly-rootfs spec: validationFailureAction: Enforce rules: - name: check-readonly-rootfs match: any: - resources: kinds: [Pod] namespaces: - "production-*" - "staging-*" validate: message: "Root filesystem must be read-only in production namespaces." pattern: spec: containers: - securityContext: readOnlyRootFilesystem: true

الأمان أثناء التشغيل: كشف التهديدات بـ Falco

يمنع التحكم في القبول نشر التكوينات السيئة. لكن ماذا عن الهجمات التي تحدث أثناء التشغيل — حاوية تفتح shell غير متوقعة، أو عملية تقرأ /etc/shadow، أو تبعية مخترقة تستدعي curl لتسرب البيانات؟ Falco هو محرك أمان التشغيل المعتمد من CNCF الذي يكشف هذه السلوكيات عبر مراقبة مستدعيات kernel في Linux باستخدام eBPF.

تنبّه قواعد Falco على الشذوذات السلوكية. قاعدة حرجة لنطاق PCI: أي shell يُولَد داخل حاوية تعمل في نطاق الاسم payment-processing يُطلق تنبيهاً P1 وعملية kubectl cordon تلقائية للعقدة عبر مكوِّن استجابة Falco.

# falco-custom-rules.yaml - rule: Shell Spawned in Payment Namespace desc: Detect any shell process started in the payment-processing namespace condition: > spawned_process and container and k8s.ns.name = "payment-processing" and proc.name in (shell_binaries) output: > Shell spawned in payment namespace (pod=%k8s.pod.name user=%user.name shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline image=%container.image.repository) priority: CRITICAL tags: [pci-dss, container, shell] - rule: Outbound Connection from DB Container desc: Database containers must not initiate outbound connections condition: > outbound and container and k8s.deployment.name contains "postgres" and not fd.sport in (5432) output: Unexpected outbound from DB container (dest=%fd.rip:%fd.rport pod=%k8s.pod.name) priority: WARNING tags: [network, lateral-movement]
يتطلب Falco مع برنامج تشغيل eBPF الإصدار 5.8+ من النواة وCAP_BPF أو صلاحيات الجذر. على EKS، استخدم الإضافة المُدارة — تتولى AWS مصفوفة توافق وحدة النواة. وجِّه تنبيهات Falco إلى سياسة تصعيد PagerDuty مخصصة منفصلة عن تنبيهات التطبيقات؛ تنبيه الأمان أثناء التشغيل لا يُتجاوز أبداً.

موقف الامتثال: معايير CIS وسجلات التدقيق

تتطلب PCI-DSS فحوصات ثغرات داخلية ربع سنوية واختبارات اختراق سنوية. لكن المنصة الناضجة لا تنتظر عمليات التدقيق — بل تحافظ على درجة امتثال مستمرة. يُشغِّل kube-bench فحوصات معيار CIS Kubernetes على كل عقدة ومكون control plane كـ DaemonSet، ويُصدر نتائج منظمة إلى مجموعة السجلات المركزية. أي تراجع في المعيار خلال نشر يحجب خط CD عبر بوابة الجودة في Argo CD.

كل إجراء على خادم Kubernetes API يُحفظ في CloudWatch Logs عبر تكامل سجل تدقيق EKS. تُكتشف أنماط تصعيد الامتيازات عبر استعلامات Athena على سجل التدقيق: أي create rolebinding أو patch clusterrole خارج فريق platform-engineering يُطلق تنبيهاً تلقائياً على Slack وتذكرة Jira لفريق الأمان للمراجعة خلال 24 ساعة — مما يُلبي متطلب PCI-DSS رقم 10.3.

احتفظ بسجلات تدقيق Kubernetes لمدة 12 شهراً على الأقل (متطلب PCI-DSS 10.7). مدة الاحتفاظ في CloudWatch تُضبط لكل مجموعة سجلات — الافتراضي هو "لا تنتهي"، وهذا مكلف. اضبطها على 365 يوماً وصدِّر إلى S3 Glacier بعد 90 يوماً للأشهر التسعة المتبقية. تنخفض التكلفة من ~0.50$/غيغابايت/شهر (CW) إلى ~0.004$/غيغابايت/شهر (Glacier).

بنية الدفاع المتعمق

Defense in Depth — Concentric Security Layers Layer 1: Network / WAF (AWS Shield + WAFv2 + Security Groups) Layer 2: Identity (IRSA, OIDC, Vault Kubernetes Auth) Layer 3: Supply Chain (Cosign + Kyverno signature verification) Layer 4: Admission Control (Kyverno policies, Pod Security Standards) Layer 5: Runtime (Falco eBPF syscall monitoring, network policies) Layer 6: Data Vault dynamic creds · TLS everywhere · KMS envelope encryption Aurora encrypted at rest · S3 SSE-KMS · Kafka TLS + SASL/SCRAM
الدفاع المتعمق: ست طبقات أمان متحدة المركز تحمي منصة Arctiq — كل طبقة تكتشف بشكل مستقل ما تفوَّت على الطبقة الخارجية.

الفكرة الجوهرية هي الاستقلالية: كل طبقة تكتشف فئة مختلفة من التهديدات. يُكتشف تكوين Security Group الخاطئ بواسطة WAF. تُحاصَر الاعتمادات المخترقة للمطور بامتيازات IRSA الأدنى. تُحجب الصورة غير الموقعة عند القبول. يُكتشف الاستغلال أثناء التشغيل بواسطة Falco قبل خروج البيانات. هذه هي البنية التي يتوقع المدقق رؤيتها — والأهم، البنية التي تصمد أمام الحوادث الحقيقية.

الأمان ليس تكويناً لمرة واحدة. جدوِل مراجعة أمنية ربع سنوية تشمل: تدوير رموز Vault الجذرية، ومراجعة استثناءات سياسات Kyverno (كل استثناء هو دَيْن تقني)، وإعادة تشغيل kube-bench بعد ترقيات EKS، ومراجعة قواعد كبت تنبيهات Falco للمدخلات القديمة. اجعل هذا هدفاً رئيسياً (OKR) لفريق المنصة وليس مهمة اختيارية.