كيف تراقب الأوامر التي نفذها المستخدمون على خادمك؟
لا تعتمد على سجل Bash لأنه قابل للتعديل. قارن بين سجلات sudo وتسجيل الجلسات وخطافات الصدفة وقواعد auditd execve، وتعرف على كيفية نقل السجلات خارج الخادم لحمايتها من العبث.
ما الذي يسجل فعلياً الأوامر التي نفذها المستخدمون على خادمك
لمراقبة الأوامر التي نفذها المستخدمون على خادمك، أنت بحاجة إلى سجل لا يمكن للمستخدم تعديله. سجل الأوامر (Shell history) ليس ذلك السجل؛ فهو مجرد ملف للتسهيل، تملكه الحساب الذي أنشأه، ويمكن لأي شخص يكتب داخل تلك الصدفة (shell) إيقاف تشغيله أو حذفه.
هناك أربع طبقات تحفظ سجلاً حقيقياً، ولكل منها تكلفة. يكتب sudo سطراً واحداً لكل أمر في syslog. وتلتقط ميزة تسجيل الإدخال/الإخراج في sudo جلسة كاملة لحساب واحد. بينما يسجل خطاف الصدفة (shell hook) مثل PROMPT_COMMAND ما كتبه مستخدم bash التفاعلي. أما النظام الفرعي للتدقيق في النواة (kernel audit subsystem) فيسجل استدعاء النظام execve نفسه، ولهذا السبب هو الطبقة الوحيدة التي ترى كل عملية (process). يصعد هذا الدليل عبر هذه المستويات، ويوضح أين تتوقف كل طبقة، وينتهي بالجزء الذي يحدد ما إذا كان أي من ذلك ذا قيمة: وهو نقل السجلات خارج الجهاز قبل أن يتمكن الشخص الذي تراقبه من الوصول إليها.
تحذير واحد قبل البدء: النظام الفرعي للتدقيق هو عمل خاص بالنواة، لذا لا يمكن اختبار أي منه داخل حاوية (container) تشارك نواة المضيف. نفذ هذه الأوامر على خادم افتراضي خاص (KVM VPS) حيث تكون النواة تحت سيطرتك.
لماذا لا يُعد سجل الأوامر (shell history) مساراً للتدقيق
يفشل ~/.bash_history كدليل إثبات لأربعة أسباب عادية، ولا يتطلب أي منها مهاجماً ذكياً.
السجل ملك للمستخدم. الملف بوضع الصلاحيات 600 ومملوك للحساب نفسه، لذا لا يحتاج rm ~/.bash_history إلى أي صلاحيات إضافية للوصول إليه. ولا يتطلب الأمر أكثر من فتحه في محرر نصوص وحذف العشرين سطراً المهمة.
يُكتب السجل عند إغلاق الـshell. الجلسة التي تنتهي بـkill -9 $$، أو بسبب انقطاع الاتصال، لا تكتب أي شيء في الملف. تنفيذ history -c قبل exit يؤدي إلى النتيجة ذاتها، ويظهر الأمر وكأن شيئاً لم يحدث.
يمكن إيقافه بكلمة واحدة. يمنع unset HISTFILE كتابة الملف لهذه الجلسة. ويوقف set +o history التسجيل فوراً. ويخفي HISTCONTROL=ignorespace أي أمر يبدأ بمسافة. كل هذه الخيارات موجودة في man bash، لأن الغرض منها هو أن تكون تحت تحكم المستخدم.
يسجل ما كُتب، لا ما نُفذ. وجود alias أو دالة shell يعني أن النص الموجود في الملف ليس بالضرورة البرنامج الذي نفذه الـkernel.
لا توجد طوابع زمنية أيضاً، إلا إذا كان HISTTIMEFORMAT مضبوطاً وقت كتابة الإدخال، لأن bash يكتب أسطر العلامات #1755043200 فقط عند ضبط هذا المتغير.
في حالة تسجيل الدخول المشترك، لا يمكن للسجل تحديد هوية الفاعل. ثلاثة أشخاص يستخدمون حساب deploy واحداً ينتجون ملفاً متداخلاً واحداً تحت معرف مستخدم (uid) واحد. لا يمكن لأي طبقة تسجيل أن تنسب إجراءً إلى إنسان معين عندما يتشارك شخصان في معرف مستخدم واحد، وهذا هو الحجة العملية لـاستخدام حساب واحد غير ذي صلاحيات لكل شخص بدلاً من تسجيل الدخول المشترك.
سجل الـshell جيد في أداء وظيفته الحقيقية، وهي مساعدتك على إعادة كتابة أمر الأمس. استخدمه كدليل استرشادي فقط. ولا تقدمه أبداً كإثبات قاطع.
ما الذي يسجله sudo، وأين يتوقف
يرسل sudo سطراً لكل أمر يقوم بتنفيذه إلى مرفق authpriv syslog.
sudo grep 'sudo:' /var/log/auth.log | tail -5
journalctl -t sudo -n 5يحدد كل سطر المستخدم، والمحطة الطرفية (terminal)، ومجلد العمل، والمستخدم المستهدف، والأمر المنفذ:
sudo: alice : TTY=pts/0 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/apt updateإذا كان /var/log/auth.log غير موجود، فهذا يعني أن rsyslog غير مثبت على تلك الصورة، وتوجد السجلات نفسها في journal فقط. تأكد من أن journal ليس متطايراً (volatile) قبل الاعتماد عليه:
journalctl --list-bootsظهور سجلات الإقلاعة الحالية فقط يعني أن /var/log/journal غير موجود، مما يجعل journal يعيش في /run، وبالتالي يُمحى كل سطر عند إعادة التشغيل التالية. اجعله دائماً:
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journaldالآن، إليك القيد. يسجل sudo الأمر الذي طُلب منه تنفيذه فقط. هو لا يسجل ما يفعله ذلك الأمر لاحقاً. لذا، ينتهي مسار التتبع عند سطر واحد:
sudo -iيحصل السجل على سجل واحد فقط للـ shell. كل أمر يُكتب داخل shell بصلاحيات root يكون غير مرئي لـ sudo، لأن sudo لم يعد في مسار التنفيذ. كل من sudo su -، وsudo bash، وsudo vim /etc/shadow متبوعاً بـ :!bash لها نفس النتيجة. قاعدة sudoers التي تسمح بأي برنامج يحتوي على ميزة shell escape، مثل vim أو find، هي قاعدة تمنح صلاحيات root غير مسجلة. راجع ما يمكن للحساب الوصول إليه فعلياً قبل أن تثق بسطور السجل الخاصة به:
sudo -l -U aliceتسجيل جلسة كاملة لحساب واحد
تحقق أولاً من إصدار sudo الذي تستخدمه، لأن هذه الميزة غير موجودة في إعادة كتابة البرنامج بلغة Rust:
sudo --version | head -1إذا كان المخرج يشير إلى sudo-rs، فتجاوز هذا القسم واستخدم النظام الفرعي audit. توضح وثائق Ubuntu لإصداري 25.10 و26.04 أن تسجيل الإدخال/الإخراج وsudoreplay غير مدعومين، وظل هذا صحيحاً حتى أغسطس 2026. هذا الأمر مهم لأن sudo-rs هو الـsudo الافتراضي في تلك الإصدارات، لذا قد يؤدي الترقية إلى إزالة تحكم كنت تعتقد أنك تمتلكه. قائمة التغييرات الكاملة في سلوك sudo-rs تستحق القراءة قبل التخطيط لأي تسجيل يعتمد على sudo.
باستخدام sudo الأصلي، الذي لا يزال يأتي مع Ubuntu 24.04 LTS، فعّل تسجيل الإدخال/الإخراج لحساب واحد:
sudo visudo -f /etc/sudoers.d/iologDefaults:deploy log_output
Defaults!/usr/bin/sudoreplay !log_outputاستخدم visudo بدلاً من محرر نصوص، لأنه يرفض حفظ الملف إذا كان يحتوي على أخطاء في الصياغة. ملف sudoers تالف سيمنع الجميع من استخدام sudo. بعد ذلك، أعد تشغيل الجلسة:
sudo sudoreplay -l user=deploy
sudo sudoreplay 000001يسرد sudoreplay -l الجلسات مع معرفاتها ولا يطبع شيئاً إذا لم يتم تطبيق log_output على ذلك المستخدم. التكلفة: كل بايت يمر عبر الطرفية يُخزّن تحت /var/log/sudo-io، لذا فإن الجلسة الطويلة ستكون ذات حجم كبير. السطر الثاني في sudoers يمنع إعادة التشغيل من تسجيل نفسها. التكلفة الحقيقية هي الأسرار، لأن سجل الإدخال/الإخراج يحتفظ بكل ما تم كتابته وطباعته، بما في ذلك كلمة المرور التي تُكتب في مطالبة داخل الجلسة، لذا فهو يحتاج إلى نفس حماية مخزن كلمات المرور. التغطية محدودة أيضاً؛ فهي ترى الأوامر التي تُنفذ عبر sudo فقط. الشخص الذي يسجل دخوله ويعمل بالكامل بصفته الشخصية لن يتم تسجيله على الإطلاق.
خطافات الصدفة (Shell hooks)، وكيفية تجاوزها بالضبط
الوصفة المتداولة لـ "تسجيل كل أمر" هي خطاف PROMPT_COMMAND يُوضع في /etc/profile.d/:
# /etc/profile.d/00-cmdlog.sh
PROMPT_COMMAND='logger -p local6.info -t cmdlog "$(whoami) $$ $(history 1 | sed "s/^ *[0-9]* *//")"'يُشغّل bash المتغير PROMPT_COMMAND قبل رسم كل محث (prompt)، لذا يصل السطر إلى syslog فور كتابته بدلاً من انتظاره حتى الخروج، كما يكتب logger عبر خادم سجلات النظام، مما يجعل صلاحيات ملفات المستخدم غير ذات صلة. افتح صدفة تسجيل دخول جديدة وتحقق باستخدام sudo tail -f /var/log/syslog، أو journalctl -t cmdlog -f على صورة لا تحتوي على rsyslog.
ثم يتوقف الأمر عن العمل، وذلك بخمس طرق يمكنك إعادة إنتاج كل منها في دقيقة:
- الصدفات غير التفاعلية لا ترسم محثاً أبداً. يُشغّل
ssh you@server 'id'الأمر ويعود، ولا يتم تسجيل أي شيء، لأنPROMPT_COMMANDلم يتم تقييمه قط. - إنه مجرد متغير. يُعطّله
unset PROMPT_COMMANDلبقية الجلسة ولا يتطلب أي صلاحيات. - الملف يُقرأ بواسطة صدفات تسجيل الدخول فقط. لا يقوم
bash --noprofile --norcباستدعاء/etc/profile.d/مطلقاً. - إنه خاص بـ bash. تُشغّل كل من
zshوshوpython3 -c 'import os; os.system("id")'و:!idداخلvimبرامج لن يراها أي خطاف محث في bash. - هو يسجل السطر كما كُتب، لذا يظل الاسم المستعار (alias) أو الدالة (function) يخفيان الأمر الذي تم تنفيذه فعلياً.
استخدم خطاف الصدفة كوسيلة للراحة. فهو يجيب على سؤال "ما الذي شغلته يوم الثلاثاء الماضي؟" للمستخدمين المتعاونين. لا تسمح لقائمة مراجعة بأن تعتبره وسيلة تحكم.
نظام تدقيق النواة الفرعي يرصد كل عملية execve
يُعد نظام تدقيق Linux الفرعي، الذي يُدار بواسطة الخادم auditd، الطبقة الوحيدة هنا التي لا يمكن للمستخدم تجاوزها، لأن السجل يُنشأ داخل النواة في اللحظة التي يتم فيها تنفيذ نداء النظام (syscall). إذا نفذت أي عملية برنامجاً ما، فسيتم تسجيل حدث بذلك. لا يهم هنا نوع الصدفة (shell) أو لغة البرمجة أو وجود طرفية (terminal).
sudo apt update && sudo apt install -y auditd audispd-plugins
sudo systemctl enable --now auditd
sudo auditctl -sيطبع auditctl -s حالة الخادم. وجود enabled 1 مع قيمة غير صفرية في pid يعني أنه يعمل، وlost 0 تعني أنه لم يتم إسقاط أي سجلات حتى الآن. تذكر عداد lost هذا، فسنعود إليه لاحقاً.
auid هو الحقل الذي يجعل التدقيق يستحق العناء. يقوم PAM بتعيين معرف تسجيل دخول (login uid) عند بدء الجلسة، وتنقله النواة إلى كل عملية فرعية تابعة لها منذ ذلك الحين. تحقق من معرفك:
cat /proc/self/loginuidتطبع جلسة SSH التفاعلية معرف المستخدم الخاص بك، لأن /etc/pam.d/sshd يتضمن pam_loginuid.so. القيمة 4294967295 تعني أن loginuid لم يتم تعيينه أبداً، وهو أمر طبيعي للعمليات التي يبدأها خادم النظام عند الإقلاع. الجزء المهم هو أن sudo -i لا يغير هذا المعرف: صدفة root التي تفتحها alice لا تزال تحمل auid 1000، لذا يمكن نسب كل أمر بداخلها إلى alice. هذه هي الفجوة التي يتركها sudo مفتوحة. يتطلب تغيير loginuid بعد تعيينه صلاحية CAP_AUDIT_CONTROL، التي لا يملكها المستخدمون العاديون، كما يقوم sudo auditctl --loginuid-immutable بإغلاقها أمام root أيضاً حتى إعادة التشغيل التالية.
تأكد من أن /etc/pam.d/sshd و/etc/pam.d/login و/etc/pam.d/cron تتضمن جميعها pam_loginuid.so، وإلا ستصل الأحداث دون ربطها بأي مستخدم. هذه هي نفس قائمة الملفات التي تعدلها عند تأمين وصول SSH على خادم افتراضي، لذا قم بتنفيذ المهمتين معاً.
مجموعة قواعد أولية لـ auditd
توجد القواعد في /etc/audit/rules.d/*.rules. يقوم augenrules بدمجها حسب ترتيب أسماء الملفات في قائمة واحدة، ويحدد الترتيب سلوك النظام لأن النواة تتوقف عند أول قاعدة مطابقة. اقرأ ما هو موجود مسبقاً قبل إضافة أي شيء، لأن وجود -D في ملف لاحق سيؤدي إلى مسح كل ما تم تحميله قبله.
ls /etc/audit/rules.d/
cat /etc/audit/rules.d/audit.rulesثم اكتب /etc/audit/rules.d/50-exec.rules:
## Suppressions first: the kernel takes the first matching rule.
-a never,exit -F arch=b64 -S execve -F exe=/usr/bin/dpkg
-a never,exit -F arch=b64 -S execve -F exe=/usr/bin/dpkg-deb
-a never,exit -F arch=b64 -S execve -F exe=/usr/bin/dpkg-query
-a never,exit -F arch=b64 -S execve -F exe=/usr/bin/dpkg-split
-a never,exit -F arch=b64 -S execve -F exe=/usr/bin/dpkg-trigger
## Every program started by a logged-in human.
-a always,exit -F arch=b64 -S execve,execveat -F auid>=1000 -F auid!=unset -k exec
-a always,exit -F arch=b32 -S execve,execveat -F auid>=1000 -F auid!=unset -k exec
## Changes to who may become root.
-w /etc/sudoers -p wa -k sudoers
-w /etc/sudoers.d/ -p wa -k sudoers
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity
## Changes to the audit configuration itself.
-w /etc/audit/ -p wa -k auditconfigقم بتحميلها وتأكد من ذلك:
sudo augenrules --load
sudo auditctl -lيعني auditctl -l عند طباعة قواعدك أنها أصبحت نشطة. بينما يعني No rules أن التحميل فشل، ويحدد journalctl -u auditd -n 20 الملف والسطر الذي رفضه المحلل. لا تفهم إصدارات مستخدمي audit القديمة الكلمة المفتاحية unset. إذا اشتكى المحمّل من هذا الحقل، اكتب -F auid!=4294967295 بدلاً منه، وهي نفس القيمة مكتوبة بالكامل.
الآن اقرأ الأحداث:
sudo ausearch -k exec -ts recent -i | tail -40
sudo ausearch -ul 1000 -ts today -i
sudo aureport -k --summary -iيقوم -i بتحويل معرفات المستخدمين (uids) وأرقام استدعاءات النظام (syscalls) إلى أسماء، وهو أمر لا غنى عنه عملياً. يغطي -ts recent الدقائق العشر الأخيرة. يصل كل تنفيذ كمجموعة من السجلات: سجل SYSCALL يحمل uid وauid وحالة الخروج والمفتاح، وسجل EXECVE يحتوي على قائمة الوسائط الكاملة، بالإضافة إلى سجلات CWD وPATH للسياق.
هناك قيد واحد صريح، لأنه يباغت المستخدمين. يسجل audit استدعاءات النظام، والأوامر المدمجة في الصدفة (shell builtin) لا تُجري أي استدعاء نظام خاص بها. لا يقوم cd /root بتشغيل أي برنامج. كما أن echo evil >> /etc/passwd عند كتابته في موجه bash لا يشغل أي برنامج أيضاً، لأن كلاً من echo وإعادة التوجيه يحدثان داخل عملية الصدفة التي تعمل بالفعل. لذا ترى قواعد execve البرامج، وترى قواعد -w عمليات الكتابة. لا تكفي أي منهما بمفردها.
أخيراً، قم بتأمين الإعدادات:
## /etc/audit/rules.d/99-finalize.rules
-e 2يجعل -e 2 مجموعة القواعد غير قابلة للتغيير حتى إعادة التشغيل التالية. بعد تحميلها، يبلغ auditctl -s عن enabled 2، وستفشل أي محاولة لإضافة أو حذف قاعدة مع ظهور Operation not permitted، حتى بالنسبة للمستخدم root. أضف هذا الملف أخيراً، وتوقع الحاجة لإعادة التشغيل في كل مرة ترغب فيها بتغيير قاعدة. هذا المقايضة هي الهدف: مجموعة قواعد يمكن لأي شخص إيقافها بهدوء لا تعتبر دليلاً.
سجل التدقيق الذي لا يقرؤه أحد هو مجرد أداة للامتثال
نمط الفشل في auditd ليس في تفويت الأحداث، بل في تسجيل كميات هائلة من البيانات لا يطّلع عليها أحد، ليصبح السجل موجوداً فقط لاستيفاء قائمة تحقق بدلاً من الإجابة على سؤال فعلي.
أجرِ الحسابات على خادمك الخاص قبل تعديل أي إعدادات:
sudo aureport -k --summary -i
sudo du -sh /var/log/auditيقوم sudo apt upgrade واحد بتشغيل آلاف العمليات قصيرة العمر، وكل واحدة منها تحمل معرف المستخدم الخاص بك (auid)، لذا يمكن لتحديث حزمة واحدة أن يطغى على أسبوع كامل من نشاطك البشري. لهذا السبب تستهدف عمليات الحجب أعلاه dpkg ومساعديه. احجب بناءً على الملف التنفيذي، ولا تحجب أبداً بناءً على المستخدم: الاستثناء لـ /usr/bin/dpkg هو ثغرة يمكنك وصفها في جملة واحدة، بينما الاستثناء لحساب مستخدم هو ثغرة مصممة تماماً على شكل الشيء الذي كنت تحاول رصده.
مفتاح -k في كل قاعدة هو ما يجعل السجل قابلاً للبحث بعد شهر من الآن. ausearch -k sudoers هو سؤال له إجابة. أما ausearch بدون مرشح (filter) فهو جدار من النصوص يدربك على التوقف عن القراءة. إذا كان مجمع السجلات الخاص بك يتطلب تنسيق JSON بدلاً من التنسيق الأصلي، فإن laurel هو إضافة لـ auditd تعيد صياغة كل حدث ككائن JSON واحد مع فك ترميز الوسائط. يتم تسجيل الإضافة في /etc/audit/plugins.d/ مثل أي إضافة أخرى، ويقوم auditd برصد تغييرات الإضافات عند sudo pkill -HUP auditd.
تكلفة auditd الحقيقية
يتحول كل استدعاء نظام (syscall) مطابق إلى سجل ينسقه النواة ويسلمه إلى مساحة المستخدم. تظهر التكلفة في مكانين، وكلاهما قابل للقياس على عبء العمل الخاص بك بدلاً من الاعتماد على أرقام منشورة من مصادر أخرى.
- المعالج (CPU) وزمن الاستجابة. الجهاز الذي يقوم بعمليات fork مستمرة، مثل خادم البناء أو بيئة CI، ينتج سجلاً لكل عملية exec. عندما يمتلئ سجل الانتظار (backlog) في النواة، تجعل
--backlog_wait_timeالنواة توقف العملية التي أنشأت الحدث مؤقتاً حتى تتوفر مساحة، لذا يظهر audit كبطء في عمليات البناء بدلاً من كونه نسبة مئوية من استهلاك المعالج. راقبbacklogوlostفيsudo auditctl -sتحت ضغط العمل الفعلي. ارتفاعlostيعني فقدان سجلات، والسجل الذي يحتوي على فجوات صامتة أسوأ من عدم وجود سجل على الإطلاق، لأنك ستستمر في الوثوق به. - القرص. اقرأ
/etc/audit/auditd.confوقرر بوعي ما سيحدث عند امتلاء القرص، لأن القيم الافتراضية هي مجرد آراء. تتحكمmax_log_fileوnum_logsوmax_log_file_actionفي التدوير (rotation). تتحكمspace_left_actionوadmin_space_left_actionوdisk_full_actionفي حالة الطوارئ، وبعض الإجراءات المتاحة، مثلhaltوsingle، تؤدي إلى إيقاف الجهاز بدلاً من فقدان سجل.
السطر -f في /etc/audit/rules.d/audit.rules يمثل نفس القرار على مستوى النواة: تبلغ -f 1 عن فشل audit إلى syslog، بينما تسبب -f 2 توقف النواة (kernel panic). اختر 2 فقط إذا كنت تفضل حقاً فقدان الخادم على فقدان سجل. على خادم افتراضي (VPS) يعتمد عليه المستخدمون، استخدم التدوير بدلاً من ذلك، وانقل مشكلة التخزين خارج الجهاز.
انقل السجلات خارج الخادم في وقت شبه حقيقي
هذا هو الجزء الذي تثبت تقارير الحوادث أهميته باستمرار. السجلات التي تبقى على الخادم المخترق يمكن تعديلها من قبل أي شخص اخترقه. يمكن للمستخدم root إعادة كتابة /var/log/auth.log، وحذف /var/log/audit/audit.log، وإيقاف الخدمة (daemon). يمنع -e 2 إلغاء تحميل القواعد، لكنه لا يفعل شيئاً حيال rm. كل طبقة أعلاه لا تنتج أدلة إلا إذا غادرت نسخة منها الجهاز أولاً.
وسيلة النقل الخاصة بـ Audit هي الملحق audisp-remote من audispd-plugins. فعّله في /etc/audit/plugins.d/au-remote.conf:
active = yes
direction = out
path = /usr/sbin/audisp-remote
type = always
format = stringتحقق من path مقابل command -v audisp-remote قبل إعادة التحميل، لأن المسار الخاطئ لا ينتج شيئاً سوى سطر واحد في السجل (journal). اضبط remote_server وport في /etc/audit/audisp-remote.conf، وعلى جهاز التجميع (collector) اضبط tcp_listen_port = 60 في ملف auditd.conf الخاص به. أعد التحميل باستخدام sudo pkill -HUP auditd. في العديد من صور الأنظمة، يتم رفض systemctl restart auditd لأن ملف الوحدة يضبط RefuseManualStop=yes، لذا فإن إرسال الإشارة هو المسار الموثوق.
الخيار الآخر هو إدراج سجلات audit في تدفق syslog الذي تقوم بإعادة توجيهه بالفعل. يأتي /etc/audit/plugins.d/syslog.conf مع active = no. اضبطه على yes، وأعد التحميل، وستنضم أحداث audit إلى أسطر sudo وكل شيء آخر. بعد ذلك، أعد توجيه الكل باستخدام rsyslog عبر TLS (أمن طبقة النقل)، وهو ما يتطلب حزمة rsyslog-gnutls:
# /etc/rsyslog.d/60-forward.conf
*.* action(type="omfwd"
target="logs.example.net" port="6514" protocol="tcp"
StreamDriver="gtls" StreamDriverMode="1"
StreamDriverAuthMode="x509/name"
StreamDriverPermittedPeers="logs.example.net"
action.resumeRetryCount="-1"
queue.type="linkedList" queue.filename="fwd" queue.saveOnShutdown="on")إعدادات قائمة الانتظار هي الجزء المهم. يقوم action.resumeRetryCount="-1" بإعادة المحاولة إلى الأبد، وتحتفظ قائمة الانتظار المدعومة بالقرص باستخدام queue.saveOnShutdown="on" بالسجلات بينما يكون جهاز التجميع غير قابل للوصول، ثم ترسلها عند عودته للعمل. بدون هذين الإعدادين، سيؤدي إعادة تشغيل جهاز التجميع إلى ترك فجوة في أدلتك دون أي تنبيه بوجودها. طبّق الإعدادات باستخدام sudo systemctl restart rsyslog، ثم تأكد من وصول السجلات فعلياً إلى جهاز التجميع قبل الوثوق بأي منها.
بقيت حلقة واحدة يجب إغلاقها: يجب أن يكون جهاز التجميع جهازاً لا يمكن للأشخاص الخاضعين للتدقيق تسجيل الدخول إليه. إذا كانت مجموعة الإدارة نفسها تمتلك صلاحيات root على خادم السجلات، فقد قمت بنسخ الملف ولم تقم بحمايته. استخدم بيانات اعتماد منفصلة، ومفاتيح منفصلة، ومن الأفضل استخدام حساب مزود خدمة منفصل. هذا هو المنطق نفسه الذي يجعل طريقة مركزية لإدارة العديد من خوادم Linux تستحق البناء قبل الحاجة إليها، وهو الفرق بين ساعة أولى مفيدة وساعة عديمة الفائدة عندما تتعامل مع خادم VPS مخترق.
تحقق من عدم قدرة مستخدم عادي على إعادة كتابة السجل
اختبر الادعاء بدلاً من افتراض صحته. من حساب عادي، بدون صلاحيات sudo:
echo test >> /var/log/auth.log
cat /var/log/audit/audit.log
auditctl -D
id -nGتوقع النتائج التالية بالترتيب: Permission denied، لأن auth.log مملوك لـ syslog مع المجموعة adm والنمط 640؛ و Permission denied مجدداً، لأن سجل التدقيق بنمط 600 ومملوك للمستخدم root؛ وخطأ يرفض التنفيذ، لأن تغيير قواعد التدقيق يتطلب CAP_AUDIT_CONTROL؛ وقائمة مجموعات لا تحتوي على adm ولا systemd-journal.
هذا الفحص الأخير هو ما يخفق فيه الكثيرون. تمنح العضوية في adm صلاحية القراءة لـ /var/log/auth.log، وتمنح العضوية في systemd-journal صلاحية القراءة للسجل بالكامل. لا تمنح أي منهما صلاحية الكتابة، لذا لا تسمح أي منهما بالتلاعب. كلاهما يسمح للشخص بقراءة كل سطر مصادقة على الجهاز، وهو قرار يجب اتخاذه عن قصد بدلاً من نسخ سطر usermod -aG من إجابة في منتدى.
أخيراً، تأكد من الأمرين اللذين يجب أن يستمرّا بعد إعادة التشغيل:
sudo auditctl -s
systemctl is-enabled auditdتعني enabled 2 أن مجموعة القواعد مقفلة حتى الإقلاع التالي. تعني enabled من الأمر الثاني أن auditd يبدأ العمل مجدداً بعد ذلك الإقلاع. مجموعة القواعد التي تستمر فقط حتى تحديث النواة التالي لا تُعتبر مسار تدقيق.
FAQ
كيف يمكنني رؤية كل أمر نفذه مستخدم معين؟
اعثر على معرف المستخدم (uid) الخاص به باستخدام id -u alice، ثم ابحث في سجل التدقيق (audit log) حسب معرف تسجيل الدخول: sudo ausearch -ul 1000 -ts today -i. أضف -k exec لقصر النتائج على قاعدة execve. يتم تعيين معرف تسجيل الدخول عند الدخول ويبقى ثابتاً عبر su وsudo -i، لذا يلتقط هذا الأمر الأوامر المنفذة داخل shell بصلاحيات root التي فتحها ذلك الحساب. يعمل هذا فقط مع الأوامر التي نُفذت بعد تحميل القواعد، لأن audit لا يحتفظ بسجل للأحداث التي لم يُضبط لتسجيلها. يمنحك sudo aureport -k --summary -i أعداد الأحداث لكل قاعدة إذا أردت رؤية هيكل البيانات أولاً.
هل يمكن للمستخدم حذف سجل bash الخاص به لإخفاء ما نفذه؟
نعم، ولا يتطلب ذلك أي صلاحيات. يمتلك المستخدم ملف ~/.bash_history بصلاحيات 600، لذا يمكنه تعديله أو تقليصه أو حذفه. يمكنه أيضاً منع الكتابة فيه باستخدام unset HISTFILE، أو إيقاف التسجيل في منتصف الجلسة باستخدام set +o history، أو إخفاء أوامر فردية بكتابتها مسبوقة بمسافة عند ضبط HISTCONTROL=ignorespace. يكتب Bash الملف عند خروج الـshell، لذا فإن الجلسة التي تُنهى بـkill -9 $$ لا تسجل شيئاً. تعامل مع سجل الـshell كإشارة استدلالية، وليس كدليل قاطع.
هل يسجل sudo ما يحدث داخل sudo -i؟
لا. يسجل sudo الأمر الذي طُلب منه تنفيذه، لذا ينتج sudo -i سطراً واحداً للـshell ولا شيء بعده. كل أمر يُكتب داخل shell بصلاحيات root يكون غير مرئي لـsudo، لأن sudo لم يعد مشاركاً في العملية. تتصرف sudo su - وsudo bash وأي برنامج مسموح به يحتوي على shell escape بنفس الطريقة. هناك أمران يسدان هذه الفجوة: قواعد audit على execve، والتي تسجل كل برنامج مع إرفاق معرف تسجيل الدخول الأصلي، وقواعد sudoers التي لا تمنح صلاحية الوصول إلى shell في المقام الأول.
هل سيؤدي auditd إلى إبطاء الخادم؟
يعتمد الأمر كلياً على عدد العمليات التي يبدأها حمل العمل الخاص بك، لذا قم بقياسه بدلاً من الوثوق برقم محدد. الخادم الذي يجيب على الطلبات في الغالب ينفذ عمليات قليلة جداً ولن يلاحظ فرقاً. أما خادم البناء (build host) أو مشغل CI فينفذ عمليات باستمرار وقد يلاحظ تأثيراً كبيراً، لأنه عندما يمتلئ backlog الخاص بـaudit في النواة، تتوقف العملية التي أنشأت الحدث مؤقتاً حتى تتوفر مساحة. شغّل sudo auditctl -s تحت حمل عمل حقيقي وراقب backlog وlost. أي قيمة لـlost أكبر من صفر تعني أنه تم إسقاط سجلات، وهي أسوأ نتيجة ممكنة، لأن السجل سيحتوي حينها على فجوات غير مرئية.
أين يجب تخزين سجلات التدقيق؟
على جهاز آخر، مع تأخير يُقاس بالثواني. يمكن لأي شخص يصل إلى صلاحيات root على الخادم الخاضع للتدقيق حذف /var/log/audit/audit.log وإعادة كتابة /var/log/auth.log، لذا فإن النسخ المحلية تجيب فقط على الأسئلة المتعلقة بالحوادث التي لم يحاول أحد إخفاءها. قم بإعادة التوجيه باستخدام إضافة audisp-remote إلى خادم auditd مركزي، أو فعّل إضافة audit syslog وأعد توجيه تدفق syslog بالكامل باستخدام rsyslog عبر TLS. امنح الجامع (collector) بيانات اعتماد خاصة به، وتأكد من أن الحسابات التي تخضع للتدقيق لا تملك أي وصول إليه.