لماذا تستخدم Secrets Manager بدلاً من تخزين كلمات المرور في الكود؟

في كل مرة يُقال فيها 'المستودع خاص، لا أحد سيرى كلمة المرور'، تبدأ قصة اختراق جديدة. تخزين بيانات اعتماد قاعدة البيانات داخل الكود هو أحد أكثر الأخطاء شيوعاً في بيئات الإنتاج، وAWS Secrets Manager موجود تحديداً لإغلاق هذا الباب.

ملخص سريع (TL;DR)

الجانب Hardcoding في الكود AWS Secrets Manager
مكان التخزين داخل الكود / ملفات البيئة مخزن مشفر مُدار بالكامل
التدوير التلقائي يدوي — يتطلب نشراً جديداً تلقائي عبر Lambda
التدقيق والمراقبة لا يوجد CloudTrail لكل عملية وصول
تسريب السر أي شخص يرى الكود يرى السر IAM يتحكم في من يصل
التكلفة صفر — حتى يحدث الاختراق تسعير حسب الاستخدام — راجع توثيق AWS

كيف يعمل AWS Secrets Manager

Secrets Manager ليس مجرد قاموس مشفر. هو خدمة دورة حياة كاملة للأسرار: تخزين، وصول، تدوير، وتدقيق. عندما يطلب تطبيقك سراً، يتصل بـ Secrets Manager عبر API، الخدمة تتحقق من صلاحيات IAM، ثم تُعيد القيمة المشفرة بعد فك تشفيرها باستخدام AWS KMS.

graph LR App["التطبيق"] -->|"GetSecretValue"| SM["Secrets Manager"] SM -->|"التحقق من الصلاحيات"| IAM["IAM"] IAM -->|"مسموح"| SM SM -->|"فك التشفير"| KMS["AWS KMS"] KMS -->|"القيمة المفككة"| SM SM -->|"بيانات الاعتماد"| App SM -->|"تسجيل الوصول"| CT["CloudTrail"]
  1. التطبيق يستدعي GetSecretValue بدلاً من قراءة متغير بيئة.
  2. IAM يتحقق أن الدور المرتبط بالتطبيق لديه صلاحية secretsmanager:GetSecretValue.
  3. KMS يفك تشفير السر قبل إعادته — المفتاح لا يغادر KMS أبداً.
  4. CloudTrail يسجل كل استدعاء: من طلب، متى، من أي IP.
  5. عند التدوير، Lambda تُحدّث السر في Secrets Manager وفي قاعدة البيانات بشكل متزامن.

لماذا المستودع الخاص لا يكفي

المستودع الخاص يحمي من الوصول العام، لكنه لا يحمي من:

  • Git history: حتى لو حذفت كلمة المرور لاحقاً، تاريخ الـ commits يحتفظ بها إلى الأبد ما لم تُعد كتابة التاريخ بالكامل.
  • المطورين السابقين: أي شخص استنسخ المستودع يحمل نسخة محلية من السر.
  • أدوات CI/CD: Jenkins، GitHub Actions، وغيرها تقرأ الكود — وبالتالي تقرأ السر.
  • تسريب السجلات: إذا طُبع السر في log بالخطأ، يصبح مرئياً لكل من يملك وصولاً للسجلات.
المستودع الخاص مثل خزنة بزجاج شفاف — من الداخل تبدو آمنة، لكن كل من دخل المبنى يرى ما بداخلها.

إعداد AWS Secrets Manager — خطوة بخطوة

الخطوة 1: إنشاء السر

ابدأ بتخزين بيانات اعتماد قاعدة البيانات. هذا يُنشئ السر ويُشفّره فوراً باستخدام KMS.

aws secretsmanager create-secret \
  --name 'prod/myapp/db-credentials' \
  --description 'RDS credentials for production app' \
  --secret-string '{"username":"dbadmin","password":"MySecurePass123!"}' \
  --region us-east-1

الناتج يتضمن ARN للسر — احتفظ به، ستحتاجه في سياسة IAM.

الخطوة 2: منح التطبيق صلاحية الوصول

بدلاً من توزيع كلمة المرور، تمنح الدور المرتبط بتطبيقك صلاحية قراءة هذا السر تحديداً — مبدأ الصلاحية الأدنى تطبيقياً.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowAppToReadSecret",
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret"
      ],
      "Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/myapp/db-credentials-*"
    },
    {
      "Sid": "AllowKMSDecrypt",
      "Effect": "Allow",
      "Action": [
        "kms:Decrypt"
      ],
      "Resource": "arn:aws:kms:us-east-1:123456789012:key/your-kms-key-id"
    }
  ]
}

لاحظ أن ARN السر ينتهي بـ -* لأن Secrets Manager يُضيف لاحقة عشوائية عند الإنشاء.

الخطوة 3: قراءة السر من الكود

بدلاً من password = 'hardcoded_value'، يستدعي التطبيق API مرة واحدة عند البدء أو عند الحاجة.

🔽 مثال Python — اضغط للتوسيع
import boto3
import json

def get_db_credentials(secret_name: str, region: str = 'us-east-1') -> dict:
    client = boto3.client('secretsmanager', region_name=region)
    response = client.get_secret_value(SecretId=secret_name)
    secret = json.loads(response['SecretString'])
    return secret

# الاستخدام
creds = get_db_credentials('prod/myapp/db-credentials')
db_user = creds['username']
db_pass = creds['password']

الخطوة 4: التحقق من السر الحالي

قبل إعداد التدوير، تحقق من حالة السر الحالية.

aws secretsmanager describe-secret \
  --secret-id 'prod/myapp/db-credentials' \
  --region us-east-1

التدوير التلقائي لكلمات المرور — كيف يعمل فعلاً

هذا هو الجزء الذي يُفرّق Secrets Manager عن مجرد تخزين مشفر. التدوير التلقائي يعني أن كلمة المرور تتغير دورياً دون أي تدخل بشري ودون إعادة نشر التطبيق.

sequenceDiagram participant SCH as Secrets Manager Scheduler participant LMB as Lambda Function participant RDS as RDS Database participant SM as Secrets Manager Store participant APP as التطبيق SCH->>LMB: تشغيل دورة التدوير LMB->>RDS: تحديث كلمة المرور في قاعدة البيانات RDS-->>LMB: تأكيد التحديث LMB->>SM: تحديث السر بالكلمة الجديدة SM-->>LMB: تأكيد الحفظ LMB->>RDS: اختبار الاتصال بالكلمة الجديدة RDS-->>LMB: الاتصال ناجح APP->>SM: GetSecretValue (الطلب التالي) SM-->>APP: كلمة المرور الجديدة تلقائياً
  1. Secrets Manager يُطلق دالة Lambda في الموعد المحدد.
  2. Lambda تُنشئ كلمة مرور جديدة وتُحدّثها في قاعدة البيانات.
  3. Lambda تُحدّث القيمة في Secrets Manager بالكلمة الجديدة.
  4. Lambda تتحقق أن الاتصال بقاعدة البيانات يعمل بالكلمة الجديدة.
  5. في المرة القادمة التي يطلب فيها التطبيق السر، يحصل على الكلمة الجديدة تلقائياً.

تهيئة التدوير التلقائي عبر CLI

التدوير يتطلب دالة Lambda تنفذ منطق التحديث. عند استخدام واجهة AWS Console مع RDS، يمكن لـ AWS إنشاء هذه الدالة تلقائياً. عبر CLI، يجب تحديد ARN الدالة صراحةً باستخدام --rotation-lambda-arn.

aws secretsmanager rotate-secret \
  --secret-id 'prod/myapp/db-credentials' \
  --rotation-lambda-arn 'arn:aws:lambda:us-east-1:123456789012:function:SecretsManagerRDSRotation' \
  --rotation-rules '{"AutomaticallyAfterDays": 30}' \
  --region us-east-1

إذا لم تكن دالة Lambda موجودة بعد، يمكنك نشرها من قوالب التدوير الجاهزة من AWS قبل تشغيل هذا الأمر.

التحقق من حالة التدوير

aws secretsmanager describe-secret \
  --secret-id 'prod/myapp/db-credentials' \
  --query '{RotationEnabled:RotationEnabled,LastRotatedDate:LastRotatedDate,NextRotationDate:NextRotationDate}' \
  --region us-east-1

تجربة حقيقية: الخطأ الذي يقع فيه الجميع

السيناريو الكلاسيكي: فريق يُفعّل التدوير، ويلاحظ بعد 30 دقيقة أن التطبيق بدأ يُعيد أخطاء authentication failed من قاعدة البيانات. التشخيص الأول يكون دائماً 'ربما Lambda فشلت في التحديث'.

الأمر الفعلي: التطبيق كان يُخزّن كلمة المرور في الذاكرة عند البدء ولا يُعيد جلبها. بعد التدوير، Secrets Manager يحمل الكلمة الجديدة، لكن التطبيق لا يزال يستخدم القديمة المخزنة في متغير محلي.

الإصلاح: التطبيق يجب أن يستدعي GetSecretValue عند كل اتصال بقاعدة البيانات، أو على الأقل عند اكتشاف خطأ مصادقة — وليس مرة واحدة فقط عند بدء التشغيل. هذا تفاعل بين آلية التدوير وطريقة تخزين السر في الذاكرة — لا يظهر في توثيق أي من الطرفين بشكل صريح.

التدوير التلقائي لا يُصلح تطبيقاً يُخزّن السر في الذاكرة — هو يُغيّر القفل، لكن التطبيق لا يزال يحمل المفتاح القديم.

Secrets Manager مقابل SSM Parameter Store

كلاهما يخزن أسراراً، لكن لكل منهما حالة استخدام مختلفة.

الميزة Secrets Manager SSM Parameter Store
التدوير التلقائي ✅ مدمج ❌ يدوي
حجم القيمة حتى 65536 بايت حتى 4096 بايت (Standard) وحتى 8192 بايت (Advanced)
التكامل مع RDS ✅ مدمج ❌ يدوي
التسعير مدفوع لكل سر مجاني (Standard) / مدفوع (Advanced)
الاستخدام المثالي بيانات الاعتماد الحساسة إعدادات التطبيق وغير الحساسة

القاعدة العملية: إذا كان السر يحتاج تدويراً أو يرتبط بقاعدة بيانات، استخدم Secrets Manager. لباقي الإعدادات، Parameter Store كافٍ وأرخص.

لماذا AWS Secrets Manager هو الخيار الصحيح للإنتاج

الاستمرار في استخدام Hardcoding يعني أن كل مطور جديد، كل أداة CI/CD، وكل نسخة من الكود تحمل مفتاح قاعدة البيانات. Secrets Manager يُحوّل هذا من 'من يملك الكود يملك الوصول' إلى 'من يملك الدور الصحيح في IAM يملك الوصول' — وهذا الفرق هو جوهر نموذج الأمان في AWS.

الخطوة التالية: راجع التوثيق الرسمي لـ AWS Secrets Manager لاستكشاف قوالب التدوير الجاهزة لـ RDS وRedshift وDocumentDB.

المصطلحات الأساسية

المصطلح التعريف
Secret Rotation عملية تغيير كلمة المرور أو بيانات الاعتماد تلقائياً بشكل دوري دون تدخل بشري
KMS (Key Management Service) خدمة AWS لإدارة مفاتيح التشفير — تُشفّر الأسرار المخزنة في Secrets Manager
IAM Role هوية AWS تمنح صلاحيات محددة للتطبيقات والخدمات بدلاً من استخدام بيانات اعتماد ثابتة
Hardcoding تضمين قيم حساسة مباشرة في الكود المصدري أو ملفات الإعداد
CloudTrail خدمة تسجيل API calls في AWS — تُوثّق كل وصول إلى الأسرار

Related Posts

تعليقات

المشاركات الشائعة من هذه المدونة

استرجاع معرّف نسخة EC2 عبر خدمة البيانات الوصفية IMDSv2

أوضاع سعة DynamoDB: متى تختار On-Demand ومتى تختار Provisioned؟

فهم مهلة الرؤية في SQS: لماذا تُعالَج رسائلك مرتين؟