استخدام متغيرات البيئة في Lambda وتشفيرها باستخدام KMS

عندما تحتاج إلى تمرير نقطة نهاية قاعدة بيانات أو أي إعداد حساس إلى دالة Lambda، فإن تضمينها مباشرةً في الكود هو أسرع طريق نحو كارثة أمنية — سواء عبر تسريب في مستودع Git أو عند مشاركة حزمة النشر. متغيرات البيئة في Lambda هي الحل الأمثل لفصل الإعداد عن الكود، مع إمكانية تشفيرها باستخدام AWS KMS لحماية القيم الحساسة.

ملخص سريع (TL;DR) — متغيرات البيئة في Lambda

الجانبالتفاصيل
ما هي؟أزواج مفتاح/قيمة تُحقن في بيئة تشغيل الدالة عند الاستدعاء
متى تستخدمها؟نقاط نهاية قواعد البيانات، أسماء الجداول، مفاتيح API غير الحساسة جداً، أعلام الميزات
التشفير الافتراضيمشفرة أثناء النقل والتخزين باستخدام مفتاح Lambda المُدار من AWS
تشفير KMS المخصصاستخدام CMK خاص بك لمزيد من التحكم وصلاحيات الوصول
الحد الأقصى للحجم4 كيلوبايت لمجموع جميع متغيرات البيئة — راجع التوثيق الرسمي للقيود الحالية
البديل للأسرار الحساسةAWS Secrets Manager أو AWS Systems Manager Parameter Store

كيف تعمل متغيرات البيئة في Lambda

Lambda تخزّن متغيرات البيئة كجزء من إعداد الدالة، وتحقنها في عملية التشغيل عند بدء كل استدعاء. هذا يعني أن القيم متاحة عبر آليات متغيرات البيئة القياسية للغة البرمجة التي تستخدمها — os.environ في Python، أو process.env في Node.js.

التشفير يحدث على مستويين: Lambda تشفّر المتغيرات تلقائياً أثناء التخزين باستخدام مفتاح مُدار من AWS خاص بخدمة Lambda. إذا أردت التحكم الكامل — مثلاً لتقييد من يستطيع فك التشفير باستخدام سياسات KMS — فأنت بحاجة إلى توفير Customer Managed Key (CMK) خاص بك.

graph LR A["إعداد الدالة
Lambda Console / CLI"] --> B["تشفير المتغيرات
KMS Key"] B --> C["تخزين مشفر
Lambda Config"] C --> D["استدعاء الدالة"] D --> E["فك التشفير التلقائي
بواسطة Lambda"] E --> F["حقن في بيئة التشغيل
os.environ / process.env"] F --> G["كود الدالة
يقرأ القيم"]
  1. الإعداد: تُخزَّن متغيرات البيئة مشفرةً في إعداد الدالة باستخدام مفتاح KMS (افتراضي أو CMK مخصص).
  2. الاستدعاء: عند بدء تشغيل الدالة، تفك Lambda تشفير المتغيرات وتحقنها في بيئة التشغيل.
  3. الوصول: الكود يقرأ القيم عبر متغيرات البيئة القياسية — لا يوجد استدعاء API إضافي.
  4. التحكم بالوصول: إذا استخدمت CMK مخصصاً، فإن سياسة المفتاح تتحكم في من يستطيع تشفير/فك تشفير القيم.

إضافة متغيرات البيئة عبر AWS CLI

الطريقة الأكثر موثوقية في بيئات الإنتاج هي إدارة المتغيرات عبر CLI أو Infrastructure as Code — لا عبر Console يدوياً. هذا يضمن إمكانية التتبع والتكرار.

الخطوة 1: إنشاء الدالة مع متغيرات البيئة

إذا كنت تنشئ دالة جديدة وتريد تضمين المتغيرات من البداية:

aws lambda create-function \
  --function-name my-db-function \
  --runtime python3.12 \
  --role arn:aws:iam::123456789012:role/my-lambda-execution-role \
  --handler lambda_function.lambda_handler \
  --zip-file fileb://function.zip \
  --environment 'Variables={DB_ENDPOINT=mydb.cluster-xyz.us-east-1.rds.amazonaws.com,DB_NAME=production,APP_ENV=prod}' \
  --region us-east-1

الخطوة 2: تحديث متغيرات البيئة لدالة موجودة

هذا هو الأمر الذي ستستخدمه أكثر في الإنتاج — تحديث نقطة نهاية قاعدة البيانات بعد migration أو تغيير الإعداد. لاحظ أن update-function-configuration يستبدل جميع المتغيرات الحالية بالقيم الجديدة، لذا تأكد من تضمين جميع المتغيرات التي تريد الاحتفاظ بها:

aws lambda update-function-configuration \
  --function-name my-db-function \
  --environment 'Variables={DB_ENDPOINT=mydb-new.cluster-abc.us-east-1.rds.amazonaws.com,DB_NAME=production,APP_ENV=prod}' \
  --region us-east-1

الخطوة 3: التحقق من المتغيرات الحالية

قبل أي تغيير، تحقق مما هو مُعيَّن حالياً — هذا يمنع الاستبدال غير المقصود لمتغير ناسيته:

aws lambda get-function-configuration \
  --function-name my-db-function \
  --region us-east-1 \
  --query 'Environment.Variables'

تشفير متغيرات البيئة باستخدام KMS CMK

التشفير الافتراضي باستخدام المفتاح المُدار من AWS كافٍ لكثير من حالات الاستخدام. لكن إذا كنت في بيئة تتطلب تدقيقاً صارماً على من يستطيع الوصول إلى القيم — أو إذا كانت سياسات الامتثال تشترط استخدام مفاتيح خاصة بك — فأنت بحاجة إلى CMK.

sequenceDiagram participant Dev as المطور participant Lambda as Lambda Service participant KMS as AWS KMS participant Role as Execution Role Dev->>KMS: إنشاء CMK وتحديد سياسة المفتاح Dev->>Lambda: update-function-configuration مع kms-key-arn Lambda->>KMS: تشفير متغيرات البيئة باستخدام CMK KMS-->>Lambda: قيم مشفرة Note over Lambda: تُخزَّن المتغيرات مشفرةً Note over Lambda,Role: عند الاستدعاء Lambda->>KMS: طلب فك التشفير (باسم Execution Role) KMS->>Role: التحقق من سياسة IAM وسياسة المفتاح KMS-->>Lambda: قيم مفككة التشفير Lambda-->>Lambda: حقن في بيئة التشغيل
  1. إنشاء CMK: تُنشئ مفتاح KMS مخصصاً وتحدد سياسته لمنح Lambda صلاحية استخدامه.
  2. ربط CMK بالدالة: عند الإعداد، تحدد ARN المفتاح — Lambda تستخدمه لتشفير المتغيرات.
  3. صلاحيات execution role: دور تنفيذ Lambda يحتاج صلاحية kms:Decrypt على المفتاح لفك التشفير عند الاستدعاء.
  4. التدقيق: كل عملية فك تشفير تظهر في AWS CloudTrail مرتبطةً بالمفتاح المحدد.

الخطوة 1: إنشاء CMK في KMS

aws kms create-key \
  --description 'Lambda environment variables encryption key' \
  --key-usage ENCRYPT_DECRYPT \
  --region us-east-1

احفظ قيمة KeyId من الناتج — ستحتاجها في الخطوات التالية.

الخطوة 2: إنشاء alias للمفتاح (اختياري لكن موصى به)

aws kms create-alias \
  --alias-name alias/lambda-env-vars-key \
  --target-key-id YOUR_KEY_ID \
  --region us-east-1

الخطوة 3: منح execution role صلاحية استخدام المفتاح

هذه الخطوة يفوت عليها كثيرون — الدالة ستفشل في الاستدعاء بخطأ AccessDeniedException إذا لم يكن لدور التنفيذ صلاحية kms:Decrypt. أضف هذه السياسة إلى دور IAM الخاص بالدالة:

🔽 عرض سياسة IAM المطلوبة
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowLambdaToDecryptEnvVars",
      "Effect": "Allow",
      "Action": [
        "kms:Decrypt"
      ],
      "Resource": "arn:aws:kms:us-east-1:123456789012:key/YOUR_KEY_ID"
    }
  ]
}

الخطوة 4: ربط CMK بالدالة وتعيين المتغيرات

aws lambda update-function-configuration \
  --function-name my-db-function \
  --kms-key-arn arn:aws:kms:us-east-1:123456789012:key/YOUR_KEY_ID \
  --environment 'Variables={DB_ENDPOINT=mydb.cluster-xyz.us-east-1.rds.amazonaws.com,DB_NAME=production}' \
  --region us-east-1

قراءة المتغيرات داخل كود Lambda

Lambda تفك التشفير وتحقن القيم تلقائياً قبل تشغيل الكود — لا تحتاج إلى استدعاء KMS API يدوياً من داخل الدالة.

Python

import os

def lambda_handler(event, context):
    db_endpoint = os.environ['DB_ENDPOINT']
    db_name = os.environ['DB_NAME']
    app_env = os.environ.get('APP_ENV', 'development')  # قيمة افتراضية إذا لم يكن موجوداً
    
    # استخدم القيم في الاتصال بقاعدة البيانات
    print(f'Connecting to {db_name} at {db_endpoint} in {app_env} mode')
    return {'statusCode': 200}

Node.js

exports.handler = async (event) => {
    const dbEndpoint = process.env.DB_ENDPOINT;
    const dbName = process.env.DB_NAME;
    const appEnv = process.env.APP_ENV || 'development';
    
    console.log(`Connecting to ${dbName} at ${dbEndpoint} in ${appEnv} mode`);
    return { statusCode: 200 };
};

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

المشهد المتكرر: تُعيّن متغيرات البيئة بنجاح، تُشغّل الدالة، وتحصل على AccessDeniedException غامض. تتحقق من سياسة IAM لدور التنفيذ — تبدو صحيحة. تتحقق من KMS — المفتاح موجود.

التشخيص الخاطئ الأول: 'ربما المفتاح في منطقة مختلفة.' التشخيص الخاطئ الثاني: 'ربما الدالة لم تُحدَّث بعد.' الإجابة الفعلية في معظم الحالات: سياسة المفتاح في KMS نفسه لا تسمح لدور التنفيذ باستخدامه.

KMS يعمل بطبقتين من التحكم: سياسة IAM على الدور، وسياسة المفتاح على CMK نفسه. كلاهما يجب أن يسمح بالعملية. إذا كانت سياسة المفتاح الافتراضية تمنح التحكم الكامل لـ root فقط، فإن أي Explicit Allow في IAM لن يكفي وحده.

للتحقق من سياسة المفتاح الحالية:

aws kms get-key-policy \
  --key-id YOUR_KEY_ID \
  --policy-name default \
  --region us-east-1

تأكد من أن سياسة المفتاح تتضمن Principal يشمل دور تنفيذ Lambda أو تسمح للحساب بالتفويض عبر IAM. راجع توثيق KMS Key Policies للتفاصيل.

سياسة IAM على الدور هي تصريح من جانبك. سياسة المفتاح في KMS هي تصريح من جانب المفتاح. الاتصال يحتاج كليهما — مثل باب يحتاج مفتاحاً من الجانبين.

متى تستخدم Secrets Manager بدلاً من متغيرات البيئة

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

الحالةالأداة المناسبة
نقطة نهاية قاعدة بيانات، اسم bucketمتغيرات البيئة
كلمة مرور قاعدة بيانات، API secret keyAWS Secrets Manager أو SSM Parameter Store (SecureString)
تدوير تلقائي للأسرارAWS Secrets Manager
مشاركة الإعداد بين دوال متعددةSSM Parameter Store

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

الخلاصة والخطوات التالية

استخدام متغيرات البيئة في Lambda هو الطريقة الصحيحة لفصل الإعداد عن الكود وتجنب hardcoding نقاط النهاية. التشفير الافتراضي باستخدام المفتاح المُدار من AWS كافٍ لمعظم الحالات، بينما يمنحك CMK المخصص تحكماً كاملاً في سياسات الوصول والتدقيق. تذكر دائماً التحقق من طبقتي التحكم عند استخدام KMS: سياسة IAM على الدور وسياسة المفتاح على CMK نفسه.

مسرد المصطلحات

المصطلحالتعريف
CMK (Customer Managed Key)مفتاح KMS تنشئه وتديره بنفسك، يمنحك تحكماً كاملاً في سياسات الوصول والتدوير
Execution Roleدور IAM يُسند إلى دالة Lambda ويحدد الصلاحيات التي تملكها الدالة للوصول إلى خدمات AWS الأخرى
Key Policyسياسة موارد مرتبطة بمفتاح KMS تحدد من يستطيع استخدام المفتاح أو إدارته
Hardcodingتضمين قيم الإعداد مباشرةً في كود المصدر بدلاً من قراءتها من مصدر خارجي
Secrets Managerخدمة AWS لتخزين وتدوير الأسرار الحساسة مثل كلمات المرور ومفاتيح API

تعليقات

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

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

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

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