Прасочыце адзін запыт ад тэлефона ў цягніку да бэкенда, які існуе толькі ў прыватнай сетцы. Тэлефон вырашае публічнае імя, падключаецца да публічнага адраса на порце 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.

Затым падумайце пра абсяг. Frontend патрабуе маршруту да адраса бэкенда, і ён таксама мусіць працягваць адказваць публічным кліентам. Поўны тунель на гэтым хосце можа задаволіць першае патрабаванне і зламаць другое.

Там, дзе палітыка гэта дазваляе, тунель да пэўнага прызначэння — чысцейшы дызайн. Там, дзе палітыка патрабуе поўнага тунелю, frontend належыць да асобнага сеткавага кантэксту, а не латаецца ad hoc маршрутамі для вядомых наведвальнікаў.

Напісаць блок сервера так, каб абедзве часткі правяралі

Выкажам здагадку, што бэкенд падае сертыфікат для 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 — гэта наўмысна. Бэкенд варта наладзіць прымаць гэтае публічнае паходжанне, і ён мусіць давяраць перасланым загалоўкам толькі ад гэтага frontend. Перазапіс X-Forwarded-For адрасам кліента правільны для аднаго проксі і памылковы для ланцуга, таму разгортванне з некалькімі проксі патрабуе ўласнага ўпарадкавання давераных адрасоў.

Прымусіць публічнае паходжанне паводзіць сябе як такое

Праграма мусіць выдаваць абсалютныя URL, перанакіраванні і cookie для публічнага паходжання. Калі яна перанакіроўвае наведвальніка на backend.corp.example, гэты наведвальнік трапляе на імя, якое не можа вырашыць.

Папраўце гэта праз наладку знешняга URL, якую падтрымлівае праграма, і перагледжаную палітыку перанакіравання, а не праз перапісванне імёнаў хостаў у целах адказаў. Замена радкоў у адвольным змесце ламае падпісаныя карысныя нагрузкі і стварае памылкі, якія цяжка прасачыць.

Cookie заслугоўваюць такой жа ўвагі. Cookie, абмежаваная прыватным імем, ніколі не будзе адаслана браўзерам, які ведае толькі публічнае.

Таксама пацвердзіце, што Nginx сапраўды можа валодаць публічным сокетам. Існуючая вэб-служба на 443 мусіць пераехаць, або frontend мусіць жыць у іншым месцы, бо два працэсы не могуць заняць той самы адрас і порт.

Праверыць кожную частку там, дзе яна сапраўды працуе

Правалідуйце канфігурацыю ўсталяваным парсерам перад кожным перазапускам, каб друкарская памылка не паклала слухача, які зараз абслугоўвае.

Затым праверце частку бэкенда з самага хоста frontend, у тым жа сеткавым кантэксце, які выкарыстоўвае Nginx. Ping праз тунель даказвае дасяжнасць і нічога пра TLS, аўтарызацыю ці праграму.

Нарэшце зрабіце свежы публічны запыт да сапраўднага імя хоста са звычайнай праверкай сертыфіката і назірайце за зваротным шляхам, а не толькі за целам адказу.

Захавайце абодва назіранні разам з разгорнутай канфігурацыяй і запішыце, што адбываецца, калі тунель недаступны. Frontend мусіць вяртаць кантраляваную памылку upstream, а не ціха перамыкацца на іншы бэкенд, які ніхто не задокументаваў. 502 з ясным радком у логу — добры вынік. Закэшаваная старонка з непажаданага паходжання — не.

Падобныя артыкулы