ट्रेन में बैठे फ़ोन से एक अनुरोध को ऐसे बैकएंड तक ट्रैक करें जो केवल निजी नेटवर्क के अंदर मौजूद है। फ़ोन एक सार्वजनिक नाम हल करता है, पोर्ट 443 पर सार्वजनिक पते से जुड़ता है और सामान्य TLS हैंडशेक पूरा करता है। Nginx उस कनेक्शन को स्वीकार करता है और फिर दूसरा, पूरी तरह अलग कनेक्शन उस पते की ओर खोलता है जहाँ वह केवल VPN इंटरफ़ेस से पहुँचता है। फ़ोन पर कुछ नहीं बदलता, और फ़ोन को कभी पता नहीं चलता कि कोई सुरंग शामिल थी।

एक अनुरोध को दो कनेक्शनों से गुजरते देखना

आने वाला हिस्सा एक सार्वजनिक HTTP लेन-देन है। इसका एक सार्वजनिक नाम, एक सार्वजनिक प्रमाणपत्र और एक प्रतिक्रिया पथ है जो हर उस पते के लिए काम करना चाहिए जो उस समय आगंतुक के पास है। उस पथ को बिगाड़ने वाला कोई भी बदलाव एक साथ सभी आगंतुकों को तोड़ देता है। इसलिए सार्वजनिक हिस्सा वह है जिस पर आप सबसे कम प्रयोग करना चाहेंगे।

बाहर जाने वाला हिस्सा निजी है। Nginx क्लाइंट बन जाता है, किसी आंतरिक नाम को हल करता है या स्थिर पता इस्तेमाल करता है, और ऐसी सेवा तक पहुँचता है जो इंटरनेट से आने वाला कनेक्शन ठुकरा देती।

Public client  -> frontend public address:443   (TLS, public name)
Frontend       -> VPN private backend 10.40.0.20:8443  (TLS, private name)

इन्हें मन में अलग रखें और कॉन्फ़िगरेशन स्पष्ट हो जाता है। इन्हें मिला दें तो अंत में आप एक सार्वजनिक क्लाइंट को सुरंग में शामिल करने की कोशिश करेंगे, और इस डिज़ाइन की ज़्यादातर उलझन वहीं से आती है। निजी हिस्सा नाज़ुक हो सकता है। सार्वजनिक नहीं।

इसमें से कुछ भी बनाने से पहले पुष्टि करें कि एप्लिकेशन प्रकाशित करना इरादतन है। काम करता प्रॉक्सी भी काम करता जोखिम है, और प्रमाणीकरण मॉडल निर्णय होना चाहिए, दुष्प्रभाव नहीं।

गेटवे का नाम सुरंग से बचकर निकलना चाहिए

नामों के हल में एक बारीक जाल है। अगर निजी DNS उसी नाम को बदल दे जिसे VPN प्रोफ़ाइल अपने गेटवे के लिए इस्तेमाल करता है, तो दोबारा कनेक्ट होने पर अंत में उसी सुरंग से उस गेटवे तक पहुँचने की कोशिश हो सकती है जिसे उसे खुद बनाना है। क्लाइंट को यह नाम सुरंग के मौजूद होने से पहले हल चाहिए। एक बार जब यह सुरंग के अंदर हल हो जाए, तो कनेक्शन कभी बनाया ही नहीं जा सकता।

गेटवे और बैकएंड के लिए अलग स्वीकृत नाम इस्तेमाल करें, और रिज़ॉल्वर नीति को इस तरह सीमित करें कि हर नाम उस पते पर हल हो जिसकी उसके उपभोक्ता को ज़रूरत है। किसी एप्लिकेशन का Host हेडर बदलना यहाँ कुछ नहीं करता, क्योंकि खोज VPN क्लाइंट करता है।

फिर दायरे के बारे में सोचें। फ़्रंटएंड को बैकएंड के पते तक मार्ग चाहिए और उसे सार्वजनिक क्लाइंट्स को जवाब देते रहना भी चाहिए। उस होस्ट पर पूरी सुरंग पहली शर्त पूरी कर सकती है और दूसरी तोड़ सकती है।

जहाँ नीति अनुमति देती है, किसी विशिष्ट गंतव्य की सुरंग ज़्यादा साफ़ डिज़ाइन है। जहाँ नीति पूरी सुरंग अनिवार्य करती है, फ़्रंटएंड अलग नेटवर्क संदर्भ में रहता है, न कि जाने-पहचाने आगंतुकों के लिए तदर्थ मार्गों से जोड़ा जाता है।

सर्वर ब्लॉक ऐसे लिखें कि दोनों हिस्से सत्यापित करें

मान लें कि बैकएंड इस नाम के लिए प्रमाणपत्र प्रस्तुत करता है: backend.corp.example और निजी पते पर जवाब देता है। किसी नाम को सत्यापित करते हुए किसी पते से जुड़ना ठीक वही है जिसके लिए प्रॉक्सी मॉड्यूल के SNI और नाम विकल्प हैं।

upstream private_app {
    server 10.40.0.20:8443;
}

server {
    listen 443 ssl;
    server_name app.example.com;

    ssl_certificate     /etc/nginx/tls/app-fullchain.pem;
    ssl_certificate_key /etc/nginx/tls/app-key.pem;

    location / {
        proxy_pass https://private_app;
        proxy_ssl_server_name on;
        proxy_ssl_name backend.corp.example;
        proxy_ssl_trusted_certificate /etc/nginx/trust/backend-ca.pem;
        proxy_ssl_verify on;
        proxy_ssl_verify_depth 3;

        proxy_set_header Host app.example.com;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-For $remote_addr;
    }
}

ऊपर दिया हर पथ और पता एक प्लेसहोल्डर है। महत्वपूर्ण वे हिस्से हैं जो सत्यापन को चालू रखते हैं: जाँचने के लिए एक नाम, उसके विरुद्ध जाँचने के लिए एक ट्रस्ट बंडल, और स्वीकृत श्रृंखला से मेल खाती गहराई।

proxy_set_header Host app.example.com जानबूझकर है। बैकएंड को इस सार्वजनिक मूल को स्वीकार करने के लिए कॉन्फ़िगर किया जाना चाहिए, और उसे फ़ॉरवर्ड किए गए हेडर पर केवल इस फ़्रंटएंड से भरोसा करना चाहिए। इसके ऊपर लिखना X-Forwarded-For क्लाइंट पते के साथ एक प्रॉक्सी के लिए सही है और श्रृंखला के लिए गलत, इसलिए बहु-प्रॉक्सी परिनियोजन को अपनी विश्वसनीय पता व्यवस्था चाहिए।

सार्वजनिक मूल को सार्वजनिक मूल जैसा व्यवहार कराएँ

एप्लिकेशन को सार्वजनिक मूल के लिए निरपेक्ष URL, रीडायरेक्ट और कुकीज़ जारी करनी चाहिए। अगर वह किसी आगंतुक को यहाँ भेजता है: backend.corp.example, तो वह आगंतुक ऐसे नाम पर भेजा जाता है जिसे वह हल नहीं कर सकता।

इसे एप्लिकेशन की समर्थित बाहरी URL सेटिंग और समीक्षित रीडायरेक्ट नीति से ठीक करें, प्रतिक्रिया निकायों में होस्ट नाम दोबारा लिखकर नहीं। मनमानी सामग्री में स्ट्रिंग बदलना हस्ताक्षरित पेलोड तोड़ता है और ऐसी बग बनाता है जिन्हें ट्रैक करना कठिन है।

कुकीज़ भी उसी देखभाल की हक़दार हैं। निजी नाम तक सीमित कुकी ऐसा ब्राउज़र कभी नहीं भेजेगा जो केवल सार्वजनिक नाम जानता हो।

यह भी पुष्टि करें कि Nginx वाकई सार्वजनिक सॉकेट का मालिक हो सकता है। 443 पर मौजूद वेब सेवा को हटना होगा या फ़्रंटएंड को कहीं और रहना होगा, क्योंकि दो प्रक्रियाएँ एक ही पता और पोर्ट नहीं बाँध सकतीं।

हर हिस्से को वहीं जाँचें जहाँ वह वाकई चलता है

किसी भी पुनःलोड से पहले कॉन्फ़िगरेशन को स्थापित पार्सर से मान्य करें, ताकि टाइपिंग की गलती उस लिसनर को गिरा न दे जो अभी सेवा दे रहा है।

फिर बैकएंड वाले हिस्से को खुद फ़्रंटएंड होस्ट से, उसी नेटवर्क संदर्भ में परखें जो Nginx इस्तेमाल करता है। सुरंग से होकर ping पहुँच साबित करता है और TLS, प्राधिकरण या एप्लिकेशन के बारे में कुछ नहीं।

अंत में असली होस्ट नाम पर सामान्य प्रमाणपत्र सत्यापन के साथ ताज़ा सार्वजनिक अनुरोध करें, और केवल प्रतिक्रिया निकाय नहीं बल्कि प्रतिक्रिया पथ देखें।

दोनों अवलोकनों को परिनियोजित कॉन्फ़िगरेशन के साथ रखें और लिखें कि सुरंग उपलब्ध न होने पर क्या होता है। फ़्रंटएंड को नियंत्रित upstream त्रुटि लौटानी चाहिए, न कि चुपचाप किसी दूसरे बैकएंड पर गिर जाना चाहिए जिसे किसी ने प्रलेखित नहीं किया। स्पष्ट लॉग पंक्ति के साथ 502 अच्छा परिणाम है। अनचाहे मूल से कैश किया गया पृष्ठ ऐसा नहीं है।

संबंधित लेख