Utrzymanie adresu klienta VPN aż do aplikacji sprawia, że każda linia logu i każdy wpis na liście dozwolonych znaczą to samo. Przepisywanie go na granicy chmury upraszcza tabelę routingu i czyni logi mniej użytecznymi. Żaden z wyborów nie jest sam w sobie błędny, a argument, który go rozstrzyga, rzadko dotyczy wydajności. Rozstrzygają trzy warunki: czy aplikacja musi wiedzieć, która osoba się połączyła, czy tkanina chmury zaakceptuje źródło, które zamierzasz wysłać, i kto później weźmie odpowiedzialność za trasę powrotną.

Rozstrzygają trzy warunki

Zacznij od wymagania aplikacji, a nie od diagramu sieci. Jeśli autoryzacja lub audyt zależą od indywidualnego adresu klienta, to jego zachowanie jest wymogiem funkcjonalnym, a tłumaczenie regresją. Jeśli aplikacja musi tylko wiedzieć, że ruch przyszedł ścieżką dostępu zdalnego, wystarczy przetłumaczony adres i jest to znacznie tańsze w utrzymaniu.

Drugi warunek jest mechaniczny. Sieć wirtualna nie ufa automatycznie pakietowi, który twierdzi, że adres nie został przypisany interfejsowi wysyłającemu. Większość tkanin chmury wymusza to na różne sposoby i pod różnymi nazwami, a projekt, który to ignoruje, będzie wyglądał poprawnie na diagramie i po cichu zawiedzie na produkcji.

Trzeci jest organizacyjny. Zachowanie źródeł oznacza, że tabela routingu podsieci aplikacji musi wskazywać z powrotem na bramę dla prefiksu klienta, a każdy zespół, który później doda podsieć, musi utrzymać tę trasę spójną. To jednorazowo mały koszt i koszt powtarzający się w dziesiątkach kont. Zdecyduj, kto go ponosi, zanim obiecasz to zachowanie.

Trasa nie jest pozwoleniem na podszywanie się

Dodanie trasy powrotnej mówi twojej podsieci, dokąd mają trafiać odpowiedzi. Nie mówi tkaninie, że instancja przekazująca te pakiety ma prawo wysyłać je z obcym źródłem. W AWS odpowiednią kontrolą jest sprawdzanie źródła i celu, i jest ono widoczne dla każdej instancji:

aws ec2 describe-instances --instance-ids i-0a1b2c3d4e5f60718 \
  --query "Reservations[].Instances[].SourceDestCheck"
aws ec2 modify-instance-attribute --instance-id i-0a1b2c3d4e5f60718 \
  --no-source-dest-check

Wyłącz je tylko dla instancji, której udokumentowanym zadaniem jest przekazywanie, i dla niczego innego. Każda maszyna wirtualna aplikacji, która zostawia to sprawdzanie włączone, to o jedną maszynę mniej, której można użyć do wysyłania ruchu z pożyczonym źródłem. Jeśli twoja platforma nie jest AWS, poszukaj równoważnego ustawienia anty-podszywania się lub dozwolonych adresów, zamiast zakładać, że zachowanie się przeniesie.

Szybkie przechwycenie pakietów rozstrzyga pytanie szybciej niż czytanie konsoli. Jeśli odpowiedzi wychodzą, a klient nigdy ich nie widzi, to tkanina odrzuca podrobione źródło, a nie aplikacja zawodzi.

Co kupuje tłumaczenie i ile kosztuje

Przepisanie źródła na bramie usuwa problem trasy powrotnej. Aplikacja widzi jeden adres, do którego już wie, jak dotrzeć, a prefiks klienta nigdy nie musi pojawiać się w tabeli routingu chmury. W Linuksie reguła to jedna linia i warto napisać najwęższą wersję, jaką potrafisz:

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -s 172.20.8.0/24 -o ens5 -j SNAT --to-source 10.40.3.10

Zwróć uwagę, co aplikacja teraz zapisuje: 10.40.3.10 dla każdego użytkownika, przy każdym połączeniu, na zawsze. Każda lista dozwolonych adresów zbudowana na tej wartości daje teraz dostęp całej populacji dostępu zdalnego, a każdy przegląd incydentu musi wrócić do bramy, aby odpowiedzieć, kto to był.

Rozwiązaniem nie jest porzucenie tłumaczenia, lecz zaprzestanie udawania, że adres jest tożsamością. Noś tożsamość klienta w uwierzytelnionym polu, zapisuj ją na bramie razem z przetłumaczoną krotką i pozwól aplikacji się na niej łączyć. Bez klucza łączenia tłumaczenie zamienia problem sieciowy w trwały problem kryminalistyczny.

Przekaźnik to inny interfejs

Odwrotne proxy przed aplikacją całkowicie omija kwestię trasy routowanej. Proxy otwiera własne połączenie z backendem, więc prefiks klienta nigdy nie musi być trasowalny w sieci wirtualnej, a aplikacja może otrzymać tożsamość w nagłówku, który ustawia proxy.

Ten nagłówek jest wiarygodny tylko wtedy, gdy backend przyjmuje go od proxy i od niczego innego. W terminach nginx oznacza to nazwanie zaufanego partnera wprost, zamiast wierzyć we wszystko, co przychodzi:

set_real_ip_from 10.40.3.10;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

Każdy klient, który może dotrzeć do backendu bezpośrednio, może podrobić ten sam nagłówek, więc backend musi być nieosiągalny poza proxym. To fakt zapory sieciowej, a nie opinia o konfiguracji, i właśnie to założenie ludzie pomijają, kopiując fragment.

Przekaźnik zmienia też to, co kupujesz. Otrzymujesz tożsamość na poziomie aplikacji i naturalne miejsce, by ją zapisywać; rezygnujesz z ogólności, bo każdy nowy protokół potrzebuje własnego wsparcia proxy. Dla usług HTTP ta wymiana jest zwykle dobra, a dla wszystkiego, co nie jest HTTP, zwykle w ogóle nie jest dostępna.

Zapisz, co widzi każda granica

Cokolwiek wybierzesz, przegląd projektu powinien kończyć się jedną tabelą, która nazywa adres źródłowy i dowodliwą tożsamość na każdym skoku. Bez niej pierwszy incydent daje trzy zespoły, z których każdy opisuje innego klienta.

BoundarySource the next hop seesWhat is actually proven
Client to gateway172.20.8.14A certificate or credential was presented
Gateway to app subnet, preserved172.20.8.14The same session, if the return route exists
Gateway to app subnet, translated10.40.3.10Only that traffic came through the gateway
Proxy to backend10.40.3.10 plus a headerThe proxy asserted an identity it authenticated

Potem wybierz. Zachowaj źródło, gdy autoryzacja aplikacji naprawdę zależy od adresu klienta i możesz wziąć trasę na siebie. Tłumacz, gdy tak nie jest i możesz nieść tożsamość poza pasmem, a do ustawień przekazywania specyficznych dla platformy użyj wskazówek AWS dotyczących instancji przekazujących. Sięgnij po przekaźnik, gdy usługa mówi po HTTP i chcesz, aby tożsamość przestała być adresem.

Powiązane artykuły