Guacamole
👋 Présentation
Apache Guacamole est une passerelle de bureau à distance qui ne nécessite pas l'installation d'un client lourd. Elle prend en charge les protocoles standard tels que VNC, RDP et SSH.
Grâce à HTML5, une fois Guacamole installé sur un serveur, tout ce dont vous avez besoin pour accéder à vos postes de travail ou serveurs est un navigateur Web pour vous connecter à l'interface web de l'application.
Dans mon cas, j'ai souhaité l'installer et l'utiliser en tant que bastion.
Technos utilisées dans le cadre de cette expérimentation : - Docker - Traefik + Let's Encrypt - Crowdsec - Authelia
Installation de Guacamole avec Docker
Arborescence
Renseignement de compose.yml et .env
Les URL sont à adapter à votre environnement. Il faudra également renseigner une valeur arbitraire concernant la variable OPENID_AUTHORIZATION_ENDPOINT à la place de <RAMDOM_VALUE>
. Personnellement j'ai utilisé Authelia avec la commande suivante : docker run authelia/authelia:latest authelia crypto rand --length 64 --charset alphanumeric
mais vous pouvez également utiliser tr -cd '[:alnum:]' < /dev/urandom | fold -w "64" | head -n 1
---
services:
# daemon
bastion-dmn:
image: guacamole/guacd
container_name: bastion-dmn
restart: unless-stopped
volumes:
- "/etc/localtime:/etc/localtime:ro"
- ./drive:/drive:rw
- ./record:/var/lib/guacamole/recordings:rw
networks:
bastion_bckd:
# mysql
bastion-db:
image: mariadb:10.9.5
container_name: bastion-db
restart: always
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_PASSWORD}
MYSQL_DATABASE: 'guacamole_db'
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- './db-data:/var/lib/mysql'
networks:
bastion_bckd:
# guacamole
bastion:
image: guacamole/guacamole:latest
container_name: bastion
restart: always
depends_on:
- bastion-dmn
- bastion-db
environment:
GUACD_HOSTNAME: bastion-dmn
# Très important pour récupérer l'IP réelle du client
REMOTE_IP_VALVE_ENABLED: true
MYSQL_DATABASE: guacamole_db
MYSQL_HOSTNAME: bastion-db
MYSQL_PASSWORD: '${MYSQL_PASSWORD}'
MYSQL_USER: '${MYSQL_USER}'
# Afin que de pouvoir régler les permissions des users s'auth. avec Authelia
MYSQL_AUTO_CREATE_ACCOUNTS: true
# TOTP à activer si SSO non utilisé
#TOTP_ENABLED: 'true'
# SSO avec OIDC
OPENID_SCOPE: openid profile groups email
OPENID_AUTHORIZATION_ENDPOINT: https://<URL_AUTHELIA>/api/oidc/authorization?state=<RAMDOM_VALUE>
OPENID_JWKS_ENDPOINT: https://<URL_AUTHELIA>/jwks.json
OPENID_ISSUER: https://<URL_AUTHELIA>
OPENID_CLIENT_ID: <CLIENT_ID_AUTHELIA>
OPENID_REDIRECT_URI: https://<URL_GUACAMOLE>
OPENID_USERNAME_CLAIM_TYPE: preferred_username
OPENID_GROUPS_CLAIM_TYPE: groups
EXTENSION_PRIORITY: '*,openid'
volumes:
- ./drive:/drive:rw
- ./record:/var/lib/guacamole/recordings
labels:
- "traefik.enable=true"
- "traefik.docker.network=web"
- "traefik.http.routers.bastion.rule=Host(`bastion.raspot.in`)"
- "traefik.http.routers.bastion.tls=true"
- "traefik.http.routers.bastion.tls.certresolver=letsencrypt"
- "traefik.http.routers.bastion.entrypoints=websecure"
- "traefik.http.routers.bastion.middlewares=guac-addprefix,crowdsec@file,guac-ipok"
# Pour remove /guacamole de l'URL
- "traefik.http.middlewares.guac-addprefix.addprefix.prefix=/guacamole"
# Je préfère ne pas exposer sur le net et y accéder par le VPN
- "traefik.http.middlewares.guac-ipok.ipallowlist.sourcerange=10.1.1.0/24, 127.0.0.1/32, 192.168.1.0/24"
- "traefik.http.services.bastion.loadbalancer.server.port=8080"
- "traefik.http.routers.bastion.service=bastion"
networks:
web:
bastion_bckd:
networks:
web:
external: true
bastion_bckd:
Lancement de la stack et initialisation de la BDD
docker compose up -d
docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --mysql > initdb.sql
docker exec -i bastion-db mysql --user un_user --password=un_mot_de_passe guacamole_db < initdb.sql
Configuration d'Authelia
C'est la partie SSO. Ce n'est pas indispensable mais tellement pratique. J'ai rédigé une doc ici 🔒Authentification centralisée avec Authelia et LLDAP
L'objectif est double :
- Permettre l'authentification avec Authelia
- Limiter l'accès à un groupe d'utilisateurs
# Authelia CLIENT_ID:
docker run authelia/authelia:latest authelia crypto rand --length 64 --charset alphanumeric
# Authelia CLIENT_SECRET:
docker run authelia/authelia:latest authelia crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986
(...)
identity_providers:
oidc:
jwks:
- key: {{ secret "/secrets/private.pem" | mindent 10 "|" | msquote }}
certificate_chain: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
lifespans.access_token: 1h
lifespans.authorize_code: 1m
lifespans.id_token: 1h
lifespans.refresh_token: 90m
enable_client_debug_messages: false
# RBAC : on limite l'accès aux users faisant partis du groupe guacamole
authorization_policies:
policy_guac:
default_policy: 'deny'
rules:
- policy: 'two_factor'
subject: 'group:guacamole'
clients:
- client_id: '<RAMDOM_VALUE>'
# RBAC
authorization_policy: 'policy_guac'
client_name: 'Apache Guacamole'
client_secret: '<RAMDOM_VALUE>'
public: false
redirect_uris:
- 'https://bastion.raspot.in'
scopes:
- 'openid'
- 'profile'
- 'groups'
- 'email'
response_types:
- 'id_token'
grant_types:
- 'implicit'
consent_mode: 'auto'
pre_configured_consent_duration: '1y'
Relancez Authelia puis rendez-vous sur l'URL de Guacamole.
Gestion des utilisateurs
J'ai créé 3 utilisateurs dans le groupe guacamole qui utiliseront Authelia pour s'authentifier (en 2FA évidemment).
Je me suis rendu sur l'URL de Guacamole puis je me suis identifié avec le user "gadmin" qui servira d'admin en cliquant sur "OpenID" en bas à gauche de la page web :
Je me suis déconnecté puis je me suis connecté cette fois-ci directement dans l'application avec le compte créé par défaut (user:guacadmin, password:guacadmin) pour configurer le compte "gadmin" en tant qu'administrateur. De nouveau je me suis reconnecté avec "gadmin" pour supprimer le compte "guacadmin".
2FA TOTP
Au départ je voulais conserver un compte admin local mais en activant le 2FA sur Guacamole, cela avait pour conséquence de s'appliquer à tous et donc aux users en provenance d'Authelia. Par conséquentj'ai fait le choix de virer le compte admin local et d'utiliser un compte admin passant par Authelia. Après réflexion, j'aurai pu également simplement supprimer le 2FA avec Authelia.
J'ai ensuite créé un groupe guacamole afin d'y régler les permissions au niveau du groupe. J'ai intégré deux utilisateurs (avec lesquels je m'étais connecté auparavant).
Création d'une session
Connectez-vous avec un user puis cliquez en haut à droite sur le nom du user puis Paramètres.
Cliquez sur l'onglet Connexions, puis sur Nouveau Groupe. Renseignez le nom (Maison dans mon cas) et cliquez sur Enregistrer.
Dépliez le groupe créé et cliquez ensuite sur Nouvelle Connexion se situant juste dessous et légèrement grisé. Il ne vous reste plus qu'à renseigner le type de connexion, les creds...
🏁 Conclusion
Je ne vais pas m'étendre sur l'utilisation de Guacamole dans cette documentation. Je n'ai pas pu encore tester le RDP mais je vois déjà un problème se profiler au loin concernant les utilisateurs Windows faisant partis du groupe "Protected users". À voir.
Enfin un dernier élément que je trouve très gênant est le fait que l'admin de Guacamole a accès aux sessions des users. Il peut très bien utiliser celles-ci pour se connecter en SSH ou en RDP. Cela sera tracé mais je trouve ça très limite. Autre point gênant qui provient peut-être de mon manque d'expérience sur l'application sont les groupes. Si mon user n°1 crée un groupe, l'autre user peut le voir ou pas mais ne peut pas y créer une connexion lui étant propre. Je trouve la gestion des permissions très légères pour en faire un outil multi-utilisateurs. À creuser.
Sachez qu'un petit nouveau est arrivé depuis : Nexterm et qui intègre Guacamole. C'est un projet encore jeune, pas multi-user et il y a encore des fonctionnalités en cours d'implémentation. Ce qui m'a plu est la possibilité de se connecter à un noeud Proxmox VE et de récupérer l'ensemble des VM/CT.
Enfin je lorgne depuis peu sur Teleport (Teleport) qui semble plus poussé mais plus complexe à déployer avec des serveurs Windows.