منح OpenVPN صلاحية CAP_NET_ADMIN دون منحه صلاحيات الجذر
الوحدة التي تبدأ بمستخدم غير مميّز ما زالت بحاجة إلى مجموعة الصلاحيات الصحيحة. افحص الوحدة، والعملية الحيّة، وحدّ التنفيذ، بهذا الترتيب.
تبدأ الخدمة، ويشكو السجل من أنه لا يستطيع فتح جهاز tun، ولا تظهر المسارات أبدًا. نفّذ capsh --print من الصدفة لديك وستجد cap_net_admin حاضرًا، ما يجعل الفشل يبدو مستحيلًا. ما يختلف بين صدفتك والوحدة هو انتقال الامتيازات، وليس استعداد النواة لمنح الصلاحية. اعمل على الفحوص الأربعة أدناه بالترتيب وتوقّف عند أول فحص يفسّر الفجوة.
افصل بين صلاحية مفقودة وجهاز مخفي
فشلان يبدوان متشابهين من سطر السجل. العملية التي تفتقر إلى CAP_NET_ADMIN لا تستطيع إنشاء واجهة النفق أو تهيئتها، والعملية التي يخفي صندوقها الرملي /dev/net/tun لا تستطيع فتحه من الأصل. وإضافة صلاحيات لن تصلح الحالة الثانية.
تحقّق من وجود الجهاز داخل نطاق أسماء الخدمة قبل أن تعدّل أي شيء. PrivateDevices=yes سطر تقوية شائع يزيل عقدة tun بالكامل، و ProtectSystem المقيّد يمكن أن يجعل مسار الإعداد للقراءة فقط بطريقة تُقرأ كخطأ في الأذونات. كلاهما ينتج أسطر سجل تذكر النفق، ولهذا تُلام الصلاحيات عليها. تأكّد أولًا من أن العقدة موجودة وقابلة للفتح، ثم انتقل إلى ما بعدها.
اعرف مجموعة الصلاحيات التي تنظر إليها
يحتفظ Linux بمجموعات مسموحة وفعّالة وقابلة للتوريث ومحدودة ومحيطية، والمجموعة المحيطية هي التي تنجو من تنفيذ exec لمستخدم غير جذر. صلاحيات الملف على الملف التنفيذي يمكن أن تنقل حقوقًا مسموحة وفعّالة عند exec، لكن فقط ما دام لا شيء في السلسلة يمنع ذلك النقل.
هنا يضلّل sudo الناس. الأمر الذي يُنفّذ عبر sudo -u يبدأ انتقال امتيازات جديدًا وتختفي المجموعة المحيطية، لذا يفشل هناك نفس الفحص الذي ينجح بصفة الجذر. ومدير الخدمات انتقال آخر مرة أخرى، وهو لا يمنح شيئًا محيطيًا ما لم تقل الوحدة ذلك.
امنح الصلاحية في الوحدة، لا في غلاف
قسم خدمة أدنى لنفق يحتاج إلى إنشاء جهاز وتثبيت مسارات يبدو هكذا.
[Unit]
Description=OpenVPN client, office profile
After=network-online.target
[Service]
Type=notify
User=openvpn
Group=openvpn
NoNewPrivileges=yes
AmbientCapabilities=CAP_NET_ADMIN
CapabilityBoundingSet=CAP_NET_ADMIN
ExecStart=/usr/sbin/openvpn --config /etc/openvpn/office.confAmbientCapabilities يضع الحق في المجموعة المحيطية قبل بدء العملية، و CapabilityBoundingSet يمنع العملية من حمل أي شيء خارج تلك القائمة. NoNewPrivileges=yes يمنع كسب الامتيازات عبر setuid أو صلاحيات الملف، بينما الصلاحية التي تمنحها الوحدة صراحةً تظل سارية. أضف CAP_NET_BIND_SERVICE فقط عندما يجب على الخدمة ربط منفذ منخفض، ولا تضف CAP_SYS_ADMIN أبدًا لأن موضوعًا في منتدى فعل ذلك.
إذا كانت الوحدة تغلّف الملف التنفيذي بـ sudo، فأزل الغلاف. systemd يطبّق User= بالفعل، وتلك الطبقة الإضافية هي السبب الأرجح لكون المجموعة المحيطية فارغة.
تحقّق مقابل العملية الحيّة، لا ملف الوحدة
اقرأ ما طبّقه المدير فعلًا، ثم اقرأ العملية التي أنشأها.
unit=openvpn-client@office
systemctl show -p User -p AmbientCapabilities "$unit"
systemctl show -p MainPID --value "$unit" | xargs -r getpcaps
grep -E '^Cap(Eff|Amb)' /proc/$(systemctl show -p MainPID --value "$unit")/statusإذا كانت الوحدة تسرد الصلاحية وظل CapEff يفتقر إليها، فملف drop-in يتجاوز الإعداد أو خطوة ExecStartPre تغيّر البيئة. ابحث في أدلة drop-in عن اسم الوحدة قبل أن تفترض أن الملف الرئيسي هو المرجع، لأن ملفًا لاحقًا يفوز بصمت. إذا أظهرت الوحدة والعملية معًا الصلاحية وظل النفق يفشل، فارجع إلى فحوص الجهاز والمسار بدلًا من توسيع المجموعة المحدودة. توسيعها يخفي السبب الحقيقي ويترك الخدمة أكثر امتيازًا مما كانت.
فضّل إسقاط الامتيازات بعد بدء التشغيل
OpenVPN يمكن أن يبدأ بامتيازات ثم ينتقل إلى حساب غير مميّز عبر خياري user و group الخاصين به، مع إبقاء persist-key و persist-tun النفق صالحًا للاستخدام بعد ذلك. هذا الترتيب يضيّق النافذة التي تحمل فيها العملية حقوقًا، وغالبًا ما يكون أنسب من بدء الخدمة الخفية كلها غير مميّزة بصلاحيات دائمة.
أي نموذج تختار، أعد تشغيل الوحدة وكرّر الفحوص بعد إعادة الإقلاع، لأن خدمة تعمل من صدفة جذر تفاعلية وتفشل عند الإقلاع هي عادةً فرق في الصلاحية أو الجهاز أو أذونات الملف. سجّل إعدادات الوحدة بجوار مخرجات صلاحيات العملية حتى يرى المراجع التالي ما إذا كان تحديث حزمة أو ملف drop-in قد حرّك الحدّ.