أساسيات لينكس

مشروع: إعداد بيئة مستخدمين على خادم لينوكس

35 دقيقة الدرس 10 من 26

مشروع: إعداد بيئة مستخدمين على خادم لينوكس

يجمع هذا المشروع الختامي كل ما تعلمته في هذا التعليمي: إدارة المستخدمين، والمجموعات، والصلاحيات، ونظام الملفات، وضبط الصدفة البرمجية، وإدارة الحزم، ومتغيرات البيئة. ستُهيئ خادم Ubuntu 24.04 جديداً لفريق هندسي صغير من أربعة أدوار — مطورة تطبيقات، ومهندس عمليات، وحساب خدمة CI/CD، ومدقق امتثال — لكل منهم صلاحيات محددة بدقة وبيئة صدفة منتجة. هذا هو بالضبط النوع من المهام التي ستكررها على كل خادم جديد، وكل VM سحابي، وكل سكريبت إقلاع لعقدة Kubernetes تكتبه على نطاق واسع.

سيناريو المشروع: يعمل فريقك على نشر واجهة برمجية Node.js على خادم لينوكس مباشر. أربعة مستخدمين يحتاجون إلى وصول: alice (مطورة)، وbob (مهندس عمليات)، وsvc-deploy (بوت CI/CD — بدون تسجيل دخول تفاعلي)، وauditor (مراجع امتثال بصلاحية قراءة فقط). ستُنشئ المستخدمين، والمجموعات، وهيكل المجلدات، والصلاحيات، وقواعد sudoers، وملفات تعريف الصدفة، وتأمين SSH في سكريبت واحد قابل للتكرار.

الخطوة 1 — أنشئ المجموعات أولاً

المجموعات هي الآلية الأساسية للتحكم في الوصول. أنشئ المجموعات دائماً قبل المستخدمين حتى تتمكن من تعيين المجموعتين الأساسية والإضافية عند إنشاء المستخدم. ثلاث مجموعات تغطي السيناريو: developers وops وauditors.

# تشغيله كـ root أو باستخدام sudo sudo groupadd --gid 2001 developers sudo groupadd --gid 2002 ops sudo groupadd --gid 2003 auditors # التحقق getent group developers ops auditors

تثبيت GIDs بأرقام محددة هو عادة إنتاجية. على أجهزة VM السحابية التي تُعاد بناؤها بشكل متكرر، يمكن أن تتغير GIDs الديناميكية بين البنيات، مما يُعطل ملكية الملفات على وحدات تخزين NFS المشتركة أو أقراص EBS الثابتة. ثبّت GIDs فوق 2000 للابتعاد عن نطاق حسابات النظام (0-999) ونطاق التخصيص الديناميكي (1000-1999).

الخطوة 2 — أنشئ المستخدمين بصدفات مقيّدة

كل مستخدم يحصل على الحد الأدنى من الإعداد المطلوب لدوره. حساب خدمة CI/CD المسمى svc-deploy لا يحتاج قط إلى صدفة تفاعلية — تقييده بـ /usr/sbin/nologin يمنع أي تسجيل دخول تفاعلي عرضي أو ضار مع الإبقاء على إمكانية تنفيذ الأوامر عبر SSH باستخدام ForceCommand (مغطى في الخطوة 6).

# alice — مطورة، تسجيل دخول تفاعلي، مجلد منزلي sudo useradd \ --uid 2101 \ --gid developers \ --groups auditors \ --create-home \ --shell /bin/bash \ --comment "Alice — Backend Developer" \ alice # bob — عمليات، تسجيل دخول تفاعلي، عضو في developers أيضاً sudo useradd \ --uid 2102 \ --gid ops \ --groups developers \ --create-home \ --shell /bin/bash \ --comment "Bob — Platform Ops" \ bob # svc-deploy — بوت CI/CD، بدون تسجيل دخول تفاعلي، لا يحتاج مجلداً منزلياً sudo useradd \ --uid 2103 \ --gid ops \ --no-create-home \ --shell /usr/sbin/nologin \ --comment "CI/CD deployment service account" \ svc-deploy # auditor — مراجع بصلاحية قراءة، تفاعلي لكن مقيّد sudo useradd \ --uid 2104 \ --gid auditors \ --create-home \ --shell /bin/bash \ --comment "Auditor — Compliance" \ auditor # قفل المصادقة بكلمة المرور لجميع الحسابات — مفاتيح SSH فقط sudo passwd --lock alice sudo passwd --lock bob sudo passwd --lock auditor sudo passwd --lock svc-deploy # التأكيد getent passwd alice bob svc-deploy auditor
الممارسة الإنتاجية: عطّل مصادقة كلمة المرور لجميع حسابات الخدمة والمستخدمين البشريين على الخوادم. فرض مصادقة مفتاح SSH في /etc/ssh/sshd_config (عبر PasswordAuthentication no) وأدر المفاتيح العامة عبر مدير الأسرار أو أدوات إدارة الضبط (Ansible أو Puppet أو Chef). لا تُوزع كلمات مرور مشتركة عبر المحادثات.

الخطوة 3 — بناء شجرة مجلدات التطبيق

هيكل المجلدات المدروس يجعل إدارة الصلاحيات لا لبس فيها. الاصطلاح أدناه يفصل كود التطبيق الثابت عن بيانات وقت التشغيل، ويفصل السجلات عن الأسرار، ويضمن أن حساب CI/CD يمكنه النشر دون لمس الأسرار أو السجلات المملوكة لمستخدم وقت التشغيل.

# جذر التطبيق — مملوك لـ root، قابل للقراءة من ops و developers sudo mkdir -p /opt/nodeapp/{releases,current,shared/{config,logs,tmp}} # تعيين ملكية المجلدات sudo chown -R root:ops /opt/nodeapp sudo chown -R root:developers /opt/nodeapp/releases sudo chown -R bob:ops /opt/nodeapp/shared/logs # نموذج الصلاحيات: # /opt/nodeapp root:ops 750 — ops يمكنه التنقل، الآخرون لا # releases/ root:devs 755 — المطورون يقرؤون/يسردون الإصدارات # shared/config root:ops 750 — الأسرار قابلة للقراءة من مجموعة ops فقط # shared/logs bob:ops 775 — مجموعة ops تكتب السجلات # shared/tmp root:ops 1777 — tmp بـ sticky-bit داخل شجرة التطبيق sudo chmod 750 /opt/nodeapp sudo chmod 755 /opt/nodeapp/releases sudo chmod 750 /opt/nodeapp/shared/config sudo chmod 775 /opt/nodeapp/shared/logs sudo chmod 1777 /opt/nodeapp/shared/tmp # المدقق يحتاج وصولاً للقراءة فقط للسجلات — استخدم ACLs (يتطلب حزمة acl) sudo apt-get install -y acl sudo setfacl -Rm u:auditor:r-x /opt/nodeapp/shared/logs sudo setfacl -dm u:auditor:r-x /opt/nodeapp/shared/logs # افتراضي — يُطبق على الملفات الجديدة # التحقق من ACLs getfacl /opt/nodeapp/shared/logs

قوائم التحكم في الوصول POSIX هي الأداة الصحيحة حين تحتاج منح وصول لمستخدم لا يشترك في مجموعة مع مالك المجلد. بدلاً من إضافة auditor إلى مجموعة ops (مما سيمنحه صلاحية الكتابة)، يمنح إدخال setfacl المحدد وصولاً للقراءة فقط. هكذا تمنح فرق العمليات الكبيرة فرق الامتثال وصولاً للسجلات دون توسيع نطاق الضرر المحتمل.

Team Access Layout: Users, Groups and Directory Permissions Users Groups Directories / ACL alice bob svc-deploy auditor developers ops auditors releases/ root:developers 755 shared/config root:ops 750 shared/logs bob:ops 775 shared/logs + ACL auditor:r-x shared/tmp root:ops 1777 Primary group Supplementary group
تخطيط صلاحيات الفريق: كل مستخدم، وعضوياته في المجموعات، ونموذج ACL للمجلدات التي تنطبق عليه.

الخطوة 4 — ضبط sudoers بمبدأ الحد الأدنى من الصلاحيات

لا تُضف المستخدمين إلى مجموعة sudo بشكل شامل. استخدم ملفات sudoers المنفصلة تحت /etc/sudoers.d/ لمنح الأوامر التي يحتاجها كل دور فعلاً. هذا هو الفرق بين "منحت alice صلاحية sudo" و"alice تستطيع فقط إعادة تشغيل خدمة التطبيق وقراءة سجلات nginx — لا شيء غير ذلك."

# /etc/sudoers.d/ops — bob ومجموعة ops يحصلان على sudo واسع مع تسجيل # استخدم دائماً visudo أو الكتابة الذرية، وليس vi العادي sudo tee /etc/sudoers.d/ops <<'EOF' # مجموعة Ops: sudo كامل مع تأكيد كلمة المرور %ops ALL=(ALL:ALL) ALL EOF # /etc/sudoers.d/svc-deploy — حساب CI/CD: سكريبت النشر فقط، NOPASSWD sudo tee /etc/sudoers.d/svc-deploy <<'EOF' # بوت CI/CD: تنفيذ بدون كلمة مرور لسكريبت النشر فقط svc-deploy ALL=(root) NOPASSWD: /opt/nodeapp/bin/deploy.sh EOF # /etc/sudoers.d/developers — إعادة تشغيل الخدمة فقط sudo tee /etc/sudoers.d/developers <<'EOF' # المطورون يستطيعون إعادة تشغيل خدمة التطبيق وعرض آخر سجلاتها فقط %developers ALL=(root) NOPASSWD: /bin/systemctl restart nodeapp, \ /usr/bin/journalctl -u nodeapp -n 200 EOF # تقييد صلاحيات sudoers.d — مطلوب لكي يُطبّقها sudo sudo chmod 440 /etc/sudoers.d/ops /etc/sudoers.d/svc-deploy /etc/sudoers.d/developers # التحقق من الصياغة قبل التطبيق sudo visudo --check --file=/etc/sudoers.d/ops
مزلق إنتاجي: الملفات في /etc/sudoers.d/ يجب أن تكون مملوكة لـ root وبصلاحية 0440. صلاحية 0644 أو إمكانية الكتابة للجميع تجعل sudo يتجاهل الملف بأكمله بصمت في معظم التوزيعات. بعد أي تغيير، نفّذ sudo visudo --check للكشف عن أخطاء الصياغة قبل أن تحجب وصولك المميز.

الخطوة 5 — توزيع مفاتيح SSH العامة

وزّع مفاتيح SSH العامة برمجياً، وليس بالنسخ واللصق اليدوي. يجب أن يكون ملف authorized_keys في ~/.ssh/authorized_keys مع ملكية وصلاحيات صارمة. أي انحراف يجعل sshd يرفض المفتاح بصمت.

# دالة مساعدة — قابلة للاستخدام في سكريبت الإقلاع install_ssh_key() { local user="$1" local pubkey="$2" local home home=$(getent passwd "$user" | cut -d: -f6) install -d -m 700 -o "$user" -g "$user" "${home}/.ssh" echo "$pubkey" >> "${home}/.ssh/authorized_keys" chmod 600 "${home}/.ssh/authorized_keys" chown "$user":"$user" "${home}/.ssh/authorized_keys" } # استدعاء مع المفتاح العام لكل مستخدم (مجلوب من مدير الأسرار أو vault) install_ssh_key alice "ssh-ed25519 AAAA...alice_key alice@laptop" install_ssh_key bob "ssh-ed25519 AAAA...bob_key bob@workstation" install_ssh_key auditor "ssh-ed25519 AAAA...auditor_key auditor@audit-host" # مفتاح svc-deploy: تقييده بأمر واحد حتى على مستوى SSH # أضف بادئة لأمر مفروض في authorized_keys sudo -u svc-deploy tee /home/svc-deploy/.ssh/authorized_keys <<'KEYS' command="/opt/nodeapp/bin/deploy.sh",no-pty,no-agent-forwarding ssh-ed25519 AAAA...ci_key ci@github-actions KEYS

الخطوة 6 — تأمين sshd وتطبيق ملفات تعريف الصدفة

ضع مقتطف إعداد في /etc/ssh/sshd_config.d/ (يتضمن Ubuntu 24.04 هذا المجلد افتراضياً). هذا يتجنب تعديل الملف الأساسي ويجعل تغيير التأمين قابلاً للمراجعة في git.

sudo tee /etc/ssh/sshd_config.d/99-team-hardening.conf <<'EOF' # تعطيل كل مصادقة بكلمة المرور — المفاتيح فقط PasswordAuthentication no KbdInteractiveAuthentication no PermitRootLogin no # السماح فقط للأربعة مستخدمين ومجموعة ops AllowUsers alice bob auditor svc-deploy AllowGroups ops developers auditors # مهلة قصيرة للخمول — قطع الاتصال بالجلسات الخاملة بعد 10 دقائق ClientAliveInterval 300 ClientAliveCountMax 2 # تسجيل كل تسجيل دخول بمستوى verbose للمدقق LogLevel VERBOSE EOF # التحقق من الإعداد قبل إعادة التحميل — إذا فشل هذا، لا تُعد التحميل sudo sshd -t && sudo systemctl reload ssh # إعداد مقتطف .bashrc مشترك للمطورين sudo tee /etc/profile.d/nodeapp-env.sh <<'EOF' # بيئة مشتركة لجميع الجلسات التفاعلية على هذا الخادم export APP_ENV=production export APP_ROOT=/opt/nodeapp/current export PATH="$APP_ROOT/bin:$PATH" # موجّه ملوّن مع اسم المضيف وفرع git PS1='\[\e[1;32m\]\u@\h\[\e[0m\]:\[\e[1;34m\]\w\[\e[0m\]$(git branch 2>/dev/null | grep -o "* .*" | sed "s/* / /")\$ ' EOF

الخطوة 7 — التحقق من الإعداد الكامل

لا تثق قط في سكريبت الإعداد الخاص بك دون التحقق من النتائج. نفّذ هذه الفحوصات وقارنها بالمخرجات المتوقعة قبل تسليم الخادم للفريق.

# 1. تأكيد وجود جميع المستخدمين ولديهم الصدفات الصحيحة getent passwd alice bob svc-deploy auditor # 2. تأكيد عضويات المجموعات for u in alice bob svc-deploy auditor; do echo "--- $u ---" id "$u" done # 3. التحقق من مطابقة صلاحيات المجلدات للنموذج stat -c "%a %U:%G %n" /opt/nodeapp \ /opt/nodeapp/releases \ /opt/nodeapp/shared/config \ /opt/nodeapp/shared/logs \ /opt/nodeapp/shared/tmp # 4. فحص ACLs على مجلد السجلات getfacl /opt/nodeapp/shared/logs # 5. التحقق من صياغة sudoers sudo visudo --check # 6. اختبار تصعيد الصلاحيات كـ alice (يجب أن ينجح للأمرين المسموح بهما) sudo -u alice sudo -n /bin/systemctl restart nodeapp 2>&1 # 7. اختبار عدم قدرة auditor على الكتابة في السجلات (يجب أن يفشل) sudo -u auditor touch /opt/nodeapp/shared/logs/test.txt 2>&1 # 8. التأكيد من صحة إعداد sshd sudo sshd -t && echo "sshd config OK"
الممارسة الاحترافية: اجمع كل هذه الخطوات في سكريبت shell ذا طبيعة idempotent (أو الأفضل، playbook Ansible). Idempotent تعني أن تشغيله مرة ثانية لا ينتج تغييرات ولا أخطاء. هذا هو أساس الإعداد كرمز برمجي: كل خادم في أسطولك يجب أن يكون متطابقاً بشكل مُثبَت لأنها جميعها بُنيت من نفس السكريبت، لا لأن أحداً دخل عبر SSH وكتب الأوامر الصحيحة على كل واحد منها.

ما الذي بنيته

في نهاية هذا المشروع لديك بيئة لينوكس مؤمّنة ومناسبة للأدوار تعكس كيف تدير فرق العمل السحابية الأصيلة وصول الخادم فعلياً. القرارات الجوهرية التي اتخذتها — والمنطق وراءها — هي نفس القرارات التي ستتخذها على نطاق واسع:

  • UIDs/GIDs مثبّتة تضمن ملكية متسقة عبر أجهزة VM المُعاد بناؤها والتخزين المشترك.
  • كلمات مرور مقفلة مع مصادقة بمفتاح SSH فقط تُزيل ناقلات هجوم حشو بيانات الاعتماد والقوة الغاشمة.
  • قواعد sudoers بأدنى الصلاحيات تُقيّد نطاق الضرر في حالة اختراق حساب.
  • قوائم تحكم POSIX ACLs تمنح وصولاً متقاطعاً بين المجموعات دون توسيع العضوية وصلاحيات الكتابة غير المقصودة.
  • ملف إعداد sshd منفصل يجعل التأمين قابلاً للتدقيق وللتحكم في الإصدارات بدلاً من دفنه في ملف إعداد ضخم.
  • فحوصات التحقق تحوّل الإعداد إلى أثر قابل للاختبار — الخطوة الأخيرة في كل تغيير بنية تحتية حقيقي.

هذا النمط يتوسع من VM واحد إلى playbook Ansible يدير عشرة آلاف عقدة. قد تتغير صياغة الأوامر؛ التفكير لا يتغير.