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

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

TZ=Europe/Madrid
VERSION=1.6.0
GUACD_HOSTNAME=guacd 
MYSQL_HOSTNAME=guacdb
MYSQL_ROOT_PASSWORD=#GeneraPassword
MYSQL_DATABASE=guacamole_db
MYSQL_USER=guacamole_user
MYSQL_PASSWORD=#GeneraPassword
MARIADB_AUTO_UPGRADE=1

Fichero docker-compose inicial

services:
  guacdb:
    container_name: guacdb
    image: mariadb
    restart: unless-stopped
    env_file: stack.env
    volumes:
      - db:/var/lib/mysql
    networks:
      - backend

volumes:
  db:

networks:
  backend:
  proxy:
    external: true

Iniciando la base de datos

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 .

# Genera script SQL para iniciar una nueva base de datos
docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --mysql > guac_db.sql

# Copia script de inicialización en el contenedor
docker cp guac_db.sql guacdb:/guac_db.sql

# Inicializa la base de datos
docker exec -it guacdb bash -c "cat /guac_db.sql | mariadb -u root -p guacamole_db"

Ampliando el fichero docker-compose

services:
  guacdb:
    container_name: guacdb
    image: mariadb
    restart: unless-stopped
    env_file: stack.env
    volumes:
      - db:/var/lib/mysql
    networks:
      - backend

  guacd:
    container_name: guacd
    image: guacamole/guacd:$VERSION
    restart: unless-stopped
    volumes:
      - drive:/drive:rw
      - record:/record:rw
    networks:
      - backend

  guacamole:
    container_name: guacamole
    image: guacamole/guacamole:$VERSION
    restart: unless-stopped
    env_file: stack.env
    depends_on:
      - guacdb
      - guacd
    ports:
      - 8080:8080
    networks:
      - backend
      - proxy

volumes:
  db:
  drive:
  record:

networks:
  backend:
  proxy:
    external: true

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

Using a reverse proxy for SSL termination — Apache Guacamole Manual v1.6.0

image.png

Para publicar el contenedor detrás de NGINX proxy, como el stack está en la red proxy solo deberás crear un nuevo host

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;
    access_log off;
}

Traefik

traefik-concepts-1.webp

Para publicar el contenedor detrás del proxy Traefik, deberás añadir al fichero docker-compose.yaml las siguientes etiquetas al servicio guacamole

    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

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.