Ktoś kieruje publiczny host HAProxy na wewnętrzną aplikację i pyta, dlaczego przeglądarka nie może podążyć. Proxy dociera do aplikacji przez swoje VPN, przekierowanie zwraca nagłówek Location, a przeglądarka próbuje wtedy adresu, który istnieje tylko wewnątrz tunelu. Z zewnątrz strona po prostu wisi. Decyzja dotyczy tego, która strona otwiera drugie połączenie, i właśnie to odróżnia przekierowanie od backendu.

Dwie ścieżki, które w konfiguracji wyglądają podobnie

Przekierowanie kończy wymianę odpowiedzią. Klient czyta Location i zaczyna nowe żądanie z miejsca, w którym się znajduje, czyli z sieci, której nigdy nie kontrolowałeś. Proxy nie bierze już udziału. Wszystko, co następuje, zależy od DNS, trasy i zaufania samego klienta, więc wynik zmienia się w zależności od tego, gdzie użytkownik otworzył przeglądarkę:

GET /app        client -> proxy
302 Location    proxy  -> client   (http://10.40.0.20:8080/)
GET /app        client -> 10.40.0.20:8080   client network, no route

Backend proxy trzyma drugi etap po stronie serwera. Proxy otwiera go ścieżką, którą już ma, a klient nadal rozmawia z jedną publiczną nazwą. Jeśli tunel padnie, klient otrzymuje błąd zamiast adresu URL, którego nie może śledzić. Ta różnica właśnie czyni awarię diagnozowalną, bo błąd pojawia się tam, gdzie są logi:

GET /app        client -> proxy
GET /app        proxy  -> 10.40.0.20:8080   over the VPN
response        proxy  -> client

Dokumentacja przekierowań HAProxy wyznacza dokładnie tę granicę: odpowiedzieć klientowi przekierowaniem to inna czynność niż przekazać żądanie do backendu. Obie dyrektywy stoją kilka linii od siebie w pliku konfiguracji i zachowują się zupełnie różnie. Jedna kończy żądanie, druga zaczyna drugie, które należy do proxy.

Czego potrzebuje przeglądarka, a czego VPN serwera jej nie daje

Żądanie samej przeglądarki potrzebuje czterech rzeczy, których może nie mieć: odpowiedzi DNS dla prywatnej nazwy, trasy do tego adresu, zgody na dotarcie do nasłuchującej usługi i zaufania do certyfikatu, który ta usługa przedstawia. Host proxy ma wszystkie cztery dzięki swojemu tunelowi. Żadna z nich nie przechodzi na klienta, który nigdy nie był w tym tunelu, bo tunel jest właściwością hosta, a nie adresu URL.

Ta luka wyjaśnia objaw prawie-działa. Pierwsze żądanie się udaje, pasek adresu się zmienia, a potem połączenie wisi lub zawodzi, podczas gdy proxy przez cały czas jest zdrowe. W konfiguracji proxy nic nie jest zepsute, a jej dostrajanie nie pomoże klientowi, który nie ma trasy do 10.40.0.20. Albo klient dostaje trasę, albo proxy musi nawiązać połączenie w jego imieniu.

Kiedy tylko proxy może dotrzeć do aplikacji

Usuń akcję przekierowania i wyślij te żądania do backendu, który wskazuje prywatny adres. Frontend zachowuje swoją publiczną nazwę, a backend decyduje, dokąd żądanie naprawdę trafia. Nic w ścieżce klienta się nie zmienia, bo proxy przestaje opisywać cel i zaczyna nim być. Dla aplikacji, która celowo nasłuchuje na wewnętrznym porcie 8080, blok serwera jest krótki:

backend private_app
    mode http
    option httpchk GET /health
    server app1 10.40.0.20:8080 check

Czytaj ten blok jako twierdzenie o tablicy routingu proxy: 10.40.0.20 musi być osiągalny z samego hosta proxy, co tutaj oznacza przez interfejs VPN, a nie przez trasę domyślną. Słowo kluczowe check tylko informuje, co robi ta trasa, a ścieżka kondycji musi istnieć w aplikacji, inaczej każde sprawdzenie oznaczy serwer jako wyłączony. Pomyślne sprawdzenie niczego nie dowodzi o kliencie i nie zastępuje polityki, która decyduje, kto może korzystać z backendu.

Fragment nie jest kompletnym frontendem. Zachowaj nasłuchiwacz, uwierzytelnianie, wybór dozwolonego hosta i ścieżki oraz regułę, która decyduje, kto w ogóle może dotrzeć do aplikacji. Dopasuj też protokół backendu, bo backend HTTPS wymaga weryfikacji certyfikatu i konfiguracji tożsamości serwera, a pominięcie tego sprawdzenia zamienia prywatne połączenie w niezweryfikowane.

Potwierdź drogę powrotną w obu kierunkach, zanim ogłosisz zwycięstwo. Aplikacja widzi teraz połączenie od proxy, więc jej logi i wszelkie metadane adresu klienta opisują proxy, chyba że urządzisz to inaczej. Zdecyduj, jak obsługiwane są tożsamość i przekazywane adresy, i przetestuj tę decyzję zamiast ją zakładać.

Własne przekierowania aplikacji nadal wskazują do środka

Przekazanie pierwszego żądania to tylko połowa integracji. Aplikacja może wysyłać bezwzględne przekierowania, zakodowane na stałe adresy zasobów lub pliki cookie ograniczone do nazwy, którą zna wewnętrznie, i każde z nich odsyła przeglądarkę pod adres, którego nie może osiągnąć. Nagłówek Location wskazujący wewnętrzną nazwę wygląda identycznie jak pierwotny problem, dlatego bywa błędnie diagnozowany jako awaria proxy.

Ustaw udokumentowany zewnętrzny URL aplikacji i jej opcje proxy, a następnie dopasuj nagłówek Host do wirtualnego hosta i oczekiwań certyfikatu. Plik cookie ograniczony do wewnętrznej nazwy nie wróci przez publiczną nazwę, a pętla logowania, która po tym następuje, czyta się jak błąd uwierzytelniania. Najpierw zmień zewnętrzny URL, przetestuj ponownie z czystego profilu przeglądarki i oczekuj, że na wpół zmigrowane ustawienia dadzą logowanie, które się udaje, oraz sesję, która natychmiast umiera.

Ufaj przekazywanym metadanym tylko od wyznaczonego proxy. Nagłówek, który może ustawić dowolny klient, nigdy nie może stać się wartością autoryzacji, inaczej proxy staje się sposobem, w jaki wywołujący rości sobie cudzą tożsamość. Ta reguła jest niezależna od kwestii przekierowania i przeżywa każdy późniejszy redesign.

Zdecyduj, jaki projekt naprawdę masz

Jeśli każdy użytkownik ma już autoryzowany dostęp VPN, przekierowanie na prywatny URL może być zamierzonym projektem. Potwierdź ten wymóg wprost, zamiast go zakładać, bo oba projekty obsługują zupełnie różne grupy. Jeden z nich w ogóle nie działa z sieci hotelowej, a drugi wystawia aplikację każdemu, kto może wczytać publiczny URL. To rozróżnienie należy do notatki projektowej.

Uruchom sprawdzenie z maszyny w sieci użytkowników i śledź każdy skok przeglądarki, nie tylko pierwszą odpowiedź. Uważaj na pasek adresu i każde kolejne żądanie, bo jeden bezwzględny URL w znaczniku zasobu wystarczy, by zepsuć przepływ, który pierwszy skok przeszedł. Logowanie musi działać przez publiczną nazwę, a zasoby, które mają być odrzucane, muszą pozostać odrzucane.

Publikowanie odwrotnego proxy to odrębna decyzja o dostępie, a nie przezroczyste rozszerzenie własnego VPN proxy na każdego, kto może wczytać jego publiczny URL. Oba wyglądają podobnie na schemacie i różnią się tym, komu wolno wejść. Rozstrzyganie tej kwestii po wdrożeniu to sposób, w jaki wewnętrzna aplikacja przypadkiem staje się publiczna.

Zapisz, który z dwóch zbudowałeś i dlaczego. Następna osoba, która dotknie konfiguracji, założy ten drugi. Jedno przekierowanie dodane dla wygody wystarczy, by odtworzyć pierwotną awarię, a objaw będzie wyglądał dokładnie jak ten, który właśnie naprawiłeś.

Powiązane artykuły