تمرير المتغيرات البيئية (Environment Variables) للحاويات بشكل آمن
تمرير المتغيرات البيئية 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