Zdalny dostęp do komputera i zasobów zabezpieczonej sieci wewnętrznej, a to wszystko prosto, a jednocześnie zgodnie z dobrymi praktykami bezpieczeństwa? Wydaje się niemożliwe, a jednak się da. Jak to osiągnąć tłumaczy Bartosz Feński aka fEnIo.
Porządnie zabezpieczona sieć komputerowa powinna być odseparowana od świata zewnętrznego tak bardzo, jak to tylko możliwe. I często tak właśnie jest to realizowane. Nawet gdy w sieci jest kilkanaście maszyn, które spełniają przeróżne wyznaczone im role w ramach infrastruktury firmowej, to zazwyczaj jedna maszyna stoi przed tym wszystkim i pełni rolę firewalla, a czasem jednocześnie routera.
Przy założeniu, że polityka wewnątrz firmy nie jest zbyt restrykcyjna, to siedząc przy biurku w pracy do takich maszyn mamy swobodny dostęp. Mogą to być przeróżne wewnętrzne serwisy, bazy danych, serwery plików czy cokolwiek innego, co jest potrzebne do funkcjonowania danego przedsiębiorstwa. Co jednak, gdy po pracy, siedząc już w domowych pieleszach, nadal potrzebujemy połączyć się z którymś serwerem, który z zewnątrz dostępny nie jest?
Postaram się opisać kilka rozwiązań, które można zastosować w takiej sytuacji.
SSH ProxyCommand
Załóżmy najprostszy i, z tego, co się orientuję, dość często spotykany scenariusz. W owej wspomnianej już firmie za firewallem stoi drugi serwer, do którego jest dostęp SSH, ale tylko w ramach lokalnej sieci. Może tak być również w sytuacji, gdy router jednocześnie robi NAT, a adresy serwerów za nim są z prywatnych klas adresowych. Tak więc by się do niego zalogować, musimy się najpierw zalogować na firewalla.
Brzmi znajomo? Ile razy zdarzyło Ci się wykonywać analogiczne jak poniższe polecenia?
laptop$ ssh router
[hasło1]
router$ ssh serwer
[hasło2]
serwer$
Ja robiłem to bardzo często, a skoro coś robi się często, to istnieje spora szansa na to, że dla kogoś powtarzanie tej czynności było na tyle frustrujące, że to zautomatyzował. Tak też się stało w przypadku SSH.
Stwórzmy na maszynie laptop plik konfiguracyjny ~/.ssh/config:
Host serwer
ProxyCommand ssh router nc %h %p 2> /dev/null
By taka konfiguracja zadziałała na maszynie router wymagany jest program netcat, ale w większości dystrybucji znajduje się w pakietach o wysokim priorytecie i zazwyczaj jest już zainstalowany. Jak teraz wygląda połączenie z serwerem?
laptop$ ssh serwer
[hasło1]
[hasło2]
serwer$
Wygenerujmy jeszcze komplet kluczy by darować sobie podawanie tych haseł.
laptop$ ssh-keygen
laptop$ ssh-copy-id router
laptop$ ssh-copy-id serwer
Teraz logowanie wygląda już całkiem przyjemnie:
laptop$ ssh serwer
serwer$
Najfajniejszy jednak w tym wszystkim jest fakt, że wraz z możliwością prostego logowania na maszynie do której publicznego dostępu nie ma, dostajemy również całą gamę usprawnień, które niesie ze sobą samo SSH. Nic nie stoi na przeszkodzie by skorzystać z scp, sshfs, forwardowania X-ów, bądź też zestawić jakiś tunel do innej maszyny przez serwer.
A co w sytuacji analogicznej do poniższej?
laptop -> router1 -> router2 -> ... -> routerN -> serwer
Nie ma przeciwwskazań by w ~/.ssh/config wprowadzić kilkanaście maszyn i zautomatyzować proces logowania nawet, gdy by dostać się do docelowej maszyny, trzeba wcześniej zalogować się na kilkunastu pośredniczących. Po prostu dla każdej z maszyn definiujemy odpowiednie polecenie proxy.
SSH SOCKS
Problem SSH mamy rozwiązany, ale co gdy usługą, do której próbujemy się dostać, jest na przykład serwer WWW? Możemy z maszyny, na którą się dostaliśmy, wykorzystać tekstowe przeglądarki, ale to raczej mało wygodne rozwiązanie.
Możemy również wykorzystać wspomniany już port forwarding, który wraz z zautomatyzowanym logowaniem na różne maszyny jest dość elastycznym rozwiązaniem, ale jednak wymaga wprowadzania dla każdej usługi specjalnych poleceń SSH (lub oczywiście konfiguracji we wspomnianym ~/.ssh/config).
Z pomocą przychodzi nam kolejna funkcja SSH. Potrafi ono pracować jako prosty serwer SOCKS.
laptop$ ssh -D 8080 router
[hasło1]
router$
Jeśli poprzednio wygenerowaliśmy klucze, to oczywiście hasła podawać nie trzeba. Teraz wystarczy w przeglądarce WWW ustawić jako serwer SOCKS localhost oraz port 8080. Wszystkie połączenia będą najpierw tunelowane do maszyny router i dla serwera WWW widoczne tak, jakby były z tej maszyny inicjowane.
Nie wszystkie aplikacje umożliwiają jednak korzystanie z serwerów SOCKS. Ale nawet na to jest lekarstwo w postaci tsocks. To dość prosty program, który za pomocą zmiennej LD_PRELOAD sprawia, że programy korzystają z alternatywnych implementacji funkcji connect(), sendto(), socket() i dzięki temu bez potrzeby ich specjalnego konfigurowania mogą korzystać z serwerów pośredniczących wręcz nieświadomie, jeśli można sobie pozwolić na takie określenie w stosunku do tworów zerojedynkowych.
W pliku konfiguracyjnym tsocks wystarczy właściwie tyle:
server = 127.0.0.1
server_type = 5
server_port = 8080
Teraz aplikacje, które chcemy “oszukać” uruchamiamy w ten sposób:
laptop$ tsocks program_bez_obsługi_socks
Jak widać, z pomocą SSH i prostego programiku możemy dość łatwo zorganizować sobie środowisko pracy z pominięciem ograniczeń wprowadzonych przez firewall. Nie rozwiążemy jednakże w ten sposób wszystkich problemów. Choćby stary, poczciwy protokół FTP z racji tego, że do komunikacji wymaga dwóch portów, w taki sposób oszukany być nie może. Poza tym w momencie, gdy za rzeczonym już firewallem mamy 40 usług na 30 maszynach, to konfiguracja SSH, by umożliwić sobie z nimi kontakt będzie strasznie rozbudowana i trudna w utrzymaniu.
Idealnie byłoby mieć rozwiązanie w którym nasz laptop z pewną klasą adresową po prostu łączy się jakimś kanałem tak, by maszyny docelowe wiedziały, że połączenia przychodzą z zaufanej sieci.
OpenVPN
Z pomocą przychodzi nam OpenVPN. W przeciwieństwie do rozwiązań bazujących na SSH, które pracują w warstwie 7 (aplikacji), OpenVPN pracuje w warstwie 3 (sieciowej) lub nawet 2 (transportowej), więc dla oprogramowania jest zupełnie przeźroczysty. Do tego wszystkiego zapewnia nam uwierzytelnianie oraz szyfrowanie, więc praktycznie nic nie tracimy w stosunku do SSH.
Co prawda od wersji 4.3 również OpenSSH doczekało się możliwości tworzenia tuneli w warstwach 2/3, ale konfiguracja do trywialnych nie należy.
OpenVPN umożliwia tworzenie zaawansowanych konfiguracji i przykładowo połączyć bezpiecznie kilkanaście oddziałów firmy. Ja jednak ograniczę się w tym artykule do zapewnienia dostępu w sytuacji opisanej na początku tego tekstu. Laptop będzie klientem, a na routerze skonfigurowany zostanie serwer VPN.
Zakładam, że pakiet openvpn jest już zainstalowany zarówno na laptopie jak i routerze. Wygenerujmy na routerze klucz, który będzie wykorzystywany do szyfrowania i uwierzytelniania transmisji:
router$ openvpn --genkey --secret /etc/openvpn/static.key
Oraz plik konfiguracyjny /etc/openvpn/server.conf:
dev tun
ifconfig 10.8.0.1 10.8.0.2
secret static.key
Adresy z klasy 10.8.x wykorzystane będą do zestawienia tunelu. Można oczywiście wykorzystać tutaj również jakieś swoje adresy.
Teraz wystarczy uruchomić serwer:
router$ sudo /etc/init.d/openvpn start
Powinien pojawić się dodatkowy interfejs:
tun0 Link encap:UNSPEC
HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:10.8.0.1 P-t-P:10.8.0.2 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Do tego musimy jeszcze odblokować w regułkach firewalla port 1194.
Stworzony klucz static.key należy przekopiować również na laptopa, a następnie utworzyć plik konfiguracyjny dla klienta /etc/openvpn/client.conf:
remote adres_routera
dev tun
ifconfig 10.8.0.2 10.8.0.1
secret static.key
route 192.168.0.0 255.255.255.0
Podmieniamy adres_routera na jego faktyczny adres. Opcja route sprawi, że automatycznie w tablicy routingu pojawi się wpis i ruch do tej sieci będzie kierowany do zestawionego tunelu.
Teraz wystarczy na laptopie również uruchomić VPN:
laptop$ sudo /etc/init.d/openvpn start
Spójrzmy w tablicę routingu:
10.8.0.1 0.0.0.0 255.255.255.255 UH 0 0 0 tun0
192.168.0.0 10.8.0.1 255.255.255.0 UG 0 0 0 tun0
Tym sposobem zestawiliśmy najprostszą możliwą konfigurację. Oczywiście, ma ona też swoje wady. Choćby fakt, że gdy taki klucz dostanie się w niepowołane ręce, to każdy jego posiadacz będzie miał dostęp do naszej sieci. OpenVPN posiada dużo bardziej wyrafinowane sposoby uwierzytelniania, choćby proste zabezpieczenie klucza hasłem, ale to już wybiega poza ramy tego artykułu. Zainteresowani jak zawsze mogą zgłębić temat samodzielnie.