Nginx-ը առջևում, մասնավոր backend-ը VPN-ի հետևում
Բրաուզերը խոսում է Nginx-ի հետ, իսկ Nginx-ը բացում է երկրորդ կապը թունելի մեջ։ Երկուսն էլ ուղղորդիր, երկու սերտիֆիկատներն էլ ստուգիր և հանրային վերահասցեավորումները հանրային պահիր։
Հետևիր մեկ հարցումով գնացքի մեջ գտնվող հեռախոսից մինչև backend, որը գոյություն ունի միայն մասնավոր ցանցում։ Հեռախոսը լուծում է հանրային անունը, միանում հանրային հասցեին 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 պրոֆիլը սեփական դարպասի համար, վերամիացումը կարող է ի վերջո փորձել հասնել այդ դարպասին այն թունելով, որը ինքն է պետք է ստեղծի։ Հաճախորդին անհրաժեշտ է, որ այդ անունը լուծված լինի նախքան թունելի գոյությունը։ Հենց որ այն լուծվում է թունելի ներսում, կապը երբեք հնարավոր չէ կառուցել։
Օգտագործիր տարբեր հաստատված անուններ դարպասի և backend-ի համար, և սահմանափակիր լուծիչի քաղաքականությունն այնպես, որ յուրաքանչյուր անուն լուծվի այն հասցեով, որն անհրաժեշտ է իր սպառողին։ Հավելվածի Host վերնագրի փոփոխությունը այստեղ չի օգնում, որովհետև որոնումը կատարում է VPN հաճախորդը։
Այնուհետև մտածիր ծավալի մասին։ Frontend-ին պետք է երթուղի դեպի backend-ի հասցե, և այն նաև պետք է շարունակի պատասխանել հանրային հաճախորդներին։ Ամբողջական թունելը այդ հոսթում կարող է բավարարել առաջին պահանջը և կոտրել երկրորդը։
Այնտեղ, որտեղ քաղաքականությունը թույլ է տալիս, կոնկրետ նպատակակետի թունելը ավելի մաքուր դիզայն է։ Այնտեղ, որտեղ քաղաքականությունը պահանջում է ամբողջական թունել, frontend-ը պատկանում է առանձին ցանցային համատեքստի, այլ ոչ թե կարկատվում է ad hoc երթուղիներով հայտնի այցելուների համար։
Գրել սերվերի բլոկն այնպես, որ երկու մասերն էլ ստուգեն
Ենթադրենք, backend-ը սերտիֆիկատ է ներկայացնում այս անվան համար՝ 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 դիտավոր է։ Backend-ը պետք է կազմաձևված լինի ընդունելու այդ հանրային ծագումը, և այն պետք է վստահի փոխանցված վերնագրերին միայն այս frontend-ից։ Վերագրանցել X-Forwarded-For հաճախորդի հասցեով ճիշտ է մեկ պրոքսի համար և սխալ՝ շղթայի համար, ուստի մի քանի պրոքսով տեղաբաշխմանը պետք է իր սեփական վստահելի հասցեների կարգավորումը։
Ստիպել հանրային ծագմանը վարվել որպես այդպիսին
Հավելվածը պետք է թողարկի բացարձակ URL-ներ, վերահասցեավորումներ և cookie-ներ հանրային ծագման համար։ Եթե այն այցելուին վերահասցեավորում է դեպի backend.corp.example, այդ այցելուն ուղարկվում է անվան, որը չի կարող լուծել։
Ուղղիր դա հավելվածի աջակցվող արտաքին URL-ի կարգավորման և վերանայված վերահասցեավորման քաղաքականության միջոցով, ոչ թե պատասխանների մարմիններում հոսթի անունները վերագրելով։ Տողերի փոխարինումը կամայական բովանդակության մեջ կոտրում է ստորագրված բեռնվածքները և ստեղծում դժվար հետևելի սխալներ։
Cookie-ները նույն խնամքին են արժանի։ Մասնավոր անվանը կապված cookie-ն երբեք չի ուղարկվի բրաուզերի կողմից, որը գիտի միայն հանրայինը։
Նաև հաստատիր, որ Nginx-ը իսկապես կարող է տիրել հանրային սոքեթին։ 443-ի վրա գտնվող գոյություն ունեցող վեբ ծառայությունը պետք է տեղափոխվի, կամ frontend-ը պետք է ապրի այլ տեղ, որովհետև երկու գործընթաց չեն կարող կապել նույն հասցեն և պորտը։
Ստուգել յուրաքանչյուր մասն այնտեղ, որտեղ այն իրականում աշխատում է
Վալիդացրու կոնֆիգուրացիան տեղադրված պարսերի միջոցով ամեն վերաբեռնումից առաջ, որպեսզի տպագրական սխալը չտապալի այն լսողին, որն այժմ սպասարկում է։
Այնուհետև փորձարկիր backend-ի մասը հենց frontend հոսթից, նույն ցանցային համատեքստում, որն օգտագործում է Nginx-ը։ Ping-ը թունելի միջով ապացուցում է հասանելիությունը և ոչինչ TLS-ի, լիազորման կամ հավելվածի մասին։
Վերջապես կատարիր նոր հանրային հարցում իրական հոսթի անվանը սովորական սերտիֆիկատի ստուգմամբ և դիտարկիր պատասխանի ուղին, այլ ոչ միայն մարմինը։
Պահիր երկու դիտարկումներն էլ տեղակայված կոնֆիգուրացիայի հետ և գրանցիր, թե ինչ է լինում, երբ թունելը հասանելի չէ։ Frontend-ը պետք է վերադարձնի վերահսկվող upstream սխալ, այլ ոչ թե լուռ անցնի մեկ այլ backend-ի, որը ոչ ոք չի փաստագրել։ 502-ը հստակ լոգի տողով լավ արդյունք է։ Քեշավորված էջ անցանկալի ծագումից այդպիսին չէ։