Guacamole mit RADIUS Erweiterung aufsetzen
Die Guacamole Version, die im UCS App-Store enthalten ist, kommt leider ohne RADIUS Modul. Daher werden wir Guacamole mit Docker basierend auf dem GitHub Repository bauen. Dies erfordert zwar momentan etwas mehr Handarbeit, ermöglicht aber über RADIUS die Integration mit privacyIDEA und somit die zentrale Verwaltung der zweiten Faktoren. Für Guacamole könnte man auch eine eigene VM mit Docker aufsetzen. Um das HowTo einfach zu halten, habe ich mich entschieden Docker und Guacamole ebenfalls auf dem LinuxMint aufzusetzen.
Dafür installieren wir zuerst einmal Docker und docker-compose
sudo apt-get install docker.io docker-compose
und laden den aktuellen Source Code des Guacamole Client herunter:
cd ~
mkdir dev
wget https://github.com/apache/guacamole-client/archive/master.zip
unzip master.zip
Als nächsten legen wir uns die docker-compose Konfiguration für Guacamole an:
cd ~
mkdir -p docker/guacamole
cd docker/guacamole
mkdir certs dbinit mysql-data
cat >docker-compose.yml <<EOF
version: '3'
services:
guacamole:
image: guacamole:latest
build:
context: ../../dev/guacamole-client-master
args:
- BUILD_PROFILE=lgpl-extensions
restart: always
# Set your hostname to the FQDN under which your
# sattelites will reach this container
hostname: linuxmint.example.com
env_file: ./env.secrets
environment:
- MYSQL_HOSTNAME=mariadb
- MYSQL_DATABASE=guacamole_db
- MYSQL_USER=guacamole_user
- GUACD_HOSTNAME=guacd
- RADIUS_EXT_LINKNAME=1-guacamole-auth-radius
- RADIUS_HOSTNAME=10.0.0.1
- RADIUS_AUTH_PROTOCOL=pap
- VIRTUAL_HOST=linuxmint.example.com
- LOGBACK_LEVEL=warn
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "10"
volumes:
- ./dbinit:/root/dbinit
networks:
- guac-tier
guacd:
image: guacamole/guacd
restart: always
environment:
- GUACD_LOG_LEVEL=warning
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "10"
networks:
- guac-tier
mariadb:
image: mariadb:10.4
restart: always
env_file: ./env.secrets
environment:
- MYSQL_DATABASE=guacamole_db
- MYSQL_USER=guacamole_user
volumes:
- ./dbinit/initdb.sql:/docker-entrypoint-initdb.d/initdb.sql
- ./mysql-data:/var/lib/mysql
networks:
- guac-tier
nginx-proxy:
image: jwilder/nginx-proxy
restart: always
ports:
- "443:443"
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./certs:/etc/nginx/certs
networks:
- guac-tier
networks:
guac-tier:
EOF
Schauen wir uns an, was die docker-compose Konfiguration macht. Erst einmal wird der Guacamole Container definiert und festgelegt, dass das Image dafür lokal aus dem Verzeichnis gebaut wird, in das wir den Source Code ausgepackt haben. Wichtig ist dabei das Build Profil, damit das Radius Modul mitgebaut wird.
services:
guacamole:
image: guacamole:latest
build:
context: ../../dev/guacamole-client-master
args:
- BUILD_PROFILE=lgpl-extensions
Mit den folgenden Umgebungsvariablen wird dem Radius Modul mitgeteilt, wo der Radius Server läuft und welches Protokoll mit diesem gesprochen wird.
- RADIUS_EXT_LINKNAME=1-guacamole-auth-radius
- RADIUS_HOSTNAME=10.0.0.1
- RADIUS_AUTH_PROTOCOL=pap
Um Guacamole über HTTPS erreichbar zu machen, wird davor ein Nginx als Reverse Proxy eingesetzt. Der eingesetzte Container generiert seine Konfiguration für jeden Container, der die Umgebungsvariable VIRTUAL_HOST definiert.
- VIRTUAL_HOST=linuxmint.example.com
Für die Guacamole Container wird noch die Logfile Rotation konfiguriert, damit das Logging der Guacamole Container mir nicht die Festplatte vollschreibt.
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "10"
Zudem wird noch der MySQL Datenbank Container und der Nginx Container definiert.
In einer separaten Datei stellen wir docker-compose die Passwörter zur Verfügung. Diese sollten auf jeden Fall durch sichere Passwörter ersetzt werden.
cat >env.secrets <<EOF
MYSQL_ROOT_PASSWORD=changeme
MYSQL_PASSWORD=changeme
RADIUS_SHARED_SECRET=changeme
EOF
Nun kann ich das Guacamole Client Docker Image bauen:
sudo docker-compose build
Bevor ich die Umgebung starte, generiere ich mit Hilfe des Guacamole Images das Skript zur Datenbank Initialisierung.
sudo docker run --rm guacamole /opt/guacamole/bin/initdb.sh --mysql > ./dbinit/initdb.sql
Ebenso brauche ich noch das Zertifikat für den Nginx Reverse Proxy. Dieses generiere ich auf dem UCS Master und kopiere es auf die LinuxMint VM. Die Dateinamen müssen sich dabei aus dem FQDN und der Dateierweiterung .crt bzw .key zusammensetzen. Der FQDN muss mit dem Wert der Variable VIRTUAL_HOST in der Datei docker-compose.yml übereinstimmen.
ssh root@10.0.0.1
cd /etc/univention/ssl
univention-certificate new -name linuxmint.example.com -days 365
cd linuxmint.example.com
scp cert.pem local-admin@10.0.0.2:/home/local-admin/docker/guacamole/certs/linuxmint.example.com.crt
scp private.key local-admin@10.0.0.2:/home/local-admin/docker/guacamole/certs/linuxmint.example.com.key
Nun kann schließlich die ganze Umgebung gestartet werden und die Log Ausgabe überwacht werden:
sudo docker-compose up -d
sudo docker-compose logs -f
Sobald die Log-Ausgabe wenig neues bringt, kann ich die Guacamole Weboberfläche aufrufen: https://linuxmint.example.com/guacamole.
Auf der Weboberfläche kann ich mich nun mit Benutzername und Passwort + OTP anmelden und erhalte die leere Verbindungsübersicht. Damit funktioniert die Authentifizierung. Jetzt gilt es noch die Authorisierung in Guacamole zu konfigurieren. Dazu melde ich mich wieder ab und melde mich mit dem Benutzer „guacadmin“ mit Passwort „guacadmin“ an. Als erstes ändere ich das Passwort über das Benutzermenü rechts oben -> „Settings“ -> „Preferences“. Dann lege ich über das Benutzermenü -> „Settings“ -> „Connections“ eine neue Verbindung mit den Namen „LinuxMint“ an. Wesentlich sind die folgenden Werte:
Attributname |
Attributwert |
Name |
LinuxMint |
Protocol |
RDP |
Parameters -> Network |
|
Hostname |
10.0.0.2 |
Parameters -> Authentication |
|
Username |
${GUAC_USERNAME} |
Password |
${GUAC_PASSWORD} |
Parameters -> Display |
|
Color depth |
True color (24-bits) |
Im Benutzermenü -> „Settings“ -> „Users“ lege ich noch einen Benutzer mit meinen Benutzernamen aus der Domäne ohne Passwort an. Dem Benutzer weise ich nun die Verbindung zu. Alternativ könnte ich eine Gruppe in Guacamole anlegen, der Gruppe die Verbindung zuweisen und den Benutzer in die Gruppe aufnehmen. Leider unterstützt das Guacamole RADIUS Modul noch keine Gruppen. Einen entsprechenden Feature Request gibt es dazu im Issue Tracker des Projektes.
Für Benutzer, die nur Berechtigung für eine Verbindung haben, öffnet Guacamole diese direkt nach dem Login. Die Variablen im Username und Password führen dazu, dass Guacamole beim Öffnen der Verbindung Benutzername und Passwort durchreicht, welche für die Anmeldung an Guacamole verwendet wurden.
Hier wird jetzt der Authentication Cache von privacyIDEA relevant, den wir in der Richtlinie „login_userpass_otp“ definiert haben. Da das Passwort ja ein OTP enthält, würde die automatische Anmeldung am xRDP einen Fehler liefern, da ein One-Time-Passcode gemäß seines Namen nur einmal verwendet werden kann. Um den Anmeldeprozess für die Benutzer komfortabler zu gestalten, habe ich entschieden, den Auth-Cache zu nutzen.
In einem Umfeld mit begrenzter Anwenderzahl lässt sich die Sicherheit noch weiter verbessern, indem der Zugriff auf den NGINX vor dem Guacamole z.B. mit Client-Zertifikats-Authentifikation eingeschränkt wird.