Polubiłem odwrotne proxy HTTP w naszym środowisku programistycznym i uznałem odwrotne proxy wirtualnych hostów oparte na DNS za całkiem przydatne. Otwarcie tylko jednego portu (i standardowego) w zaporze znacznie ułatwia zarządzanie.
Chciałbym znaleźć coś podobnego do połączeń SSH, ale nie miałem dużo szczęścia. Wolałbym nie używać tunelowania SSH, ponieważ wymaga to otwarcia zakresów portów innych niż standardowy. Czy jest coś, co może to zrobić?
Czy HAProxy może to zrobić?
ssh
reverse-proxy
Ahanson
źródło
źródło
Odpowiedzi:
Nie sądzę, aby SSH oparte na nazwach było możliwe, biorąc pod uwagę sposób działania protokołu.
Oto kilka alternatyw.
Możesz skonfigurować hosta, który odpowiada na port 22, aby działał jako brama. Następnie możesz skonfigurować serwer ssh, aby przekazywał żądania do wewnątrz na podstawie klucza. Przykład bramy SSH z kluczami
Możesz dostosować klienta do używania tego hosta jako serwera proxy. Oznacza to, że będzie ssh do hosta bramy, a następnie użyje tego hosta do nawiązania połączenia z hostem wewnętrznym. Serwer proxy SSH z konfiguracją klienta .
Możesz także skonfigurować prosty serwer proxy HTTP na brzegu. Następnie użyj tego, aby zezwolić na połączenia przychodzące. SSH przez serwer proxy HTTP .
Oczywiście w przypadku wszystkich powyższych elementów upewnienie się, że poprawnie skonfigurujesz i zablokujesz bramę, jest bardzo ważne.
źródło
Przez ostatnie 16 miesięcy szukałem rozwiązania tego problemu. Ale za każdym razem, gdy patrzę, wydaje się to niemożliwe z protokołem SSH określonym w odpowiednich dokumentach RFC i wdrożonym przez główne implementacje.
Jeśli jednak chcesz użyć nieco zmodyfikowanego klienta SSH i chcesz wykorzystać protokoły w sposób, który nie był dokładnie zamierzony w momencie ich zaprojektowania, możesz to osiągnąć. Więcej na ten temat poniżej.
Dlaczego nie jest to możliwe
Klient nie wysyła nazwy hosta w ramach protokołu SSH.
Może wysyłać nazwę hosta jako część wyszukiwania DNS, ale może to być buforowane, a ścieżka od klienta przez resolwery do autorytatywnych serwerów może nie przechodzić przez serwer proxy, a nawet jeśli tak, nie ma solidnego sposobu na powiązanie określonych wyszukiwania DNS z konkretnych klientów SSH.
Z samym protokołem SSH nie ma też nic wymyślnego. Musisz wybrać serwer, nawet nie widząc baneru wersji SSH od klienta. Musisz wysłać baner do klienta, zanim wyśle cokolwiek do proxy. Banery z serwerów mogą być inne i nie masz szansy zgadnąć, który z nich jest właściwy.
Mimo że ten baner jest wysyłany niezaszyfrowany, nie można go modyfikować. Każdy fragment tego sztandaru zostanie zweryfikowany podczas konfiguracji połączenia, więc spowodowałbyś awarię połączenia nieco dalej.
Wniosek jest dla mnie dość jasny, trzeba zmienić coś po stronie klienta, aby ta łączność działała.
Większość obejść obejmuje hermetyzację ruchu SSH w innym protokole. Można sobie również wyobrazić dodatek do samego protokołu SSH, w którym baner wersji wysyłany przez klienta zawiera nazwę hosta. Może to pozostać kompatybilne z istniejącymi serwerami, ponieważ część banera jest obecnie określana jako pole identyfikacyjne w dowolnym formularzu i chociaż klienci zwykle czekają na wersję banera z serwera przed wysłaniem własnego, protokół pozwala klientowi wysłać baner pierwszy. Niektóre najnowsze wersje klienta ssh (na przykład ta w Ubuntu 14.04) wysyłają banner bez czekania na banner serwera.
Nie znam żadnego klienta, który podjąłby kroki w celu umieszczenia nazwy hosta serwera w tym banerze. Muszę wysłać poprawkę do listy OpenSSH dodać taką funkcję do. Zostało to jednak odrzucone z powodu chęci nieujawniania nazwy hosta nikomu węszącemu w ruchu SSH. Ponieważ tajna nazwa hosta jest zasadniczo niezgodna z działaniem serwera proxy opartego na nazwie, nie należy spodziewać się wkrótce oficjalnego rozszerzenia SNI dla protokołu SSH.
Prawdziwe rozwiązanie
Najlepszym rozwiązaniem dla mnie było użycie IPv6.
Dzięki IPv6 mogę mieć osobny adres IP przypisany do każdego serwera, dzięki czemu brama może użyć docelowego adresu IP, aby dowiedzieć się, do którego serwera wysłać pakiet. Klienci SSH mogą czasami działać w sieciach, w których jedynym sposobem na uzyskanie adresu IPv6 byłoby skorzystanie z Teredo. Wiadomo, że Teredo jest zawodne, ale tylko wtedy, gdy natywny koniec połączenia IPv6 korzysta z publicznego przekaźnika Teredo. Można po prostu umieścić przekaźnik Teredo na bramie, na której miałbyś uruchomić proxy. Miredo można zainstalować i skonfigurować jako przekaźnik w mniej niż pięć minut.
Obejście
Możesz użyć hosta skoku / hosta bastionu. To podejście jest przeznaczone dla przypadków, w których nie chcesz narażać portu SSH poszczególnych serwerów bezpośrednio na publiczny internet. Ma to tę dodatkową zaletę, że zmniejsza liczbę zewnętrznych adresów IP potrzebnych do SSH, dlatego jest przydatny w tym scenariuszu. Fakt, że jest to rozwiązanie mające na celu dodanie kolejnej warstwy ochrony ze względów bezpieczeństwa, nie uniemożliwia korzystania z niego, gdy nie jest potrzebne dodatkowe zabezpieczenie.
Brudny do zhakowania, aby działał, jeśli prawdziwe rozwiązanie (IPv6) jest poza twoim zasięgiem
Hack, który zamierzam opisać, powinien być używany tylko jako ostateczność. Zanim nawet pomyślisz o użyciu tego hacka, zdecydowanie zalecamy uzyskanie adresu IPv6 dla każdego serwera, który ma być dostępny zewnętrznie przez SSH. Użyj IPv6 jako podstawowej metody dostępu do serwerów SSH i użyj tego hacka tylko wtedy, gdy potrzebujesz uruchomić klienta SSH z sieci opartej tylko na IPv4, gdzie nie masz żadnego wpływu na wdrożenie IPv6.
Chodzi o to, że ruch między klientem a serwerem musi być całkowicie prawidłowym ruchem SSH. Ale serwer proxy musi tylko zrozumieć wystarczająco dużo o strumieniu pakietów, aby zidentyfikować nazwę hosta. Ponieważ SSH nie definiuje sposobu wysyłania nazwy hosta, możesz zamiast tego rozważyć inne protokoły, które zapewniają taką możliwość.
Zarówno HTTP, jak i HTTPS pozwalają klientowi wysłać nazwę hosta, zanim serwer wyśle jakiekolwiek dane. Pytanie brzmi teraz, czy można zbudować strumień bajtów, który jest jednocześnie ważny jako ruch SSH oraz jako HTTP i HTTPS. HTTPs to w zasadzie nie starter, ale HTTP jest możliwy (dla wystarczająco liberalnych definicji HTTP).
Czy to wygląda dla ciebie jak SSH lub HTTP? Jest zgodny z SSH i całkowicie zgodny z RFC (z wyjątkiem tego, że niektóre znaki binarne zostały nieco zniekształcone przez renderowanie SF).
Ciąg wersji SSH zawiera pole komentarza, które powyżej ma wartość
/ HTTP/1.1
. Po nowej linii SSH ma pewne dane pakietu binarnego. Pierwszy pakiet toMSG_SSH_IGNORE
wiadomość wysłana przez klienta i zignorowana przez serwer. Ładunek do zignorowania to:Jeśli proxy HTTP jest wystarczająco liberalne pod względem tego, co akceptuje, wówczas ta sama sekwencja bajtów byłaby interpretowana jako wywołana metoda HTTP,
SSH-2.0-OpenSSH_6.6.1
a dane binarne na początku komunikatu o ignorowaniu byłyby interpretowane jako nazwa nagłówka HTTP.Serwer proxy nie zrozumie ani metody HTTP, ani pierwszego nagłówka. Ale może zrozumieć
Host
nagłówek, który jest wszystkim, czego potrzebuje, aby znaleźć backend.Aby to zadziałało, proxy musiałoby być zaprojektowane na zasadzie, że musi tylko zrozumieć wystarczającą ilość HTTP, aby znaleźć backend, a po znalezieniu backendu proxy po prostu przekaże strumień surowych bajtów i opuści prawdziwe zakończenie połączenia HTTP do wykonania przez backend.
To może wydawać się nieco rozciągnięte, aby przyjąć tak wiele założeń dotyczących proxy HTTP. Ale jeśli chcesz zainstalować nowe oprogramowanie opracowane z myślą o obsłudze SSH, wymagania dotyczące serwera proxy HTTP nie brzmią tak źle.
W moim przypadku ta metoda działała na już zainstalowanym serwerze proxy bez żadnych zmian w kodzie, konfiguracji lub w inny sposób. Dotyczyło to serwera proxy napisanego wyłącznie z myślą o HTTP i bez SSH.
Dowód klienta koncepcyjnego i proxy . (Wyłączenie odpowiedzialności, że serwer proxy jest usługą obsługiwaną przeze mnie. Możesz zamienić link, gdy jakikolwiek inny serwer proxy zostanie potwierdzony w celu obsługi tego użycia).
Ostrzeżenia dotyczące tego włamania
źródło
the gateway can use the destination IP address to find out which server to send the packet to
, w rozwiązaniu IPv6?-J
, więc możesz użyć: ssh -J użytkownik1 @ front użytkownik2 @ celNie wierzę, że jest to coś, co byłoby możliwe, przynajmniej tak, jak to opisałeś, chociaż chciałbym, aby udowodniono mi, że się mylę. Nie wydaje się, że klient wysyła nazwę hosta, z którym chce się połączyć (przynajmniej w sposób jawny). Pierwszym krokiem połączenia SSH wydaje się być ustawienie szyfrowania.
Ponadto wystąpiłyby problemy z weryfikacją klucza hosta. Klienci SSH zweryfikują klucze na podstawie adresu IP oraz nazwy hosta. Miałbyś wiele nazw hostów z różnymi kluczami, ale z tym samym adresem IP, z którym się łączysz.
Możliwym rozwiązaniem byłoby posiadanie hosta „bastionowego”, w którym klienci mogliby ssh do tej maszyny, uzyskać normalną (lub w razie potrzeby ograniczoną) powłokę, a następnie stamtąd mogliby ssh do wewnętrznych hostów.
źródło
Na bloku jest nowy dzieciak. Piper SSH przekieruje twoje połączenie na podstawie wstępnie zdefiniowanych nazw użytkowników, które powinny być mapowane na hosty wewnętrzne. To najlepsze rozwiązanie w kontekście odwrotnego proxy.
SSh Piper na github
Moje pierwsze testy potwierdziły, że SSH i SFTP oba działają.
źródło
debug1: Sending subsystem: sftp
. Okazuje się, że przód koszuli nie obsługuje podsystemów. Czy wspierasz rąbek w pipecie SSh?Zastanawiam się, czy nie można zmodyfikować Honeytrap (honeypot o niskiej interakcji), który ma tryb proxy, aby to osiągnąć.
Ten plaster miodu jest w stanie przekazać dowolny protokół do innego komputera. Dodanie systemu vhost opartego na nazwie (zaimplementowanego przez Apache) może uczynić go idealnym odwrotnym proxy dla dowolnego protokołu nie?
Nie mam umiejętności, aby to osiągnąć, ale może to być świetny projekt.
źródło
Wraz ze wzrostem liczby portów / hostów, do których chcesz uzyskać dostęp za zaporą, zwiększa się wygoda VPN.
Jednak nie lubię VPN.
źródło
z powodu tego, jak działa ssh, myślę, że to niemożliwe. Podobnie jak w przypadku protokołu https trzeba mieć różne (zewnętrzne) adresy IP dla różnych hostów, ponieważ brama nie wie, gdzie chcesz się połączyć, ponieważ wszystko w ssh jest zakodowane
źródło