التعامل الآمن مع الأسرار ونظافة البيئة
أبقِ بيانات الاعتماد خارج قوائم العمليات والسجلات باستخدام الإدخال القياسي والملفات والبيئات المنقّحة
التعامل الآمن مع الأسرار ونظافة البيئة درس مجاني في DevOps Bootcamp على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في DevOps Bootcamp، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة DevOps Bootcamp 4 دروس في المجموع.
لماذا تُعدّ النظافة الأمنية للأسرار مهمة
الأسرار — مثل مفاتيح API وكلمات المرور والرموز المميزة — هي أكثر البيانات حساسية في أي نظام. ويُعدّ سوء التعامل معها في برامج Bash النصية من أكثر الأخطاء الأمنية شيوعًا وأشدها ضررًا.
- قوائم العمليات: تظهر الوسائط الممررة إلى الأوامر في
ps auxو/proc/<pid>/cmdlineوسجلات تدقيق النظام، ويمكن لجميع المستخدمين على المضيف رؤيتها. - سجل الصدفة: تُسجّل الأوامر المكتوبة تفاعليًا (وأحيانًا البرامج النصية) في
~/.bash_history. - ملفات السجل: يمكن لتتبعات
set -xوسجلات التطبيقات ومخرجات CI/CD التقاط قيم المتغيرات. - تسرّب البيئة: ترث العمليات الابنة البيئة الكاملة للعملية الأم، بما في ذلك أي أسرار مُصدّرة.
يتعامل البرنامج النصي المحصّن مع الأسرار كما لو كانت مواد مشعة — يقلل مدة التعرض، ويحد من مساحة الانتشار، وينقّي كل شيء عند إخراجه.
سطح الهجوم في قوائم العمليات
عندما تمرر سرًا باعتباره وسيطًا لسطر الأوامر، يستطيع كل مستخدم على النظام قراءته فورًا عبر ps. وهذا ليس أمرًا نظريًا؛ إذ يُستغل بانتظام في بيئات الاستضافة المشتركة والحاويات.
يوضح المقتطف أدناه المشكلة والإصلاح جنبًا إلى جنب.
#!/usr/bin/env bash
# DANGEROUS: password visible in 'ps aux' output
# curl -u "admin:SuperSecret123" https://api.example.com/data
# SAFE: pass credentials via stdin or a flag that reads from a file
# Many tools support reading secrets from stdin with '-' or dedicated flags:
# Option 1 — pipe the secret so it never appears in argv
echo 'SuperSecret123' | curl -u 'admin' --password-stdin \
https://api.example.com/data 2>/dev/null || true
# Option 2 — write a temporary netrc and point curl at it
# (covered in a later scene)
echo 'Secret never touches the command line this way'قراءة الأسرار من stdin
إن النمط التفاعلي الأكثر أمانًا هو قراءة السر أثناء التشغيل باستخدام read -rs. إذ يمنع الخيار -s عرض المحارف، بينما يمنع الخيار -r تفسير الشرطات المائلة العكسية.
نقاط أساسية:
- لا يُصدَّر المتغير أبدًا، لذلك لا تستطيع العمليات الابنة رؤيته عبر
/proc/<pid>/environ. - بعد استخدامه، ألغِ تعيين المتغير فورًا باستخدام unset لتقليص فترة التعرض.
- تجنب
echo "$SECRET"— واستخدمprintf '%s'لمنع سطر جديد لاحق من إفساد القيمة، ولتبقى القيمة غير ظاهرة في التتبعات.
#!/usr/bin/env bash
set -euo pipefail
# Prompt on stderr so stdout stays clean for piping
read -rsp 'Enter API token: ' API_TOKEN <&2
printf '\n' >&2
# Use the secret — printf keeps it out of argv
response=$(printf '%s' "$API_TOKEN" | curl -sS -X POST \
-H 'Content-Type: application/json' \
--data-binary @- \
https://httpbin.org/post 2>/dev/null) || true
echo "Request sent."
# Scrub immediately — unset removes it from shell memory
unset API_TOKENالأسرار في الملفات: الأذونات والملكية
عندما يجب أن يبقى سرّ ما محفوظًا على القرص (مثل مفتاح حساب خدمة)، فإن أذونات الملف هي وسيلة دفاعكم الأساسية.
- الوضع 0600 — يمكن للمالك وحده القراءة والكتابة. ولا يوجد وصول للمجموعة أو لأي مستخدم آخر.
- الوضع 0400 — للمالك حق القراءة فقط. ويُفضَّل استخدامه للمفاتيح التي يجب ألا تستبدلوها عن طريق الخطأ مطلقًا.
- خزّنوا ملفات الأسرار ضمن دليل مخصّص مثل
~/.secrets/أو/run/secrets/(والأخير هو نظام ملفات tmpfs مدعوم بذاكرة RAM في كثير من أنظمة Linux، ولا يبقى إلا حتى إعادة التشغيل). - لا تضعوا ملفات الأسرار داخل دليل يتتبعه git مطلقًا من دون ملف
.gitignoreمحكم وموثوق تمامًا.
#!/usr/bin/env bash
set -euo pipefail
SECRETS_DIR="${HOME}/.secrets"
mkdir -p "$SECRETS_DIR"
chmod 700 "$SECRETS_DIR" # directory: only owner can list contents
KEY_FILE="${SECRETS_DIR}/api_token"
# Write secret — atomically restrict permissions before writing content
install -m 0600 /dev/null "$KEY_FILE"
printf '%s' 'my-super-secret-token' > "$KEY_FILE"
echo "Permissions:"
ls -la "$KEY_FILE"
# Read back safely — no subshell, no echo
API_TOKEN=$(< "$KEY_FILE")
echo "Token length: ${#API_TOKEN} chars (value not printed)"
unset API_TOKENاستخدام ملف .netrc مع curl
يدعم curl ملف ~/.netrc (أو مسارًا عشوائيًا عبر --netrc-file) يربط أسماء المضيفين ببيانات الاعتماد. ويؤدي ذلك إلى إبقاء بيانات المصادقة بعيدة تمامًا عن سطر الأوامر ونصّ البرنامج النصي.
تنسيق الملف بسيط:
machine api.example.com
login admin
password s3cr3tأفضل الممارسات:
- اضبطوا دائمًا
chmod 0600 ~/.netrc— إذ يرفض curl الملف إذا كان مقروءًا من جميع المستخدمين على بعض الأنظمة. - استخدموا
--netrc-file /run/secrets/netrcللإشارة إلى سرّ مدعوم بـ tmpfs أو مُحقن داخل الحاوية. - نظّفوا ملفات netrc المؤقتة باستخدام
trapعند EXIT.
#!/usr/bin/env bash
set -euo pipefail
TMP_NETRC=$(mktemp)
chmod 0600 "$TMP_NETRC"
# Trap ensures cleanup even on error or signal
trap 'rm -f "$TMP_NETRC"' EXIT
# Write credentials to the temp netrc
cat > "$TMP_NETRC" <<'EOF'
machine httpbin.org
login myuser
password mypassword
EOF
curl -fsS --netrc-file "$TMP_NETRC" \
https://httpbin.org/basic-auth/myuser/mypassword \
-o /dev/null -w 'HTTP %{http_code}\n' || true
# trap fires here: $TMP_NETRC is deleted
echo 'Temp netrc cleaned up by trap.'سلامة متغيرات البيئة
تُعدّ متغيرات البيئة طريقة شائعة لحقن الأسرار في البرامج النصية (في تطبيقات 12-factor وخطوط CI/CD). لكنها تتسرّب إلى كل عملية فرعية وتظهر في /proc/<pid>/environ طوال مدة العملية.
أساليب دفاعية:
- استوردوا السر فورًا إلى متغير محلي ثم ألغوا ضبط متغير البيئة حتى لا تتمكن العمليات الفرعية من وراثته.
- مرّروا الأسرار إلى أوامر محددة باستخدام
env -iأو باستخدام إسناد inline بدلًا من تمرير البيئة الموروثة كاملة. - لا تستخدموا
exportلمتغير سرّي مطلقًا — استخدموا الإسناد فقط (من دونexport) متى أمكن.
#!/usr/bin/env bash
set -euo pipefail
# Simulate a secret arriving via environment (e.g., from CI system)
export DB_PASSWORD='hunter2' # set by CI — we did not choose this
# Capture locally, then strip from environment immediately
db_password="$DB_PASSWORD"
unset DB_PASSWORD
# Verify the env var is gone before spawning any child process
if printenv DB_PASSWORD 2>/dev/null; then
echo 'ERROR: DB_PASSWORD still in environment!' >&2
exit 1
fi
echo 'Secret captured and env var scrubbed.'
echo "Password length: ${#db_password}"
unset db_passwordمنع ظهور الأسرار في تتبعات set -x
يُعدّ set -x (xtrace) أداة لا غنى عنها لتصحيح الأخطاء، لكنه يطبع قيمة كل متغير يوسّعه — بما في ذلك الأسرار — إلى stderr. وغالبًا ما تنتهي هذه التتبعات في سجلات CI أو syslog.
استراتيجيات حماية الأسرار مع الإبقاء على فائدة التتبع:
- عطّلوا التتبع مؤقتًا حول العمليات الحساسة باستخدام
{ set +x; } 2>/dev/null. - أعيدوا تفعيله بعد ذلك باستخدام
set -x. - وجّهوا مخرجات xtrace إلى واصف ملف منفصل يرسلها إلى ملف سجل محمي، لا إلى مجرى السجل العام.
#!/usr/bin/env bash
set -euo pipefail
set -x # tracing ON — safe for non-sensitive sections
echo 'Building application...'
SRC_DIR='/tmp/build'
mkdir -p "$SRC_DIR"
# Disable xtrace around secret handling (suppress the set +x line itself)
{ set +x; } 2>/dev/null
read -rsp 'Token (hidden from trace): ' SECRET_TOKEN <&2
printf '\n' >&2
token_len=${#SECRET_TOKEN}
unset SECRET_TOKEN
set -x # tracing back ON
echo "Token captured (length=$token_len). Continuing build..."
ls "$SRC_DIR"تنقية الأسرار من ملفات السجل
حتى عند توخي الحذر، قد تجد الأسرار طريقها أحيانًا إلى مخرجات السجل — ولا سيما في البرامج النصية المطوّلة أو القديمة. وتضيف دالة تغليف للتسجيل، تحجب الأنماط المعروفة، طبقة أمان إضافية.
يستخدم هذا النمط استبدالًا قائمًا على regex لجميع مخرجات السجل. وهو طبقة الملاذ الأخير، وليس بديلًا عن ممارسات السلامة الأخرى التي تناولناها.
#!/usr/bin/env bash
set -euo pipefail
# A logging function that scrubs common secret patterns before writing
log() {
local line
# Replace anything that looks like key=VALUE or password=VALUE
line=$(printf '%s\n' "$*" \
| sed -E 's/(password|token|secret|key)=[^[:space:]]*/\1=***REDACTED***/gi')
printf '[%s] %s\n' "$(date -u '+%T')" "$line"
}
# Usage:
log 'Connecting to database with password=hunter2'
log 'Loaded API token=sk-abc123xyz secret'
log 'Build step completed successfully' # unchangedبيئات معزولة باستخدام env -i
يبدأ env -i أمرًا باستخدام بيئة فارغة تمامًا، ما يمنع وصول أي متغيرات موروثة — بما فيها الأسرار غير المقصودة — إلى العملية الفرعية. ثم تمرّرون صراحةً ما تحتاجون إليه فقط.
يفيد ذلك خصوصًا عند تشغيل برامج نصية غير موثوقة أو أدوات بناء أو أدوات من جهات خارجية قد تستخرج بيانات البيئة.
#!/usr/bin/env bash
set -euo pipefail
# Polluted parent environment (simulating a CI runner)
export AWS_SECRET_ACCESS_KEY='AKIAIOSFODNN7EXAMPLE'
export GITHUB_TOKEN='ghp_faketoken123'
export HOME="$HOME"
export PATH="$PATH"
echo '--- Child sees full environment:'
env | grep -E 'AWS|GITHUB' | head -5
echo '--- Sanitised child (env -i) sees nothing secret:'
env -i HOME="$HOME" PATH="$PATH" TERM="${TERM:-dumb}" \
bash -c 'env | grep -E "AWS|GITHUB" || echo "No secrets visible"'
unset AWS_SECRET_ACCESS_KEY GITHUB_TOKENملفات الأسرار المؤقتة على tmpfs
tmpfs هو نظام ملفات مدعوم بذاكرة RAM. ولا تُفرَّغ الملفات المكتوبة فيه إلى القرص مطلقًا، ما يلغي خطر بقاء الأسرار في مساحة التبديل أو ذاكرة التخزين المؤقت للقرص أو اللقطات.
- في Linux، يكون كل من
/dev/shmو/run/user/<uid>عادةً نقطتي تحميل tmpfs. - احرصوا دائمًا على إقران استخدام tmpfs بـ
trap EXITلحذف الملفات عند انتهاء البرنامج النصي. - في الحاويات (Docker وKubernetes)، يمكن تحميل الأسرار مباشرةً كوحدات tmpfs داخل
/run/secrets.
#!/usr/bin/env bash
set -euo pipefail
# Prefer /run/user/$UID (user-owned tmpfs) or /dev/shm (world-readable dir!)
if [[ -d "/run/user/$UID" ]]; then
TMPFS_DIR="/run/user/$UID"
elif [[ -d '/dev/shm' ]]; then
TMPFS_DIR='/dev/shm'
else
# Fallback: warn that disk will be used
echo 'WARNING: No tmpfs available; using /tmp (disk-backed)' >&2
TMPFS_DIR='/tmp'
fi
SECRET_FILE=$(mktemp "${TMPFS_DIR}/secret.XXXXXX")
chmod 0600 "$SECRET_FILE"
trap 'shred -u "$SECRET_FILE" 2>/dev/null || rm -f "$SECRET_FILE"' EXIT
printf '%s' 'my-runtime-token' > "$SECRET_FILE"
echo "Secret stored in: $SECRET_FILE"
df -T "$SECRET_FILE" | awk 'NR==2 {print "Filesystem type:", $2}'
# Use the secret...
token=$(< "$SECRET_FILE")
echo "Token length: ${#token}"
unset token
# trap fires on exit: file shreddedجمع كل العناصر: برنامج نصي للنشر محصَّن
يجمع البرنامج النصي التالي كل التقنيات الواردة في هذا الدرس ضمن مساعد نشر واقعي. لاحظوا كيف تعزّز كل طبقة من طبقات الدفاع الطبقات الأخرى:
- القراءة من stdin باستخدام
-s— من دون إظهار الإدخال في الطرفية - ملف سرّ على tmpfs مع تنظيف باستخدام
trap - تنقية البيئة — إلغاء ضبط السر قبل أي عملية فرعية
- حارس xtrace — إيقاف التتبع حول التعليمات البرمجية الحساسة
- حجب السجلات — استخدام regex كشبكة أمان قبل الكتابة إلى السجل
#!/usr/bin/env bash
set -euo pipefail
### 1. Redacting logger
log() {
local msg
msg=$(printf '%s' "$*" \
| sed -E 's/(password|token|secret|key)=[^[:space:]]*/\1=***/gi')
printf '[%s] %s\n' "$(date -u +%T)" "$msg"
}
### 2. tmpfs secret store
TMPFS_DIR="${XDG_RUNTIME_DIR:-/tmp}"
SECRET_FILE=$(mktemp "${TMPFS_DIR}/deploy_token.XXXXXX")
chmod 0600 "$SECRET_FILE"
trap 'rm -f "$SECRET_FILE"; log "Secret file cleaned up."' EXIT
### 3. Read secret without trace
{ set +x; } 2>/dev/null
read -rsp 'Deploy token: ' _tok <&2; printf '\n' >&2
printf '%s' "$_tok" > "$SECRET_FILE"
unset _tok
set -x
### 4. Scrub inherited env vars before subprocess
unset DEPLOY_TOKEN 2>/dev/null || true
log 'Starting deployment...'
# Simulate deploy using secret from file (token never in argv)
# curl -H "Authorization: Bearer $(< $SECRET_FILE)" https://api.example.com/deploy
log 'Deployment complete. token=hidden_by_redactor'
echo 'Done.'اختبار المعرفة: انكشاف الأسرار عبر قائمة العمليات
اختبروا فهمكم لكيفية تسرّب الأسرار عبر قوائم العمليات وكيفية منع ذلك.
مراجعة الدرس: التعامل الآمن مع الأسرار
لقد أكملتم درس التعامل الآمن مع الأسرار وسلامة البيئة. إليكم مرجعًا موجزًا لكل ما تناولناه:
- قوائم العمليات: لا تمرّروا الأسرار أبدًا كوسائط لسطر الأوامر — إذ تظهر في
ps auxو/proc/<pid>/cmdline. استخدموا تمريرها عبر stdin أو--netrc-fileبدلًا من ذلك. - القراءة من stdin: استخدموا
read -rsلجمع الأسرار تفاعليًا من دون إظهارها في الطرفية أو كشفها في سجل الصدفة. - أذونات الملفات: يجب أن تكون ملفات الأسرار بإذن
chmod 0600(أو0400). استخدمواinstall -m 0600للإنشاء الذري. - ملفات netrc: فوّضوا بيانات الاعتماد إلى ملف مؤقت يُحدَّد عبر
--netrc-file، ونظّفوه باستخدامtrap EXIT. - سلامة البيئة: ألغوا فورًا ضبط متغيرات البيئة السرية باستخدام
unsetبعد حفظها محليًا؛ ولا تستخدمواexportلها بلا حاجة؛ واستخدمواenv -iلعزل العمليات الفرعية. - حارس xtrace: غلّفوا التعليمات البرمجية الحساسة ضمن
{ set +x; } 2>/dev/null ... set -xلمنع تتبعات التصحيح من كشف القيم. - حجب السجلات: استخدموا مسجّلًا قائمًا على
sedكشبكة أمان أخيرة. - tmpfs: خزّنوا أسرار وقت التشغيل في
/run/user/$UIDأو/dev/shmحتى لا تلامس القرص مطلقًا؛ ثم أتلفوها عند الخروج.
الفكرة الأساسية هي الدفاع متعدد الطبقات: لا يكفي أي إجراء منفرد، لكن جمعها معًا يجعل تسرّب الأسرار بالغ الصعوبة.
الأسئلة الشائعة
هل درس «التعامل الآمن مع الأسرار ونظافة البيئة» مجاني؟
نعم — نص درس «التعامل الآمن مع الأسرار ونظافة البيئة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة DevOps Bootcamp، انتقل إلى CoddyKit PRO. تتضمن دورة DevOps Bootcamp 4 دروس في المجموع.
ماذا ستتعلم في «التعامل الآمن مع الأسرار ونظافة البيئة»؟
أبقِ بيانات الاعتماد خارج قوائم العمليات والسجلات باستخدام الإدخال القياسي والملفات والبيئات المنقّحة تتمرن على DevOps Bootcamp مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ DevOps Bootcamp؟
لا تُشترط خبرة سابقة. DevOps Bootcamp على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.
كم من الوقت يستغرق درس «التعامل الآمن مع الأسرار ونظافة البيئة»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس DevOps Bootcamp هذا؟
نعم. كل درس في DevOps Bootcamp يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- منع حقن الأوامر والوسائط
- التعامل الآمن مع الأسرار ونظافة البيئة
- التنفيذ بأقل الصلاحيات والانضباط في استخدام sudo
- التحليل الساكن والتدقيق باستخدام ShellCheck