Прати један захтев од телефона у возу до бекенда који постоји само у приватној мрежи. Телефон резолвује јавно име, повезује се са јавном адресом на порту 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 клијент.

Затим размисли о обиму. Фронтенд има потребу за рутом до адресе бекенда и мора да настави да одговара јавним клијентима. Пун тунел на том хосту може да задовољи први услов и сломи други.

Где политика то дозвољава, тунел до конкретног одредишта је чистији дизајн. Где политика захтева пун тунел, фронтенд припада одвојеном мрежном контексту уместо да се крпи 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 је намерно. Бекенд би требало да буде конфигуриран да прихвати то јавно порекло и требало би да верује прослеђеним заглављима само од овог фронтенда. Преписивање X-Forwarded-For адресом клијента је исправно за један прокси, а погрешно за ланац, па распоређивање са више проксија треба сопствено уређење поузданих адреса.

Натерати јавно порекло да се понаша као такво

Апликација би требало да исписује апсолутне URL-ове, преусмеравања и колачиће за јавно порекло. Ако преусмери посетиоца на backend.corp.example, тај посетилац одлази на име које не може да резолвује.

Исправи то кроз подржану поставку спољног URL-а у апликацији и прегледану политику преусмеравања, а не преписивањем имена хостова у телима одговора. Замена низова у произвољном садржају квари потписане терете и ствара грешке које је тешко пратити.

Колачићи заслужују исту пажњу. Колачић ограничен на приватно име никада неће послати браузер који познаје само јавно.

Потврди и да Nginx заиста може да поседује јавни сокет. Постојећа веб услуга на 443 мора да се премести или фронтенд мора да живи негде другде, јер два процеса не могу да вежу исту адресу и исти порт.

Проверити сваки крак тамо где се заиста извршава

Валидирај конфигурацију инсталираним парсером пре сваког поновног учитавања, да словна грешка не сруши слушаоца који управо служи.

Затим тестирај крак бекенда са хоста фронтенда самог, у истом мрежном контексту који користи Nginx. Ping кроз тунел доказује доступност и ништа о TLS-у, ауторизацији или апликацији.

На крају упути свеж јавни захтев на стварно име хоста са нормалном провером сертификата и посматрај повратни пут, а не само тело одговора.

Сачувај оба опажања уз распоређену конфигурацију и запиши шта се дешава када тунел није доступан. Фронтенд би требало да врати контролисану upstream грешку, а не тихо да пређе на други бекенд који нико није документовао. 502 са јасном линијом у дневнику је добар исход. Кеширана страница са нежељеног порекла није.

Повезани чланци