Skip to main content

Apache Guacamole

Guacamole se trata de un servidor HTML5 que se encarga de realizar la conexión dentro de la red doméstica o de la empresa por Remote Desktop, SSH, Telnet, VNC o Kubernetes y servir esa conexión al exterior vía WEB.

No necesita la instalación de agentes o ningún tipo de software cliente. Gracias a HTML5, una vez Guacamole está instalado en un servidor, lo único necesario para acceder a tu desktop es un Navegador WEB.

un despliegue típico de Guacamole incluye tres servicios separados:

  1. guacamole/guacd: es el servicio guacd. guacamole-server tiene soporte para  VNC, RDP, SSH, telnet, y Kubernetes.
  2. guacamole/guacamole: proporciona las aplicaciones web de Guacamole ejecutadas en Tomcat con soporte para WebSocket.
  3. mysql o postgresql: proporciona la base de datos que usará Guacamole para validación y guarda los datos de configuración de las conexiones.

Requisitos

Enlaces

Imagenes

Directorios

mkdir -pv $HOME/docker_volumes/guacamole/{db,guacd/drive}
chmod 777 $HOME/docker_volumes/guacamole/guacd/drive

Portainer- Agregar nuevo «stack»

Add a new stack – Portainer Documentation

Web editor

En Portainer «Stack» agregamos nuevo usando el editor WEB pegando el contenido del fichero «docker-compose.yml» y el contenido del fichero de variables modificando los valores necesarios

image.png

Fichero de variables «.env»

TZ=Europe/Madrid
DOCKER_DATA_DIR=/home/"mi_usuario"/docker_volumes
DOMAIN="mi_dominio.com"
VERSION=1.5.5
GUACD_HOSTNAME=guacd 
MYSQL_HOSTNAME=guacdb
MYSQL_ROOT_PASSWORD=#GeneraPassword
MYSQL_DATABASE=guacamole_db
MYSQL_USER=guacamole_user
MYSQL_PASSWORD=#GeneraPassword

Fichero «docker-compose.yml» inicial

services:
  guacdb:
    container_name: guacdb
    image: docker.io/mariadb
    restart: unless-stopped
    env_file: stack.env
    volumes:
      - $DOCKER_DATA_DIR/guacamole/db:/var/lib/mysql

Iniciando la base de datos MySQL

Si la base de datos no ha sido iniciada aun con el esquema de Guacamole, será un paso previo usando Guacamole. Un script para generar lo necesario en SQL está incluido en la imagen de Guacamole .

Para generar el  script SQL para iniciar una nueva base de datos MySQL como  documenta el manual de Guacamole:

docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --mysql > guac_db.sql
Copiando el script de inicialización en el contenedor
docker cp guac_db.sql guacdb:/guac_db.sql
Abriendo un shell para iniciar la BD
docker exec -it guacdb bash

root@ef7a965feb22:/# cat /guac_db.sql | mysql -u root -p guacamole_db
root@ef7a965feb22:/# exit

Apaga el «Stack» y amplia el fichero docker-compose con el contenido del siguiente punto

Ampliando el fichero «docker-compose.yml»

...
  guacd:
    container_name: guacd
    image: docker.io/guacamole/guacd:$VERSION
    restart: unless-stopped
    volumes:
      - $DOCKER_DATA_DIR/guacamole/guacd/drive:/drive:rw
      - $DOCKER_DATA_DIR/guacamole/guacd/record:/record:rw
  guacamole:
    container_name: guacamole
    image: docker.io/guacamole/guacamole:$VERSION
    restart: unless-stopped
    env_file: stack.env
    depends_on:
      - guacdb
      - guacd
    ports:
      - 8080:8080

En este punto ya puedes ir a http://my.docker.ip.address:8080/guacamole y entrar con guacadmin/guacadmin.

Publicando detrás de un proxy

Crear registro DNS

En el proveedor que aloja el servidor DNS público, crear un registro DNS que resuelva la IP pública que llega al Proxy hacia un nombre del estilo "guacamole.domain.com"

NGINX proxy

image.png

Para publicar el contenedor detrás de NGINX proxy, el fichero "docker-compose.yml" contandrá lo siguiente:

services:  
  guacdb:
    container_name: guacdb
    image: mariadb
    restart: unless-stopped
    env_file: stack.env
    volumes:
      - $DOCKER_DATA_DIR/guacamole/guacdb-data:/var/lib/mysql
    networks:
      - backend
  guacd:
    container_name: guacd
    image: guacamole/guacd:$TAG
    restart: unless-stopped
    env_file: stack.env
    volumes:
      - $DOCKER_DATA_DIR/guacamole/guacd/drive:/drive:rw
      - $DOCKER_DATA_DIR/guacamole/guacd/record:/record:rw
    networks:
      - backend
  guacamole:
    container_name: guacamole
    image: guacamole/guacamole:$TAG
    restart: unless-stopped
    env_file: stack.env
    depends_on:
      - guacdb
      - guacd
    networks:
      - backend
      - proxy
networks:
  backend:
  proxy:
    external: true
Crear un nuevo "proxy host"

Añade un nuevo proxy host con el nombre de dominio creado en el paso anterior redirigido hacia el nombre del contenedor y el puerto que use:

image.png

Si queremos eliminar el "path" /guacamole de la URL, agregamos en las propiedades avanzadas del proxy host la siguiente configuración avanzada:

location / {
    proxy_pass http://guacamole: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/ /;

Traefik

traefik-concepts-1.webp

Para publicar el contenedor detrás del proxy Traefik, deberás añadir al final del fichero "docker-compose.yml" lo siguiente:

    networks:
      - backend
      - traefik_public
    labels:
      - traefik.enable=true
      - traefik.http.routers.guacamole.rule=Host(`guacamole.$DOMAIN`)
      - traefik.http.routers.guacamole.tls=true
      - traefik.http.routers.guacamole.tls.certresolver=letsencrypt
      - traefik.http.routers.guacamole.middlewares=guacamole-prefix
      - traefik.http.middlewares.guacamole-prefix.addprefix.prefix=/guacamole
networks: 
  backend:
  traefik_public: 
    external: true 

Validación de usuarios

OpenID (Azure AD)

https://guacamole.apache.org/doc/gug/openid-auth.html#automatically-redirecting-all-unauthenticated-users

Registra la aplicación siguiendo estos pasos:

  1. Validate en el portal de Azure (https://portal.azure.com/) en el servicio de "Microsoft Entra ID"
  2. En Administrar -> Registro de aplicaciones -> Nuevo Registro

image.png

image.png

Añade este contenido al fichero de variables .env

AZURE_TENANT_ID=#Id. de directorio (inquilino)
OPENID_CLIENT_ID=#Id. de aplicación (cliente)
OPENID_REDIRECT_URI=https://guacamole.$DOMAIN
OPENID_AUTHORIZATION_ENDPOINT=https://login.microsoftonline.com/${AZURE_TENANT_ID}/oauth2/v2.0/authorize
OPENID_JWKS_ENDPOINT=https://login.microsoftonline.com/${AZURE_TENANT_ID}/discovery/v2.0/keys
OPENID_ISSUER=https://login.microsoftonline.com/${AZURE_TENANT_ID}/v2.0
OPENID_USERNAME_CLAIM_TYPE=email
OPENID_SCOPE=openid email profile
EXTENSION_PRIORITY=openid

En la configuración de la "Autenticación" seleccionar "Tokens de id."

image.png

Microsoft Active Directory (LDAP)

Nota:  Si configuramos la conexión con Active Directory, tenemos que crear en nuestro Directorio Activo (dentro de nuestra Base DN) un usuario llamado "guacadmin", y NO debe tener la misma contraseña que el usuario de MySQL. Podremos validarnos con usuarios LDAP y usuarios MySQL

Añade este contenido al fichero de variables .env

# Active Directory 
LDAP_HOSTNAME=DIRECCIÓN_IP_CONTROLADOR_DE_DOMINIO
LDAP_PORT=389 # O seguro: 636 
LDAP_USER_BASE_DN=OU=ruta,DC=dominio,DC=local 
LDAP_USERNAME_ATTRIBUTE=samAccountName
LDAP_CONFIG_BASE_DN=OU=ruta,DC=dominio,DC=local
LDAP_ENCRYPTION_METHOD=none # O seguro: ssl, starttls 
LDAP_SEARCH_BIND_DN=cn=usuario_LDAP,OU=ruta,DC=dominio,DC=local 
LDAP_SEARCH_BIND_PASSWORD=password
LDAP_USER_SEARCH_FILTER=(memberOf=CN=guacamoleUsers,OU=ruta,DC=dominio,DC=local)

Para estar seguro que esto funciona, podemos acceder al  contenedor «guacamole» y ejecutar el siguiente comando para ver si se ha añadido la configuración de LDAP al fichero guacamole.properties:

docker exec -it guacamole bash
cat /home/guacamole/.guacamole/guacamole.properties

Y podremos ver el contenido del fichero guacamole.properties

Autologin a traves de URL

http://my.docker.ip.address:8080/guacamole/#/?serverid=ZZZZZZ&username=USER&password=PASS

Parameter tokens


The values of connection parameters can contain «tokens» which will be replaced by Guacamole when used. These tokens allow the values of connection parameters to vary dynamically by the user using the connection, and provide a simple means of forwarding authentication information without storing that information in the connection configuration itself, so long as the remote desktop connection uses the same credentials as Guacamole.

Each token is of the form ${TOKEN_NAME}, where TOKEN_NAME is some descriptive name for the value the token represents. Tokens with no corresponding value will never be replaced, but should you need such text within your connection parameters, and wish to guarantee that this text will not be replaced with a token value, you can escape the token by adding an additional leading «$», as in «$${TOKEN_NAME}».

${GUAC_USERNAME}
The username of the current Guacamole user. When a user accesses this connection, this token will be dynamically replaced with the username they provided when logging in to Guacamole.

${GUAC_PASSWORD}
The password of the current Guacamole user. When a user accesses this connection, this token will be dynamically replaced with the password they used when logging in to Guacamole.