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!