19.01.20237 min
Michał Giza

Michał Giza Administrator systemów / DevOps

Apache Guacamole — klient RDP, SSH i VNC w przeglądarce

Sprawdź, w jaki sposób uzyskać wygodny zdalny dostęp do maszyn i konsol. Dokonać można tego z użyciem znanych protokołów SSH, RDP i VNC oraz sprytnego przeglądarkowego narzędzia - Apache Guacamole.

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.

Guacamole - 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.

Guacamole - 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.

Guacamole - RDP Windows Server


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.

Guacamole - SSH Ubuntu


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.

<p>Loading...</p>