CyberArk HTML5 Gateway and Docker Compose

Photo by Ian Taylor on Unsplash

CyberArk HTML5 Gateway and Docker Compose

Deployment of CyberArk's HTML5 Gateway can be made trivial thanks to it being provided as a Docker image but running the container with all the necessary arguments at runtime can quickly become a headache.

With everything that needs defined as part of the docker run command, forgetting an argument or mistyping a configuration becomes almost inevitable. It can get even more complex when there are multiple HTML5 Gateways deployed among multiple environments and trying to ensure they are all configured the same way.

sudo docker run --restart unless-stopped -ti -d -p 443:8443 -v /opt/cert/:/opt/import:ro --cap-drop=all --cap-add={CHOWN,DAC_OVERRIDE,FOWNER,SETGID,SETUID} -e AcceptCyberArkEULA=yes -e GWCert=psmgw.crt -e GWKey=psmgw.key -e GWCAFile=rootCA.crt -e EndPointAddress=https://<PVWA hostname>/passwordvault --name <PSM gateway FQDN> cahtml5gw:11_06_0_8 -e

An example docker run command taken straight from CyberArk's documentation. This single command can get even longer if you want to configure the HTML5GW further.

Using Docker Compose we can represent that same command in a .YAML file, allowing easy management of how the container is configured.

What is Docker Compose and how to get it?

Taken straight from the Compose website, it '...is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration.' The HTML5 Gateway runs as a single-container Docker application but we can still get value out of defining using a Compose file to manage the HTML5GW.

Compose can be installed on the HTML5GW by simply downloading the binary or even as a container.

[tim@html5gw ~]$  sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   664  100   664    0     0   9352      0 --:--:-- --:--:-- --:--:--  9352
100 12.1M  100 12.1M    0     0   9.9M      0  0:00:01  0:00:01 --:--:-- 12.4M
[tim@html5gw ~]$ sudo chmod +x /usr/local/bin/docker-compose
[tim@html5gw ~]$ sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
[tim@html5gw ~]$ docker-compose version
docker-compose version 1.29.2, build 5becea4c
docker-py version: 5.0.0
CPython version: 3.7.10
OpenSSL version: OpenSSL 1.1.0l  10 Sep 2019
[tim@html5gw ~]$

Downloading and 'installing' the binary.

Defining a Compose file based on an existing docker run command

With Compose successfully installed we can start with creating the Compose file.

For this post, we will work with the following docker run command: docker run --restart unless-stopped -ti -p 443:8443 -v /opt/cert:/opt/import:ro -d --cap-drop=all --cap-add={CHOWN,DAC_OVERRIDE,FOWNER,SETGID,SETUID} -e AcceptCyberArkEULA=yes -e EnableJWTValidation=no -e IgnorePSMCertificateErrors=yes --name html5gw cahtml5gw:11_05_3_15

First, lets make a folder to store our Compose file in. In this example, we will do it under our home directory but when working with other team members it makes sense to put it in a shared location where everyone can access the compose file in order to start, stop, and re-configure the HTML5GW.

[tim@html5gw ~]$ mkdir docker-html5gw
[tim@html5gw ~]$ cd docker-html5gw
[tim@html5gw docker-html5gw]$

Now we create our Compose file and name itdocker-compose.yml. Naming it docker-compose.yml, when we bring up and take down the container via Compose, we won't have to specify the file in the docker-compose command as long as our current working directory is the one with our Compose file.

[tim@html5gw docker-html5gw]$ touch docker-compose.yml
[tim@html5gw docker-html5gw]$ vi docker-compose.yml

Using the Compose file version 3 reference, we end up with something like this:

version: '3.8'
services:
    cahtml5gw:
        container_name: html5gw
        image: cahtml5gw:11_05_3_15
        environment:
            - AcceptCyberArkEULA=yes
            - EnableJWTValidation=no # Just for test purposes
            - IgnorePSMCertificateErrors=yes # Just for test purposes
        ports:
            - '443:8443'
        volumes:
            - '/opt/cert:/opt/import:ro'
        restart: unless-stopped
        cap_drop:
            - ALL
        cap_add:
            - CHOWN
            - DAC_OVERRIDE
            - FOWNER
            - SETGID
            - SETUID

Compared to our docker run command, this is way easier to read. It even gives us the opportunity to comment within to explain to others (or in the future, ourselves) why things are configured the way they are.

Starting and stopping the HTML5GW with Compose

With our Compose file created we only need to pass two arguments to Compose:

[tim@html5gw docker-html5gw]$ sudo docker-compose up -d
Creating network "docker-html5gw_default" with the default driver
Creating html5gw ... done
[tim@html5gw docker-html5gw]

The -d argument does the same thing when passed to docker run -- Compose starts the container in the background.

We verify the container is running and view logs the same way as before:

[tim@html5gw docker-html5gw]$ sudo docker ps
CONTAINER ID   IMAGE                 COMMAND                  CREATED              STATUS              PORTS                                     NAMES
58f67b6b9f74   cahtml5gw:11_05_3_15   "/bin/sh -c '/opt/PS…"   About a minute ago   Up About a minute   0.0.0.0:443->8443/tcp, :::443->8443/tcp   html5gw
[tim@html5gw docker-html5gw]$ sudo docker logs -n 15 html5gw
SUCCESS: Successfully imported certificate into the Java keystore
INFO: Updating Guacamole server TLS configuration
SUCCESS: Guacamole server TLS configuration updated
INFO: Securing RDP traffic to PSM.
WARNING: No trusted PSM certificate supplied via the 'PSMCert' argument. Certificate verification warnings will be ignored.
Changing shell for tomcat.
Shell changed.
Changing shell for psmgwuser.
Shell changed.
Tomcat started.
guacd[152]: INFO:       Guacamole proxy daemon (guacd) version 1.0.0 started
guacd[152]: INFO:       Communication will require SSL/TLS.
guacd[152]: INFO:       Using PEM keyfile /opt/secrets/guacdKey.pem
guacd[152]: INFO:       Using certificate file /opt/secrets/guacdCert.crt
guacd[152]: INFO:       Listening on host 127.0.0.1, port 4822
[tim@html5gw docker-html5gw]$

Stopping the container is just as easy:

[tim@html5gw docker-html5gw]$ sudo docker-compose stop
Stopping html5gw ... done
[tim@html5gw docker-html5gw]$ sudo docker ps -a
CONTAINER ID   IMAGE                  COMMAND                  CREATED              STATUS                       PORTS     NAMES
79efa107d793   cahtml5gw:11_05_3_15   "/bin/sh -c '/opt/PS…"   About a minute ago   Exited (137) 5 seconds ago             html5gw
[tim@html5gw docker-html5gw]$

Configuring the HTML5GW with Compose

Configuring the container is done by changing the Compose file. For testing purposes, we configured our HTML5GW to use self-signed certificates, disabled JWT validation and ignore any PSM certificate errors. Lets configure the container for a more production environment-appropriate deployment:

version: '3.8'
services:
    cahtml5gw:
        container_name: html5gw
        image: cahtml5gw:11_05_3_15
        environment:
            - AcceptCyberArkEULA=yes
            - EndPointAddress=https://comp01/passwordvault # Needed for JWT validation
            - GWCert=html5gw01.crt # The certificate for the HTML5GW 
            - GWKey=html5gw01.key # The private key for the HTML5GW certificate
            - GWCAFile=rootca.crt # The root CA's certificate
        ports:
            - '443:8443'
        volumes:
            - '/opt/cert:/opt/import:ro'
        restart: unless-stopped # On restart of the docker daemon (including restart of the server) thee container will start again unless explicity stopped with docker-compose down
        cap_drop:
            - ALL
        cap_add:
            - CHOWN
            - DAC_OVERRIDE
            - FOWNER
            - SETGID
            - SETUID

We run docker-compose up -d again and the container is recreated using our signed certificates and JWT validation enabled:

[tim@html5gw docker-html5gw]$ vi docker-compose.yml
[tim@html5gw docker-html5gw]$ docker-compose up -d
Recreating html5gw ... done
[tim@html5gw docker-html5gw]$ sudo docker ps -a
CONTAINER ID   IMAGE                 COMMAND                  CREATED         STATUS         PORTS                                     NAMES
c98b0634404c   cahtml5gw:11_05_3_15   "/bin/sh -c '/opt/PS…"   8 seconds ago   Up 8 seconds   0.0.0.0:443->8443/tcp, :::443->8443/tcp   html5gw
[tim@html5gw docker-html5gw]

Upgrading the HTML5GW with Compose

Upgrading is just as easy. After loading the latest HTML5GW Docker image we change the tag defined in the image value in docker-compose.yml:

version: '3.8'
services:
    cahtml5gw:
        container_name: html5gw
        image: cahtml5gw:12_00_3_3
        environment:
            - AcceptCyberArkEULA=yes
            - EndPointAddress=https://comp01/passwordvault # Needed for JWT validation
            - GWCert=html5gw01.crt # The certificate for the HTML5GW 
            - GWKey=html5gw01.key # The private key for the HTML5GW certificate
            - GWCAFile=rootca.crt # The root CA's certificate
        ports:
            - '443:8443'
        volumes:
            - '/opt/cert:/opt/import:ro' # Used by HTML5GW to find the files defined in GWCert,GWKey, and GWCAFile
        restart: unless-stopped # On restart of the docker daemon (including restart of the server) thee container will start again unless explicity stopped with docker-compose down
        cap_drop:
            - ALL
        cap_add:
            - CHOWN
            - DAC_OVERRIDE
            - FOWNER
            - SETGID
            - SETUID

And like before we run docker-compose up -d to recreate the container based on the new tag:

[tim@html5gw docker-html5gw]$ sudo docker-compose up -d
Recreating html5gw ... done
[tim@html5gw docker-html5gw]$ sudo docker ps
CONTAINER ID   IMAGE                 COMMAND                  CREATED         STATUS         PORTS                                     NAMES
a49342a80ccf   cahtml5gw:12_00_3_3   "/bin/sh -c '/opt/PS…"   3 minutes ago   Up 3 minutes   0.0.0.0:443->8443/tcp, :::443->8443/tcp   html5gw
[tim@html5gw docker-html5gw]$

More possibilities using Compose

With the HTML5GW being configured through the Compose file, more possibilities open up. We can store our Compose file in Git, having any changes to the file done via commits. Deploying changes can be as simple as running two commands: git pull and docker-compose up -d. We could even leverage CI/CD to have our new configurations deployed across all HTML5GWs when a commit is merged into the master branch!