السماح باتصال تمرير TLS في سياق stream في NGINX
يستطيع NGINX رفض تمرير TCP TLS من دون إنهاء TLS. ضع قاعدة السماح في stream لا في location داخل HTTP، وتحقق من عنوان الطرف الذي يصل.
تمرير بايتات مشفرة من دون الاحتفاظ بالشهادة أبدا هو ما يفعله مرحل تمرير TLS، والترتيب مريح ومربك قليلا في الوقت نفسه. ولأن لا شيء يفك التشفير، لا يوجد أي شكل HTTP لتصفيته، لذا لا قيمة هنا لكتلة location المعتادة وقواعد الوصول التابعة لها. القرار المتاح لNGINX يتعلق بالاتصال نفسه: أي طرف شبكي طرق الباب، وهل ينبغي تمرير ذلك الطرف أصلا.
القرار مكانه stream لا HTTP
في سياق stream يعمل NGINX مع جلسات TCP. يرى عنوان الطرف المتصل ويستطيع تطبيق قواعد allow و deny مرتبة عليه قبل أن تصل أي بايتات إلى backend. هذا قرار قبول كامل ولا يحتاج مفتاحا خاصا ولا شهادة ولا تحليلا لHTTP.
| Mechanism | What it decides | Where it lives |
|---|---|---|
| stream allow/deny | Whether this TCP peer is relayed | stream server block |
| ssl_preread map | Which backend a named connection goes to | stream, with the preread module |
| HTTP location rule | Whether an HTTP request is served | http server block |
تلك الصفوف الثلاثة لا تحل محل بعضها أبدا. نسخ توجيه وصول HTTP إلى الملف الذي يذكر المنفذ 443 لا يغير شيئا، لأن خادم stream لا يقرأ سياق http أبدا.
اسمح بالاتصال قبل تمريره
افترض تثبيتا قائما تتوفر فيه وحدتا stream و stream-access، وعملاء VPN يحفظون عناوين المصدر في 10.90.0.0/24، وbackend عند 192.168.50.20:443 يقدم بالفعل هوية HTTPS المقصودة.
stream {
server {
listen 443;
allow 10.90.0.0/24;
deny all;
proxy_pass 192.168.50.20:443;
}
}
اقرأ ذلك كمقتطف مستمع جديد لا كبديل مباشر لتكوين عامل. راجع المستمعين و includes الموجودة أولا، لأن مستمعا ثانيا على منفذ مرتبط بالفعل يفشل عند reload لا عند وقت الطلب.
لاحظ ما هو غائب: لا listen ... ssl ولا توجيه شهادة. يمرر NGINX التدفق المشفر، وينهي backend بروتوكول TLS ويعرض الشهادة التي يتحقق منها العميل. العميل الذي يفشل في قائمة السماح تُرفض جلسة TCP الخاصة به، لا صفحة HTTP 403، وأي أداة تتوقع رمز حالة ستظهر شيئا غير مفيد.
ما تغطيه قائمة السماح وما لا تغطيه
إذا كان المرحل يختار backends باسم الخادم بالفعل، فيمكن لssl_preread و map مواصلة ذلك العمل بشرط توفر الوحدة. الاسم ما زال يقدمه العميل، ولا شيء في تقديم اسم يثبت أن العميل انضم إلى VPN.
قاعدة المثال تغطي مستمع stream بالكامل. وهذا يجعلها غير مناسبة لنقطة دخول واحدة تخدم خليطا من مواقع عامة ومواقع VPN فقط، حيث يلزم استثناء لكل اسم؛ والمستمعون المنفصلون أوضح عادة من سياسة تعتمد على الاسم لا يستطيع أحد قراءتها.
هناك ثغرتان أخريان تستحقان الذكر. مطابقة البادئة لا تقول شيئا عن الواجهة التي وصلت منها الحزمة، وقاعدة HTTP في مكان آخر لا يمكنها تقييد هذا المستمع. كلاهما سبب لإبقاء سياسة الدخول على مستوى المضيف في الصورة بدلا من اعتبار سطر allow واحدا هو الحد بأكمله. اكتب الحد كعنصر تحكمين يجب أن يتفقا، حتى تتم مراجعة أي تغيير في أحدهما.
أي عنوان يرى NGINX فعلا؟
يمكن لموازن حمل أو وكيل آخر أو NAT المصدر وضع وسيط أمام NGINX، لذا فالطرف الذي يراه ليس عنوان العميل الداخلي لVPN. افحص المسار الحقيقي قبل اختيار بادئة، لأن قائمة سماح مكتوبة لعنوان خاطئ إما تسمح لكل من خلف المترجم أو لا تسمح لأحد.
بروتوكول PROXY ومعالجة IP الحقيقي إجابتان مشروعتان، ويجب إعدادهما فقط لمرسلين متوافقين وموثوقين صراحة. كلتا الآليتين تصدقان ما يقوله المرسل، وهذا تحديدا سبب وجوب أن تكون قائمة المرسلين قصيرة. الثقة في ترويسة هوية من أي عميل إنترنت لا تعيد جعل معلومات المصدر موثوقة؛ بل تحول رفضا صحيحا إلى قبول مزور.
اختبر النتيجتين قبل reload
تحقق من التكوين، ثم reload، ثم اختبر مرتين: جلسة جديدة مسموح بها يجب أن تعمل، وأخرى مرفوضة يجب ألا تعمل. أبق تحقق شهادة backend العادي في الاختبار المسموح، لأن مرحلا يتصل لكنه لا يستطيع التحقق من backend قد أصلح مشكلة وخلق أخرى.
nginx -t
ss -tnp | grep ':443'
افحص مسار backend والرد بشكل منفصل أيضا. النجاح في قائمة السماح يثبت فقط أن NGINX قبل الجلسة؛ ولا يستطيع جعل backend غير قابل للوصول يرد، ولا إصلاح مسار عودة كان مفقودا قبل أن تبدأ.