الأسرار ومتغيرات البيئة
الأسرار ومتغيرات البيئة
كل تطبيق إنتاجي يمتلك أسرارًا: كلمات مرور قواعد البيانات، ومفاتيح API، ومفاتيح توقيع JWT، ورموز خدمات الطرف الثالث. طريقة تعاملك مع هذه الأسرار هي إحدى أهم القرارات الأمنية التي تتخذها بوصفك مطورًا. يغطّي هذا الدرس الطيف الكامل — من الأخطاء الأكثر شيوعًا إلى الأنماط التي تعتمدها الفرق المحترفة عند نشر تطبيقات Spring Boot 3.
المشكلة الجوهرية: الأسرار داخل كود المصدر
أكثر الأخطاء شيوعًا هو ترميز بيانات الاعتماد مباشرةً في application.properties وإيداع ذلك الملف في نظام التحكم بالإصدارات. بمجرد أن يصل سر ما إلى مستودع Git، يصبح عمليًا عامًا — حتى في المستودعات الخاصة، لأن السجل يبقى، ويمكن أن يُسرَّب عبر حسابات مخترقة أو موظفين سابقين أو تعريض غير مقصود.
إليك النمط الذي يجب أن تتجنبه تمامًا في أي بيئة تتجاوز النماذج المحلية:
متغيرات البيئة: أساس منهجية الاثني عشر عاملًا
تحدّد منهجية Twelve-Factor App الحلَّ القياسي: خزّن الإعدادات التي تتغير بين البيئات (dev وstaging وprod) في متغيرات البيئة. يقرأ Spring Boot متغيرات بيئة نظام التشغيل تلقائيًا ويربطها بمفاتيح الخصائص وفق قاعدة ربط مرنة: يُعيَّن SPRING_DATASOURCE_PASSWORD إلى spring.datasource.password، ويُعيَّن STRIPE_API_KEY إلى stripe.api-key.
MY_APP_API_KEY وmy.app.api-key وmyApp.apiKey كلها تُعيَّن إلى الخاصية ذاتها. يُفضَّل استخدام SCREAMING_SNAKE_CASE لمتغيرات البيئة — فهو اتفاقية Unix ولا يكتنفه أي غموض في السكريبتات.
على خادم Linux أو macOS تُصدر المتغيرات قبل تشغيل JVM:
في application.properties تُشير إليها بعناصر نائبة ${}:
القيمة المفصولة بنقطتين (${DB_HOST:localhost}) هي القيمة الافتراضية عند غياب المتغير. استخدم القيم الافتراضية للقيم غير الحساسة كأسماء المضيفين في بيئة التطوير، لكن لا توفّر قيمة افتراضية لأي سر أبدًا — غياب السر يجب أن يُفشل التطبيق عند بدء التشغيل حتى تكتشف المشكلة فورًا لا أن تستمر بقيمة خاطئة بصمت.
ملف .env وملفات تعريف Spring
في بيئة التطوير المحلي، كتابة أوامر export قبل كل تشغيل أمر مرهق. الحل المعتاد هو ملف .env في جذر المشروع:
أضف .env فورًا إلى .gitignore. لا يقرأ Spring Boot ملف .env أصلًا، لكن عدة مقاربات تعالج ذلك:
- إعدادات تشغيل IDE — تتيح IntelliJ IDEA وVS Code تحديد ملف env في إعدادات التشغيل. وهذا أنظف مقاربة محلية.
- dotenv-spring-boot — مكتبة خفيفة (
me.paulschwarz:spring-dotenv) تحمّل.envتلقائيًا فيEnvironmentالخاصة بـ Spring. - تحميل الملف في الشِّل —
set -a; source .env; set +a; ./mvnw spring-boot:runيُصدر كل سطر قبل استدعاء Maven.
.env.example في المستودع. يسرد هذا الملف كل متغير مطلوب بقيمة عنصر نائب وتعليق يشرح الغرض منه. ينسخه أعضاء الفريق الجدد إلى .env ويملؤونه. يوثّق هذا المتطلبات دون تسريب الأسرار.
قراءة الأسرار برمجيًا مع @Value و@ConfigurationProperties
بمجرد أن يكون المتغير في البيئة (أو في application.properties عبر عنصر نائب)، يحلّه Spring تلقائيًا. يمكنك حقنه بـ @Value:
أو اربط مجموعة من الأسرار المترابطة بفئة @ConfigurationProperties (تمت تغطيتها بعمق في الدرس الثاني، لكنها تستحق التذكير هنا):
log.debug("API key: {}", apiKey) في خدمة تُستدعى مع كل طلب ستبثّ سرّك في كل مجمّع سجلات تستخدمه مؤسستك.
الأسرار في البيئات الحاوية (Docker وKubernetes)
عند التشغيل في Docker، مرّر متغيرات البيئة عند بدء تشغيل الحاوية:
في Docker Compose للتطوير، استخدم توجيه env_file:
في Kubernetes، الآلية الاصطلاحية هي كائن Secret يُثبَّت كمتغيرات بيئة أو كمجلد. لا تدمج الأسرار أبدًا في صورة Docker أو في ConfigMap (الذي لا يُشفَّر في حالة الراحة).
مديرو الأسرار الخارجيون
للفرق التي تحتاج إلى سجلات تدقيق وتدوير تلقائي وتحكم دقيق في الوصول، يكون مدير الأسرار المخصص هو الأداة الصحيحة. الخيارات الرئيسية تتكامل مع Spring Boot عبر Spring Cloud:
- HashiCorp Vault — محلي أو سحابي؛ يقرأ
spring-cloud-vaultالأسرار عند بدء التشغيل ويحقنها خصائصَ. - AWS Secrets Manager / Parameter Store — يحلّ
spring-cloud-awsخصائصaws.secretsmanager.secret-nameتلقائيًا. - Azure Key Vault — يعيّن
azure-spring-cloud-starter-keyvault-secretsمدخلات الخزنة إلى خصائص Spring.
مع Spring Cloud Vault يصبح ملف bootstrap.yml (أو application.yml بالاستيراد الصحيح) بسيطًا كما يلي:
عندها يحلّ Spring Boot ${stripe.api-key} بجلب مسار السر myapp من Vault عند بدء التشغيل — لا يلمس السر نظام الملفات أو ملف خصائص قط.
الخلاصة: قائمة التحقق من معالجة الأسرار
- أضف
.envوأي ملفات*-secrets.propertiesإلى.gitignoreقبل أول إيداع. - استخدم عناصر نائبة
${ENV_VAR}في ملفاتapplication.propertiesالمُودَعة — لا قيم مرمّزة. - قدّم
.env.exampleبتعليقات دون قيم حقيقية. - لا توفّر قيمة افتراضية لعنصر نائب يمثّل سرًّا (أفشل بصوت عالٍ عند غيابه).
- لا تسجّل قيم الأسرار — حتى في وضع
DEBUG. - في الإنتاج، احقن عبر متغيرات بيئة نظام التشغيل أو أسرار Docker أو أسرار Kubernetes أو مدير أسرار متخصص.
- دوّر أي سر تعرّض للكشف — عامله باعتباره مخترقًا نهائيًا.
اتباع هذه القواعد لا يكلّف جهدًا إضافيًا يُذكر ويمنع أكثر فئات حوادث الأمان الإنتاجية شيوعًا. يبني الدرس التالي على هذا الأساس ليغطي بنية إعدادات YAML الكاملة التي تجعل إعدادات Spring Boot المعقدة قابلة للقراءة والصيانة.