Apache Guacamole — klient RDP, SSH i VNC w przeglądarce
Współcześnie kwestia uzyskania dostępu do zdalnego pulpitu czy SSH nie jest skomplikowana. Klienty tych usług są z reguły łatwe w obsłudze, często nie ma nawet potrzeby ich instalacji. Natomiast większy problem dotyczy zarządzania dostępem do podobnych wrażliwych usług. W idealnym scenariuszu usługi typu RDP i SSH powinny być ograniczone do wybranych adresów IP lub dostępne wyłącznie poprzez VPN (co z reguły spotyka się w przypadku wewnętrznych sieci firmowych).
Kiedy ten dostęp jest już ograniczony, możemy spróbować wykorzystać Apache Guacamole. To rozwiązanie zapewnia możliwość realizacji dostępu do standardowych usług zdalnych poprzez przeglądarkę. Użytkownik końcowy uzyskuje w ten sposób łatwe w użyciu narzędzie i — co jest często istotnym argumentem — nie musi nic konfigurować po swojej stronie.
Instalacja Guacamole niestety bywa problematyczna z uwagi na zastosowane technologie, natomiast ten proces jest jak najbardziej możliwy do realizacji. Najprostsze podejście wymaga instalacji serwera Tomcat i kilku bibliotek. W celu uniknięcia wystawiania serwera Tomcat „na świat”, dodania obsługi SSL oraz Basic Auth czy nawet ograniczenia dostępu dla wybranych adresów IP sprawdzi się NGINX. Inne podejście to wykorzystanie Docker.
Dlatego w pierwszym kroku instalujemy wszystkie potrzebne pakiety:
sudo apt install gcc build-essential libcairo2-dev libjpeg-turbo8-dev libpng-dev libtool-bin libossp-uuid-dev libavcodec-dev libavutil-dev libswscale-dev libpango1.0-dev libssh2-1-dev libvncserver-dev libtelnet-dev libssl-dev libvorbis-dev libwebp-dev freerdp2-dev freerdp2-x11 libavformat-dev libpulse-dev libwebsockets-dev openjdk-11-jdk nginx
Guacamole nie działa poprawnie z Tomcat 10, dlatego konieczna będzie wersja 9. Jest dostępna w repozytorium Ubuntu, ale do uruchomienia Tomcat wystarczy pobranie archiwum i dodanie odpowiedniej usługi systemowej:
sudo useradd -m -U -d /opt/tomcat -s /bin/false tomcat
wget https://downloads.apache.org/tomcat/tomcat-9/v9.0.71/bin/apache-tomcat-9.0.71.tar.gz
sudo tar -zxvf apache-tomcat-9.0.71.tar.gz -C /opt/tomcat
sudo mv /opt/tomcat/apache-tomcat-9.0.71 /opt/tomcat/src
sudo chown -R tomcat: /opt/tomcat
sudo sh -c 'chmod +x /opt/tomcat/src/bin/*.sh'
Warto weryfikować przed próbą pobrania plików ze strony downloads.apache.org, czy ścieżki nie zostały zmienione (dla nowych wersji), co będzie mieć miejsce wraz z biegiem czasu od daty publikacji tego tekstu.
Tworzymy plik /etc/systemd/system/tomcat.service
o zawartości:
[Unit]
Description=Tomcat
After=network.target
[Service]
Type=forking
User=tomcat
Group=tomcat
Environment="JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64"
Environment="JAVA_OPTS=-Djava.security.egd=file:///dev/urandom -Djava.awt.headless=true"
Environment="CATALINA_BASE=/opt/tomcat/src"
Environment="CATALINA_HOME=/opt/tomcat/src"
Environment="CATALINA_PID=/opt/tomcat/src/temp/tomcat.pid"
Environment="CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC"
ExecStart=/opt/tomcat/src/bin/startup.sh
ExecStop=/opt/tomcat/src/bin/shutdown.sh
[Install]
WantedBy=multi-user.target
Kolejne polecenia przeładują konfiguracje plików systemd, uruchomią serwer Tomcat i umożliwią automatyczny start naszej usługi po każdym restarcie systemu:
sudo systemctl daemon-reload
sudo systemctl start tomcat
sudo systemctl enable tomcat
Po wykonaniu wszystkich powyższych poleceń na porcie 8080 powinien być dostępny Tomcat.
Teraz należy pobrać archiwum z aktualnym wydaniem Guacamole i wykonać kompilację:
wget https://downloads.apache.org/guacamole/1.4.0/source/guacamole-server-1.4.0.tar.gz
tar -zxvf guacamole-server-1.4.0.tar.gz
cd guacamole-server-1.4.0
./configure --with-init-dir=/etc/init.d
make
sudo make install
sudo ldconfig
Istnieje szansa, że pojawi się błąd związany z OpenSSL i “deprecated”. Możemy to jednak obejść poprzez wykonanie przed make polecenia:
export CFLAGS=-Wno-error
Analogicznie aktywujemy usługę guacd:
sudo systemctl daemon-reload
sudo systemctl start guacd
sudo systemctl enable guacd
sudo systemctl status guacd
Następnie do katalogu /etc/guacamole
pobieramy „klienta” Guacamole ze strony Apache.
Dodajemy konfigurację w pliku /etc/guacamole/guacamole.properties
:
guacd-hostname: localhost
guacd-port: 4822
user-mapping: /etc/guacamole/user-mapping.xml
auth-provider: net.sourceforge.guacamole.net.basic.BasicFileAuthenticationProvider
Dodatkowo tworzymy dowiązania symboliczne do pobranego pliku w katalogu /opt/tomcat/src/webapps oraz do katalogu /etc/guacamole w /opt/tomcat/src
:
sudo ln -s /etc/guacamole/guacamole.war /opt/tomcat/src/webapps
sudo ln -s /etc/guacamole /opt/tomcat/src/.guacamole
W pliku /etc/guacamole/user-mapping.xml
przechowywana będzie konfiguracja dostępu dla poszczególnych użytkowników oraz hosty, do których mogą nawiązywać połączenie. Przykład dla użytkownika user z hasłem zaq1@WSX i serwera SSH oraz RDP wygląda tak:
<user-mapping>
<authorize
username="user"
password="9e38e8d688743e0d07d669a1fcbcd35b"
encoding="md5">
<connection name="Ubuntu">
<protocol>ssh</protocol>
<param name="hostname">10.0.0.10</param>
<param name="port">22</param>
</connection>
<connection name="Windows">
<protocol>rdp</protocol>
<param name="hostname">10.0.0.20</param>
<param name="port">3389</param>
<param name="ignore-cert">true</param>
<param name="enable-wallpaper">true</param>
</connection>
</authorize>
</user-mapping>
Hasło zostało zakodowane w MD5. Guacamole wspiera hasła zapisane jako plaintext lub w postaci MD5. Aby uzyskać skrót MD5 dla dowolnego ciągu, wystarczy wykonać:
echo -n <tekst> | md5sum
Kolejnego użytkownika możemy „dodać” poprzez zwykłe dopisanie znacznika authorize z atrybutami username, password i encoding. Wewnątrz tego znacznika należy po prostu wskazać hosty (connection) widoczne dla danego użytkownika. Przykład:
<user-mapping>
<authorize
username="user"
password="9e38e8d688743e0d07d669a1fcbcd35b"
encoding="md5">
<connection name="Windows">
<protocol>rdp</protocol>
<param name="hostname">10.0.0.20</param>
<param name="ignore-cert">true</param>
<param name="enable-wallpaper">true</param>
</connection>
</authorize>
<authorize
username="mgiza"
password="926f8d115f96e3f7ac0c5605c2915c15"
encoding="md5">
<connection name="Ubuntu">
<protocol>ssh</protocol>
<param name="hostname">10.0.0.15</param>
</connection>
</authorize>
</user-mapping>
Nie ma potrzeby, aby Tomcat był dostępny z zewnątrz. W celu uruchomienia tego serwera wyłącznie lokalnie, w pliku /opt/tomcat/src/conf/server.xml
należy linię <Connector port="8080" protocol="HTTP/1.1"
zmienić na <Connector address="127.0.0.1" port="8080" protocol="HTTP/1.1”
i zrestartować usługę.
Jak wspomniałem, za obsługę ruchu będzie odpowiadał NGINX, stąd powinniśmy dodać porównywalną do poniższej konfigurację:
server {
listen 80;
listen 443 ssl;
server_name webclient;
ssl_certificate /etc/nginx/ssl/webclient.crt;
ssl_certificate_key /etc/nginx/ssl/webclient.key;
if ($scheme != "https") { rewrite ^ https://$host$uri permanent; }
auth_basic "Authorization required";
auth_basic_user_file /etc/nginx/auth/webclient;
location / {
proxy_pass http://127.0.0.1:8080/guacamole/;
proxy_buffering off;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_cookie_path /guacamole/ /;
}
}
Jest to typowe reverse proxy. Zastosowano ponadto zabezpieczenie dostępu w formie Basic Auth. Po wejściu w adres podany jako server_name powinniśmy zobaczyć panel logowania. Jeśli podaliśmy prawidłowe poświadczenia, widoczne będą dodane hosty.
W przypadku usługi RDP w systemie Windows należy zmodyfikować w rejestrze w kluczu HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp
wartości:
SecurityLayer - 1
UserAuthentication - 0
Połączenie z poziomu Guacamole nie będzie niestety możliwe bez wprowadzenia tych zmian. Ponowne uruchomienie systemu nie jest wymagane, wszystko zadziała ad hoc. Poniższy zrzut ekranu przedstawia sesję RDP do Windows Server w Guacamole.
Alternatywę dla opisanej standardowej instalacji stanowi Docker. Najpierw uruchamiamy kontener z guacd:
docker run --name server -d guacamole/guacd
Następnie tworzymy bazę danych (również może być w formie kontenera) i użytkownika dla Guacamole. Dodam, że powinna to być baza PostgreSQL lub MySQL, przy czym Percona nie jest wspierana. Obraz Guacamole zawiera skrypt służący do inicjalizacji bazy danych. Efekt jego działania uzyskamy poleceniem:
docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --postgres> initdb.sql
lub (dla MySQL):
docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --mysql > initdb.sql
Importujemy plik initdb.sql:
docker exec -i mysql /usr/bin/mysql -uroot -p<hasło> guacamole < initdb.sql
Zamierzamy użyć NGINX jako reverse proxy, co jednak wymaga statycznego adresu IP dla kontenera z Guacamole. Ogólnie w tym celu tworzy się Docker network i parametrem --ip przypisuje adresy. Natomiast podczas moich testów kontener z Guacamole nie uruchamiał się poprawnie (docker logs informowały o problemach z linkowaniem do kontenera guacd), kiedy był uruchamiany w dedykowanej sieci wraz z innymi potrzebnymi kontenerami.
Rozwiązaniem może być zastosowanie IP aliasing. Polega to na powiązaniu danego interfejsu sieciowego z kilkoma adresami. Najprostszym sposobem dopisania adresu jest wykonanie polecenia:
ip addr add 172.17.0.100 dev <interfejs>
Nazwę interfejsu uzyskamy poleceniem ip a lub ifconfig. Polecam też dodać to polecenie do cron’a jako @reboot. Kontener powinien zostać poprawnie uruchomiony po wykonaniu:
docker run --name guacamole --link server:guacd --link mysql:mysql -e MYSQL_DATABASE=guacamole -e MYSQL_USER=guacamole -e MYSQL_PASSWORD=<hasło> -p 172.17.0.100:8080:8080 -d guacamole/guacamole
Konfiguracja NGINX może pozostać bez zmian, wystarczy jedynie ustawić adres 172.17.0.100 zamiast 127.0.0.1 w proxy_pass. Przykładowe uruchomienie:
docker run -d --name nginx -p 80:80 -p 443:443 -v ~/nginx/conf.d:/etc/nginx/conf.d -v ~/nginx/ssl:/etc/nginx/ssl -v ~/nginx/auth:/etc/nginx/auth nginx
Guacamole będzie już dostępny pod wskazanym adresem. Login i hasło dla tego obrazu to guacadmin. Wchodzimy w guacadmin -> Settings -> Connections -> New Connection, gdzie możemy dodać hosty i odpowiednie usługi zdalnego dostępu. Opcji będzie wiele, ale wystarczy wzorować się na podanym wyżej pliku user-mapping.xml. Nie wszystkie parametry muszą zostać koniecznie uzupełnione.
Jeśli na serwerze, do którego się łączymy, jest nowsza wersja OpenSSH, może pojawić się błąd SSH handshake failed (widać to w logach kontenera guacd). Rozwiązaniem jest dodanie do pliku /etc/ssh/sshd_config poniższych linii i restart usługi SSH.
HostKeyAlgorithms +ssh-rsa
PubkeyAcceptedKeyTypes +ssh-rsa
Widoczny zrzut ekranu przedstawia sesję SSH realizowaną przez Guacamole do hosta z systemem Ubuntu 22.04.
Podsumowanie
Opisane narzędzie z pewnością jest jednym z ciekawszych dostępnych rozwiązań. Może znaleźć zastosowanie w wielu przypadkach. Stosunkowa łatwość instalacji i późniejszej obsługi to zdecydowanie wartość dodana.