OpenVPN لا يعثر على ca.crt رغم أن الملف التعريفي يُحمّل
مسار الملف التعريفي ليس هو الأساس للملفات داخله. اكتشف لماذا يفشل --config المطلق مع ca.crt وكيف يحدد أمر التشغيل الجواب.
تبدأ الخدمة، وتقرأ الملف التعريفي دون أي شكوى، ثم تنهار عند سطر يبدو غير ذي صلة: فهي لا تستطيع فتح ca.crt. لم يتغير شيء في الشهادة، ومسار الملف التعريفي في ملف الوحدة مطلق. هذا المزيج هو الدليل. المسار الذي مررته يحدد ملفًا واحدًا، أما الأسماء داخل ذلك الملف فتُحل في مكان آخر تمامًا، لذلك قد يقرأ تشغيل يبدو مؤهلًا بالكامل مفاتيحه من دليل لم يقصده أحد.
للإخفاق عدد قليل من الأسباب، ويستحق فصلها بالترتيب: الدليل الأساسي الذي كان لدى العملية فعليًا، وسياق تشغيل الخدمة، والأذونات أو العزل حول الملف بعد أن يصبح المسار صحيحًا. وكل واحد منها يترك أثرًا مختلفًا، في الوحدة وفي العملية وعلى نظام الملفات.
مسار الملف التعريفي ليس دليلًا أساسيًا
تخيل عملية تبدأ في /tmp ويُسلَّم لها /etc/vpn/prod/tenant-a.ovpn. داخل ذلك الملف التعريفي، يسمي السطر ca ca.crt مسارًا نسبيًا. لا شيء في الوسيط الذي حدد الملف التعريفي يعيد كتابة ذلك الاسم، لذلك تبحث العملية عن /tmp/ca.crt وتُبلّغ عن ملف مفقود.
الجزء المربك هو ترتيب الأخطاء. يقوم OpenVPN بتحليل الإعداد أولًا ويفتح الملفات المشار إليها عند الوصول إليها، لذلك يُبلَّغ عن خطأ مطبعي في الملف التعريفي قبل لمس أي مفتاح، بينما تظهر الشهادة المفقودة فقط عندما يصل التحليل إلى ذلك الحد. لذلك فإن الملف التعريفي الذي يُحمَّل دليل على أن الصياغة سليمة، لا على أن الملفات التي يسميها قد وُجدت.
ما تفصله الدليل: --config و--cd
تشرح دليل OpenVPN 2.6 خيارين متمايزين. أحدهما يحمّل ملف إعداد. والآخر يغيّر دليل العملية قبل قراءة الإعداد والمفتاح والسكربت والملفات الأخرى، ويشترط دليلًا مطلقًا دون أي إشارة إلى الدليل الحالي.
openvpn --cd /etc/vpn/prod --config tenant-a.ovpn
هذا الاستدعاء شكل، وليس تعليمًا لتشغيل ملف تعريف شخص آخر. ما يمنحك إياه هو الحتمية: أساس كل اسم نسبي في السلسلة مذكور في الأمر بدل أن يُورث من أي صدفة أو مدير بدأ العملية. والبديل صالح بالقدر نفسه وغالبًا أفضل لخدمة: اترك دليل العمل كما هو واجعل كل ملف مشار إليه مطلقًا داخل الملف التعريفي.
أيًا كان اختيارك، دقّق السلسلة كلها بدل أول إخفاق. فملف التعريف قد يجذب ملف إعداد آخر، وتُحل الأسماء النسبية في الملف المضمّن مقابل دليل العملية نفسه، لا مقابل دليل الملف الذي ضمّها. ومسارات السجلات وملفات المصادقة والسكربتات المساعدة تتبع القاعدة نفسها.
الخدمة تبدأ في مكان آخر
صدفة تفاعلية في دليل الملف التعريفي لا تثبت شيئًا عن وحدة محزومة. فالمديرون يضبطون دليل عملهم، وقد يغيّره سكربت غلاف مرة أخرى قبل تشغيل الملف الثنائي. والوحدة التي تفشل هي التشغيل الوحيد الجدير بالتحليل.
systemctl show -p WorkingDirectory -p ExecStart --value openvpn@tenant-a
ls -l /proc/$(pgrep -n openvpn)/cwd
يعرض الأمر الثاني الدليل الذي تحتفظ به العملية الحية فعليًا، وهو أوثق من ملف الوحدة عندما يكون هناك غلاف. وإذا اختلف الاثنان، فالغلاف هو جوابك والوحدة توجيه خاطئ.
بعد البحث: الأذونات وchroot والعزل
الدليل الأساسي الصحيح قد ينتج الرسالة نفسها، لأن الحل والوصول خطوتان منفصلتان. تحتاج العملية إلى إذن التنفيذ على كل دليل أب وإذن القراءة على الملف، ووحدة خدمة تحجب جزءًا من نظام الملفات تغيّر ما يمكن للعملية رؤيته أصلًا.
ثلاثة أشكال شائعة تنتج الخطأ نفسه. الملف مقروء للمستخدم الجذر فقط بينما تُسقط الخدمة امتيازاتها قبل فتحه. وتضبط الوحدة منظرًا ملفيًا واقيًا لا يشمل دليل الملف التعريفي. ويعمل البرنامج الخفي داخل chroot، فالمسار الموجود على المضيف غير موجود داخل ذلك المنظر.
شخّص بملكية الملف وهوية العملية، لا بإرخاء الأذونات. فجعل مفتاح خاص مقروءًا للعالم لإسكات هذا الخطأ يقايض إخفاقًا صارخًا بآخر صامت، والمفتاح هو الجزء الذي يقلّ ما ترغب في كشفه من الدليل.
أثبت الإصلاح بالتشغيل المملوك
أعد تشغيل الوحدة الحقيقية من دليل لا صلة له بالملف التعريفي وراقب سطر بدء التشغيل نفسه. ثم تأكد من أن العملية تحتفظ بالدليل المقصود أثناء عملها، وأن الشهادة التي حمّلتها هي التي تتوقعها.
systemctl restart openvpn@tenant-a
systemctl status openvpn@tenant-a --no-pager
journalctl -u openvpn@tenant-a -n 20 --no-pager
عندما ينجح تحميل المسار، تبقى المصادقة والتوجيه مرحلتين منفصلتين لهما إخفاقاتهما، والاتصال الذي يقوم لكنه لا يمرر أي حركة بيانات هو تحقيق مختلف. الإصلاح هنا يتعلق فقط بالدليل الذي جاءت منه الملفات، وينبغي أن يظهر في الاستدعاء بدل أن يتذكره من شغّله يدويًا آخر مرة.
إذا كان الملف التعريفي يُنشر بواسطة مدير إعدادات، فضع الدليل الأساسي أو أسماء الملفات المطلقة هناك أيضًا. فالإصلاح اليدوي على مضيف واحد هو نسخة هذه المشكلة التي تعود بعد إعادة البناء التالية.