تمرير المتغيرات البيئية (Environment Variables) للحاويات بشكل آمن

دقائق القراءة: 6

تمرير المتغيرات البيئية Environment Variables للحاويات بشكل آمن

تُعد المتغيرات البيئية Environment Variables من أكثر الطرق استخداماً لتمرير إعدادات التشغيل إلى الحاويات، مثل بيانات الاتصال بقاعدة البيانات، مفاتيح API، أو وضع التطبيق بين development وproduction. لكن المشكلة أن سهولة الاستخدام لا تعني الأمان دائماً، خصوصاً في بيئات Docker وKubernetes حيث يمكن أن تتحول الإعدادات السرية إلى ثغرة صريحة إذا أُديرت بشكل خاطئ.

في عالم ما هو DevOps؟ ولماذا تدفع الشركات ثروات لمهندسي الأتمتة السحابية؟ لا يكفي أن يعمل التطبيق داخل الحاوية، بل يجب أن يُنشر معزولاً وقابلاً للتوسع وملتزماً بضوابط الأمان. لهذا السبب، فإن إدارة الأسرار Secrets Management أصبحت جزءاً محورياً من سلاسل CI/CD ومن تصميم البنية السحابية نفسها.

لماذا تُستخدم المتغيرات البيئية داخل الحاويات؟

الحاوية بطبيعتها يجب أن تكون قابلة للنقل بين البيئات المختلفة دون تغيير الصورة Image. لذلك يُفصل الكود عن الإعدادات عبر متغيرات التشغيل. هذا المفهوم أساسي عند بناء صور نظيفة، كما شرحنا سابقاً في كتابة أول Dockerfile: تحويل سكربت Python إلى صورة (Image) معزولة.

أشهر المعلومات التي تُمرر بهذه الطريقة تشمل:

  • عنوان قاعدة البيانات واسم المستخدم.
  • مفاتيح التكامل مع خدمات خارجية.
  • إعدادات المنافذ Ports واسم البيئة.
  • خيارات السجلات Logging والتصحيح Debug.

لكن استخدام هذا الأسلوب بشكل مباشر قد يؤدي إلى تسرب البيانات في أوامر التشغيل، ملفات السجل، أو أدوات الفحص مثل docker inspect.

الأخطاء الشائعة التي تجعل المتغيرات البيئية غير آمنة

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

لا تقم أبداً بتخزين كلمات المرور أو مفاتيح JWT أو رموز الوصول داخل Dockerfile أو ملفات docker-compose.yml المرفوعة إلى المستودع العام. هذا خطأ أمني قد يؤدي إلى اختراق دائم وليس مجرد تسريب عابر.

ومن الأخطاء أيضاً:

  • استخدام ملف .env دون إضافته إلى .gitignore.
  • منح جميع الحاويات نفس الأسرار رغم اختلاف الوظائف.
  • عدم تدوير الأسرار Secret Rotation.
  • طباعة المتغيرات داخل السجلات أثناء الإقلاع أو التصحيح.

تمرير المتغيرات في Docker بشكل أكثر أماناً

إذا كنت ما زلت في مرحلة الحاوية الواحدة أو البيئات المحلية، فبإمكانك استخدام ملف خارجي مع عدم رفعه إلى المستودع. هذا الأسلوب أفضل من كتابة القيم صراحة داخل الأمر. ويمكنك مراجعة أساسيات التشغيل في أوامر Docker الأساسية للتحكم: تشغيل، إيقاف، فحص، وحذف الحاويات.

استخدام ملف .env محلي

cat > .env <<EOF
APP_ENV=production
DB_HOST=db.internal
DB_USER=appuser
DB_PASSWORD=change_me_securely
API_KEY=replace_with_secret_value
EOF

docker run --env-file .env my-secure-app:latest

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

الاعتماد على Docker Compose مع فصل الإعدادات

عند تشغيل عدة خدمات، يُفضل تنظيم القيم عبر ملفات منفصلة. وإذا كنت تبني بيئة متعددة الحاويات، فراجع ما هو Docker Compose؟ ولماذا نحتاجه لتشغيل المشاريع المعقدة؟ ثم كتابة أول ملف docker-compose.yml خطوة بخطوة.

version: "3.9"

services:
  app:
    image: my-secure-app:latest
    env_file:
      - .env
    environment:
      APP_ENV: production
    restart: unless-stopped

هنا تم فصل الإعدادات المتغيرة عن التكوين العام، لكن يظل الملف النصي نفسه نقطة حساسة. لذلك في البيئات الحقيقية يُنصح بالانتقال إلى أنظمة أسرار مخصصة بدلاً من الاعتماد الدائم على env_file.

متى تصبح Docker Secrets أفضل من المتغيرات البيئية؟

في بيئات الخدمات الموزعة أو عند استخدام Swarm، تُعد Docker Secrets خياراً أقوى. فهي لا تُحقن كقيم واضحة داخل البيئة، بل تُركب كملفات مؤقتة داخل الحاوية مع تحكم أفضل بالوصول.

printf "super-secret-password" | docker secret create db_password -

docker service create \
  --name myapp \
  --secret db_password \
  my-secure-app:latest

داخل التطبيق، يمكن قراءة السر من ملف موجود غالباً تحت المسار /run/secrets/. هذه الآلية تقلل احتمال التسرب عبر أدوات الفحص أو السجلات.

تمرير الأسرار في Kubernetes بطريقة احترافية

في البيئات السحابية الحديثة، خاصة عند تشغيل التطبيقات ضمن Pods متعددة، تُستخدم موارد Secret وConfigMap بشكل منفصل. الفكرة الأساسية هي أن البيانات العامة لا تُعامل مثل الأسرار.

apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
stringData:
  DB_PASSWORD: super-secure-password
  API_KEY: replace-with-real-key
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: secure-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: secure-app
  template:
    metadata:
      labels:
        app: secure-app
    spec:
      containers:
        - name: app
          image: my-secure-app:latest
          env:
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: app-secrets
                  key: DB_PASSWORD
            - name: API_KEY
              valueFrom:
                secretKeyRef:
                  name: app-secrets
                  key: API_KEY

رغم أن هذا الأسلوب شائع، يجب الانتباه إلى أن الأسرار في Kubernetes ليست مشفرة افتراضياً داخل etcd إلا إذا فعّلت التشفير على مستوى الكتلة Cluster.

استخدم سياسات RBAC لتقييد الوصول إلى موارد Secrets، وفعّل تشفير etcd، وتجنب منح حساب الخدمة ServiceAccount صلاحيات أوسع من الحاجة الفعلية. أي توسع غير مبرر قد يسمح بقراءة أسرار تطبيقات أخرى داخل نفس المنصة.

دمج إدارة الأسرار مع خطوط CI/CD

الخطأ الكبير في أنابيب النشر المستمر هو تمرير الأسرار كسلاسل نصية ثابتة داخل ملفات البناء. الأفضل أن تأتي القيم من مخزن أسرار مركزي مثل GitHub Secrets أو Jenkins Credentials أو خدمات خارجية مثل Vault.

name: deploy-app

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      APP_ENV: production
      API_KEY: ${{ secrets.API_KEY }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Deploy container
        run: docker run -e APP_ENV -e API_KEY my-secure-app:latest

الفكرة هنا أن السر لا يُكتب داخل المستودع، بل يُسحب وقت التنفيذ فقط. ومع ذلك، يجب إخفاؤه من السجلات وعدم تمريره إلى أوامر تطبع البيئة كاملة أثناء النشر أو الاختبار.

أفضل ممارسات معمارية لتقليل المخاطر

  • امنح كل خدمة أقل قدر ممكن من الأسرار وفق مبدأ Least Privilege.
  • افصل بين الإعدادات العامة والأسرار باستخدام ConfigMap وSecret.
  • دوّر كلمات المرور والمفاتيح بشكل دوري دون إعادة بناء الصورة.
  • امنع وصول المطورين أو الخدمات غير اللازمة إلى أسرار الإنتاج.
  • اربط الحاويات عبر شبكات معزولة، ويمكنك التوسع في ذلك عبر إدارة الشبكات (Docker Networks): كيف تتحدث الحاويات مع بعضها بأمان؟.
  • راقب محاولات الوصول غير الطبيعي عبر السجلات وأنظمة التدقيق Audit Logs.

الخلاصة

تمرير المتغيرات البيئية للحاويات ليس مجرد خطوة تشغيلية بسيطة، بل قرار معماري وأمني يؤثر مباشرة على سلامة التطبيق واستقراره. في البيئات الصغيرة يمكن استخدام ملفات .env بحذر، لكن مع التوسع تصبح الحاجة واضحة إلى أدوات مثل Docker Secrets وKubernetes Secrets ومخازن الأسرار المركزية.

كلما كان تصميمك للحاويات أقرب إلى العزل، وفصل المسؤوليات، وتقليل كشف الأسرار داخل أنظمة CI/CD، زادت موثوقية منصتك وانخفضت احتمالات الاختراق أو التوقف المفاجئ Downtime. وهذا بالضبط ما يميز البنية الاحترافية عن مجرد تشغيل حاوية تعمل مؤقتاً ثم تتعطل عند أول حادث أمني.

11 comments

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *