DOCKER: Guacamole
It’s time to clean off your worktop and prepare some delicious Guacamole with the help of Kevin Wittmer.
It’s time to clean off your worktop and prepare some delicious Guacamole, with the help of Kevin Wittmer and the world of Docker containers.
Figure 1: Block diagram of Guacamole Docker footprint.
Guacamole offers ready-to-run installation packages that are available for Linux distros such as Centos or Debian. However, the thrust of this article is to illustrate running Guacamole in a Docker container context.
Fire up an environment where you have access to the Docker command line and where you feel comfortable to pull and run Docker images. It’s recommended that you evaluate Guacamole in a sandbox that has Docker tooling installed. The Docker command line should have access to the default registry maintained at hub.docker. com. To verify which registry your Docker tooling is pointing to, type this command: docker info
Scan the output of this command-line tool for Registry and confirm that this field includes index.docker.io (or possibly a mirror of this registry).
The next step is to search for the official Guacamole
Docker images using the Docker search command. The search command prints an abbreviated description of the image by default. To receive the full description specify the --no-trunc argument. The search syntax shown below matches various Docker images of
Guacamole, including several derivatives. A crude way to filter these results is by stars. docker search --no-trunc --filter stars=25 guacamole
The results should include image guacamole/ guacamole and image guacamole/guacd. To download the Apache Guacamole Proxy image from the Docker
Hub registry, execute this command: docker pull guacamole/guacd
Execute the pull command again but now download the Docker image guacamole/guacamole, as this has the Java and Javascript bits comprising the Web API and Web UI application layers.
docker pull guacamole/guacamole
After downloading has completed, reconfirm by using the Docker images command, and gain a sense of the size of each image.
docker images
Scanning the output from this command, you can see that Docker image guacd is approximately 400MB in size, while guacamole is approaching 500MB.
As a security precaution, it’s advised to scan Docker images before promoting these beyond any sandbox.
Anchore, an open source project that provides a centralised service for inspection, analysis, and certification of container images is one tooling option. In the command example below, the Anchore CLI is used to perform a vulnerability scan on the main
Guacamole Docker image.
anchore-cli image vuln guacamole/guacamole:latest all
The results of the scan will show critical, high, medium and low vulnerabilities using Common Vulnerabilities and Exposures (CVE) identifiers. The ‘all’ argument includes vulnerabilities at the OS level. Scanning all Docker images deployed is recommend. The docker inspect command gives these results.
docker inspect guacamole/guacd
The most telling fields included in the results of the docker inspect command are Exposedports, Env and Cmd. In this instance, Exposedports shows the value of QUICK TIP
Database authentication
4822/tcp, which is the port that the proxy listens on. Environmental variables include GUACD_LOG_LEVEL,
which has a log level of info. To capture more verbose logging, set the log level to debug. Also noteworthy, Cmd shows the path of the Guacamole proxy binary program to be /usr/local/guacamole/sbin/guacd. docker inspect guacamole/guacamole
Inspecting the Guacamole Java-based application server image shows that the external port exposed is 8080, a Tomcat default. The set of environment variables include JAVA_HOME and JAVA_VERSION,
which indicates that Java 8 is the base JRE. The Tomcatcentric CATALINA_HOME is also exposed. Finally, the Cmd property indicates that the start.sh script is the main entry point for container execution.
Running Guacamole in a container context requires backing the Java servlet-based server component with a relational database. Supported relational database engines include SQL Server, Postgres, and MYSQL. For my purposes, I have chosen the open source Mariadb, leveraging the MYSQL support that Guacamole offers. The next series of commands assume that your infrastructure landscape includes a Mariadb instance.
After successful DB login via the MYSQL command prompt, take a peek at the Mariadb version with
SHOW VARIABLES LIKE “%version%”;
To begin, create the Guacamole database with the following SQL statement:
CREATE DATABASE guacamole_db;
After successful database creation, create the Guacamole
DB user account and specify the password credentials. This DB user is the key account that the Guacamole server-side component uses for database connectivity.
CREATE USER ‘guacamole_user2’@’%’ IDENTIFIED BY ‘gua$am0l3’;
FLUSH;
With the user account created, the next step is to grant the authorisations the Guacamole application requires. The Guacamole database persists application data, including user accounts and server connection properties. Therefore, authorisations for reading, writing, updating, and deleting need to be assigned to the DB user. The grant command accomplishes this: GRANT SELECT,INSERT,UPDATE,DELETE ON guacamole_db.* TO ‘guacamole_user2’@’%’; FLUSH;
Before you transition to running the Guacamole
Docker images, verify DB user connectivity by attempting to log in to the Guacamole database.
mysql -D guacamole_db -u guacamole_user2 -p
If user login is successful, then you are ready to generate the Guacamole schema objects and create them in this database.
The next series leverages the previous Docker image installed to generate the Guacamole-specific database schema. This SQL initialisation script populates the empty database with the schema to enable Guacamole to run as a web application supporting dynamic user profiles and server-connection data. From the Linux shell prompt, launch the Docker container in a one-shot fashion, running long enough to capture the Guacamole database schema in a text file and then exit.
docker run --rm guacamole/guacamole /opt/ guacamole/bin/initdb.sh --mysql > initdb.sql
With the database script created, we are ready to create the database objects in the empty Guacamole database. From the MYSQL prompt, source the SQL command or script file as such:
mysql>source /home/path/initdb.sql
To verify, issue the following MYSQL command:
SHOW TABLES;
The output of this command is nearly two dozen SQL tables that span entity (base table), user, user group, sharing, connection, connection group, and core
Guacamole system-related data. SQL tables guacamole_entity and guacamole_user persist the base set of user data. It is equally valuable to know that tables guacamole_connection and guacamole_ connection_parameter contain server-connection data.
Mash the Guacamole
The Docker images are provisioned and the backend database is prepared. Now we spin up the containers for the Guacamole proxy and the Tomcat-based Guacamole web app. The Docker link mechanism used here provides network addressability and connectivity between these two distinct runtime containers (without requiring the container to expose ports in an external configuration). To instantiate the container for the
Guacamole proxy and enable debug-level logging, use: docker run --name my-guac-proxy -e GUACD_LOG_
Level=debug -d guacamole/guacd
Verify the container is running with docker ps -a
Let’s launch the Guacamole web application as a container using the following syntax and arguments. The specified arguments bring together the key dependencies to run, namely the Guacamole proxy and the backend relational database. The Guacamole proxy does not require authentication, but our backend
database requires valid credentials. In a production configuration, you should use the native secret handling of the host environment to manage sensitive credentials (e.g., Azure Key Vault) and reference this secret rather than the cleartext that we’re using in our example. docker run --name my-guac-webapp --link my-guacproxy:guacd -d -p 8087:8080 -e MYSQL_ HOSTNAME=10.1.128.16 -e MYSQL_
Database=guacamole_db -e MYSQL_PORT=3306 -e Mysql_user=guacamole_user2 -e ‘MYSQL_ PASSWORD=GUA$AM0L3’ guacamole/guacamole
Once again, use the docker ps command to verify the running state of both containers. If any issues occur reach for the docker logs command, specify the running container id, and review recent log contents.
docker logs
The output of this command is dynamic and generally reflects the contents of a Tomcat application log. An additional check is possible from the database backend. To check, launch the MYSQL command prompt to log in and print the active DB connections, checking for the Guacamole DB user account. The command SHOW PROCESSLIST provides a full, raw dump of active connections, while this SELECT
statement filters on Guacamole DB users.
SELECT * FROM information_schema.processlist
WHERE `INFO` LIKE ‘%guac%’;
Having configured and verified connectivity with the backend database provider, you are now ready to access the admin interface.
You can begin to enjoy your Guacamole through the web admin interface. The admin interface provides a fast and easy way to add server connections for remote access. To access the admin interface, you must log in with a user profile that has the admin role. Out of the box, Guacamole offers the default user profile ‘guacadmin’ for initial login purposes. Of course, you should change the default admin profile! After a successful admin login, the top-level navigation presents access to active sessions, history, users, user groups, connections and connection groups, and properties. Figure 2 (see page 75) is a screen capture of the administrative Web UI.
Defining a new connection enables you to select the protocol type, namely SSH, RDP, or VNC. The selection of the remote protocol determines the visibility of fields. In the case of RDP, the key fields are hostname, port, username, and password. Figure 3 (see below) illustrates this type of web form input. Once saved, the connection entry appears in the connection list. It is important to note that this is not the context where you launch new sessions. Instead, this is where you edit or monitor connections and sessions.
The admin interface also provides a recent connection view. This view provides a thumbnail-like presentation of recent remote sessions.
Reverse it
To help secure your productive Guacamole web application infrastructure, consider introducing a reverse proxy. A reverse proxy offers several possible capabilities, including load balancing, caching, and termination of secure HTTP connections. Pairing Guacamole with a reverse proxy reduces the attack surface of the
Guacamole application layer and can allow for offloading of the SSL/TLS processing. In the configuration illustrated below, Nginx has a reverse proxy to offload TLS processing and terminate the secure connection. Nginx exchanges requests and responses with
Guacamole via the Docker bridge-networking configuration. Along the way, configuration steps are illustrated to roll-your-own Nginx and use Docker Compose to integrate three distinct runtime containers.
The basic Nginx configuration is the server block. Fundamental specifications within the server block include the listen and location directives. In the example below, the listening port of 443, along with location guacamole-web path is declared. The server instance binds to this port and location when starting up. server { listen 443 ssl;
.. location /guacamole-web/ {
proxy_pass http://guacamole:8080/guacamole/; ..
} }
Securing an HTTP connection requires a certificate and key. To generate a self-signed certificate and associated key files, a low-commitment approach that’s helpful in the evaluation phase, use the command-line tooling provided in the OPENSSL toolbox. The command-line syntax shown below generates the key and certificate files. Additional arguments included in this example specify expiration and key length. openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/guacamole-selfsigned.key -out /etc/ssl/certs/guacamole-selfsigned.crt
The dbparam file is also required as part of a secure HTTP server configuration. This file holds the set of Diffie-hellman (DH) parameters that includes p a large prime number applied in cryptographic operations. The command-line syntax to generate this auxiliary file is: openssl dhparam -dsaparam -out /etc/nginx/dhparam. pem 4096
With these files you are ready to define the Nginx secure server configuration. This type of configuration includes specifying the SSL certificate and related key values. Below is the assignment of configuration fields ssl_certificate and ssl_certificate_key. ssl_certificate /etc/ssl/certs/guacamole-selfsigned.crt; ssl_certificate_key /etc/ssl/private/guacamoleselfsigned.key;
The configuration for daparam in the Nginx secure server configuration is another SSL directive of Nginx.
ssl_dhparam /etc/nginx/dhparam.pem;
Guacamole has specific requirements for successful reverse-proxy communication over HTTP/HTTPS. Requirements include turning off buffering and properly specifying the browser cookie path. Below are the Nginx directives that control these settings:
proxy_buffering off; proxy_cookie_path /guacamole/ /new-path/;
The final Nginx configuration to highlight is the host specification. The location directive specifies the host, port, and path as part of the proxy_pass specification.
server { location /guacamole-web/ {
proxy_pass http://guacamole-web-app:8080/ guacamole/; }
} The Docker Compose specification illustrated below binds the hostname with the host value available at container runtime.
Rolling your own
The next step is to build a custom Docker image with the handcrafted configuration and include the certificate-related files. Rolling your own Nginx involves starting with the official Nginx Docker image and adding another layer. Base Docker images of Nginx available include Alpine and Debian. In the example below, I have derived from the Alpine base Docker image. This image weighs in at 21.8MB. To begin, add another layer to this
Docker image using the FROM keyword.
FROM nginx:alpine
To add files to your custom layer, code the Docker file to copy in the certificate files as well as your customised configuration. The COPY command will do the work.
COPY guacamole-selfsigned.crt /etc/ssl/certs/ COPY guacamole-selfsigned.key /etc/ssl/private/ COPY dhparam.pem /etc/nginx/
COPY nginx.conf /etc/nginx/conf.d/nginx.conf
Build your custom Docker image as such:
docker build -f Dockerfile -t roll-your-own-nginx/ my-nginx-reverse-proxy .
The last step is to use the docker-compose
command to spin-up and link the containers at runtime. docker-compose is based on a Docker-centric YAML file to specify what captures this multi-container configuration. The primary constructs needed to run
Guacamole in a multi-container arrangement are network and services. In the fragment below, define three services: nginx-reverse-proxy, guacamole-webapp and the guacd-proxy. docker-compose processes this file, sets up the backend network, and instantiates the services as part of the Docker environment. A userdefined network facilitates communication between two containers instead of the link mechanism. The Docker team, while technically the supporting link, rather encourages the use of user-defined networks for container-to-container communication. networks: gnetwork:
driver: bridge services: nginx-reverse-proxy: depends_on:
- guacamole-web-app links:
- guacamole-web-app gnetwork: guacamole-web-app: depends_on:
- guacd-proxy environment: links:
- guacd-proxy networks: gnetwork: guacd-proxy: networks: gnetwork:
To run the containers together, use the Docker compose command and specify the up argument. docker-compose –d up
This command processes the YAML file and uses the Docker command primitives first introduced in this article to bring the Docker images to life as containers. In this case, container nginx-reverse-proxy has a dependency on guacamole-web-app, and container guacamole-web-app has a dependency on guacdproxy. docker-compose uses these declared relationships to determine the order by which to start containers. You can check the status of the running container using docker ps. After docker-compose up
has completed, log in to Guacamole by pointing your Web browser at https://myhost:/guacamole-web and use the credentials of guacadmin.
Spreading Guacamole over a Docker infrastructure has a short prep time and more enjoyment!