What is Kasm?
In October 2020 I wrote an article about an interesting bit of software called KASM
https://tech.davidfield.co.uk/kasm-a-secure-computing-platform/
Kasm is software, based on Docker which provides a Web interface to run Desktop Apps in a sandboxed container. As well as apps KASM also provides access to desktops, out of the Box is (at the time of writing) an Ubuntu 18.04 or CentOS7 Desktop.
These applications run from a remote server, however, they appear to be running from your desktop.

I do not work for Kasm, I make no money from Kasm, I’m blogging because I like it and have figured out how to do some interesting things with it.
Where does it fit in an Infrastructure?
It’s possible since lockdown started your company has started using remote desktops in one form or another the usual suspects are Citrix or Microsoft Remote Applications however, VMware also provide Horizon as a well-known alternative.
These solutions have the single premise of being able to supply you with the applications you use day to day while keeping the company’s data on their servers. On paper at least the IT support team only have to support the desktops in the cloud, not your Laptop so costs are reduced, support and updates get rolled out quicker, and instead of needing to do a regular laptop refresh the servers these systems sit on are updated at a possibly cheaper price.
This is true remote cloud computing enables companies to reduce hardware costs and provide a consistent desktop experience for all staff.
The problem is this method of Virtual Desktops can get expensive if you host it on your own or if you run off Amazon Workspaces or an equivalent service.
The hardware is not cheap, the licensing isn’t cheap and the initial outlay requires a lot of funding.
Where KASM seems to fit in is that it’s supplying the applications you know VSCode, Teams, Only Office, etc based on a Linux environment, and it’s providing them backed out by Docker, so each application runs in its own sandbox meaning if you were to get something nasty running in your desktop or application, it affects only you.
Admittedly the fact that this is based on Linux is possibly enough to put most sysadmins off entirely. However, if you work in a place or need access to common applications which people are used to using then actually this may not be so much of a problem. Linux takes fewer resources in KASM than Windows on Citrix/Horizon etc and there are no license costs for the OS.
So if you run an SMB and are interested to see how VDI could help your workforce, or run a home lab and want access to applications on a server which you can run and leave open and come back to later from any device with a web browser. This may be something you are interested in.
Installing KASM
I outlined the installation instructions in the previous post, the instructions are also found here:

As a quick recap, what I’m running here is a single server instance, so everything I need is on one server,
I’m using Ubuntu 20.04 server (incidentally this OS is running on a MacBookPro natively) with 16Gb Ram

There is also a far more resilient multi-server install available.

Download the latest version of KASM

Run the following
cd /tmptar -xf kasm_release*.tar.gzsudo bash kasm_release/install.sh
There is a good video on the KASM Docs site which runs through the Install
At the end of the install, you’ll be provided several logins
SAVE THESE PASSWORDS IN YOUR PASSWORD SAFE
Login as admin@kasm.local using https:////serveripaddress for example https://192.168.1.222
This should provide a KASM desktop that looks as follows

Change the passwords.
Making the install External Facing
For my setup, I was looking to have access from the internet to my KASM server, before I opened this up I needed to do a few things
1) Enable HTTPS access from my NGINX reverse proxy
2) Implement SSL Cert Checking
3) Enable 2FA on KASM
While not perfect this is strength in-depth and offers some protection.
External site: kasm.example.com
Internal server IP: 192.168.1.222
Reverse Proxy
I run a failover NGINX reverse proxy, in which each service is associated with its own config file in /etc/nginx/sites-enabled with this in mind my Kasm reverse proxy config looks like this
server {server_name kasm.example.com; location / { proxy_pass https://192.168.1.222; # WebSocket Support proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # Host and X headers proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # Connectivity Options proxy_http_version 1.1; proxy_read_timeout 1800s; proxy_send_timeout 1800s; proxy_connect_timeout 1800s; proxy_buffering off;# Allow large requests to support file uploads to sessions client_max_body_size 10M; }client_max_body_size 50m;listen 443;}server {server_name kasm.example.com;listen 80;return 404; # managed by Certbot}
On its own, this is not a secure config because I need to add the SSL certs which is done using Letsencrypt.
LetsEncrypt
To install certbot a tool for working with LetEncrypt run the following
sudo apt install certbot python3-certbot-nginx
Then run
sudo certbot --nginx -d kasm.example.com
A series of tests will run and as long as your external network has been set up to see the reverse proxy using the config above on the domain name kasm.example.com you’ll be asked to update the Nginx config and redirect port 80 to port 443 which will update the Nginx config file as follows
server {server_name kasm.example.com; location / { proxy_pass https://192.168.1.222; # WebSocket Support proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # Host and X headers proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # Connectivity Options proxy_http_version 1.1; proxy_read_timeout 1800s; proxy_send_timeout 1800s; proxy_connect_timeout 1800s; proxy_buffering off; # Allow large requests to support file uploads to sessions client_max_body_size 10M; }client_max_body_size 50m;listen 443 ssl; # managed by Certbotssl_certificate /etc/letsencrypt/live/kasm.example.com/fullchain.pem; # managed by Certbotssl_certificate_key /etc/letsencrypt/live/kasm.example.com/privkey.pem; # managed by Certbotinclude /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbotssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot}server { if ($host = homeoffice.safewebbox.com) { return 301 https://$host$request_uri;} # managed by Certbotserver_name kasm.example.com;listen 80;return 404; # managed by Certbot}
The lines added are marked with # managed by Certbot
listen 443 ssl; # managed by Certbotssl_certificate /etc/letsencrypt/live/kasm.example.com/fullchain.pem; # managed by Certbotssl_certificate_key /etc/letsencrypt/live/kasm.example.com/privkey.pem; # managed by Certbotinclude /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbotssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
and the redirect to HTTPS section
server { if ($host = homeoffice.safewebbox.com) { return 301 https://$host$request_uri;} # managed by Certbotserver_name kasm.example.com;listen 80;return 404; # managed by Certbot}
Check this works by accessing
https://kasm.example.com
If it does, move forward, if not check /var/logs/nginx/ for help
SSL Cert check
The next step is to add a check, the reverse proxy will check if a certificate is available on a client before it displays the page. No certificate on the client device and there are loading errors.
First, let’s create a directory for the certificates
sudo mkdir /etc/nginx/clients_certscd /etc/nginx/clients_certs
Next, create a certificate using OpenSSL
openssl genrsa -des3 -out ca.key 4096openssl req -new -x509 -days 3650 -key ca.key -out ca.crtopenssl genrsa -des3 -out user.key 4096openssl req -new -key user.key -out user.csropenssl x509 -req -days 365 -in user.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out user.crt
During the above process, you’ll be asked for a CA and Cert password, and also for detail about the certificate. Keep a note of the passwords in your password safe.
Export a PFX certificate for Client machines
openssl pkcs12 -export -out user.pfx -inkey user.key -in user.crt -certfile ca.crt
You’ll be asked for an export password.. this password will be asked each time you import the certificate into a client.
Put the user.pfx file into somewhere clients can access it.
Under the Certbot lines in the Nginx config file add
ssl_client_certificate /etc/nginx/client_certs/ca.crt;ssl_verify_client on;
The final output looks like this
server {server_name kasm.example.com; location / { proxy_pass https://192.168.1.222; # WebSocket Support proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # Host and X headers proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # Connectivity Options proxy_http_version 1.1; proxy_read_timeout 1800s; proxy_send_timeout 1800s; proxy_connect_timeout 1800s; proxy_buffering off; # Allow large requests to support file uploads to sessions client_max_body_size 10M; }client_max_body_size 50m;listen 443 ssl; # managed by Certbotssl_certificate /etc/letsencrypt/live/kasm.example.com/fullchain.pem; # managed by Certbotssl_certificate_key /etc/letsencrypt/live/kasm.example.com/privkey.pem; # managed by Certbotinclude /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbotssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbotssl_client_certificate /etc/nginx/client_certs/ca.crt;ssl_verify_client on;}server { if ($host = homeoffice.safewebbox.com) { return 301 https://$host$request_uri;} # managed by Certbotserver_name kasm.example.com;listen 80;return 404; # managed by Certbot}
Restart Nginx
Install the Client Cert
On each client that will access https://kasm.external.com now import the PFX file into the cert store and ensure is trusted.
Further Reading: https://www.tbs-certificates.co.uk/FAQ/en/installer_certificat_client_google_chrome.html
Now when you access https://kasm.example.com you’ll be prompted to confirm a certificate and then provided access to the KASM login page.
Enable 2FA
The final item to enable is 2 Factor Authentication, and to use this you’ll need your clients to have access to a 2FA app like Authy
Login to Kasm as Admin
Open Groups

Select All users (or the group you want to use 2FA) then click on the triple-dot thingy at the end of the row and choose View

Scroll down to group settings and click on Add settings

Select enable_totp_two_factor and select true is asked

Enable this option and now all users in this group will need to enable 2FA on first login.

From the client’s perspective, this is scanning a QR code with the 2FA code app of choice on their mobile.
What have we done?
In this section, we learned how to
- Install KASM
- Setup a Reverse proxy
- Access the reverse proxy over Letsencrypt HTTPS
- Add a client certificate for security
- Enable 2FA for all users.
Applications
When you first log in to Kasm there are a list of preinstalled applications from the Community

These are split into two types of app ones that open as applications in the browser and Desktop applications that provide a full Ubuntu 18.04 or CentOS 7 Desktop (using XFCE) all within a browser window.
A standalone application might look like this

The full desktop would look like this

What happens if the application you want isn’t available or you’d like a more up to date Desktop (like Ubuntu 20.04)
Well firstly reach out to the community, however, because this is docker-based, it’s actually not that hard to create your own app or desktop containers.
Kasm Documentation has this covered here

Note I’m doing the following on a VM running Ubuntu 20.04 AMD64 as I found out that if i do this on my MBP M1, it uses ARM64 files
Creating a Rocket Chat Image
I wanted to create a version of Rocket.Chat desktop client for KASM, because it’s docker based it’s not too hard to build the image.
In this example the base image will be the Ubuntu Bionic Desktop so the full desktop will open, and Rocket chat will be available under the start menu.
I created a Dockerfile and added this
FROM kasmweb/core-ubuntu-bionic:1.9.0USER rootENV HOME /home/kasm-default-profileENV STARTUPDIR /dockerstartupENV INST_SCRIPTS $STARTUPDIR/installWORKDIR $HOME######### Customize Container Here ###########RUN wget https://github.com/RocketChat/Rocket.Chat.Electron/releases/download/3.2.3/rocketchat_3.2.3_amd64.debRUN apt install -y gdebi-coreRUN gdebi -n rocketchat_3.2.3_amd64.debRUN chmod 4755 /opt/Rocket.Chat/chrome-sandboxRUN sed -i 's+Exec=/opt/Rocket.Chat/rocketchat-desktop %U+Exec=/opt/Rocket.Chat/rocketchat-desktop %U --no-sandbox+g' /usr/share/applications/rocketchat-desktop.desktop RUN cat /usr/share/applications/rocketchat-desktop.desktop######### End Customizations ###########RUN chown 1000:0 $HOMERUN $STARTUPDIR/set_user_permission.sh $HOMEENV HOME /home/kasm-userWORKDIR $HOMERUN mkdir -p $HOME && chown -R 1000:0 $HOMEUSER 1000
Most of it has been lifted from the Kasm Documentation, however, the following was added to install Rocket.Chat
RUN wget https://github.com/RocketChat/Rocket.Chat.Electron/releases/download/3.2.3/rocketchat_3.2.3_amd64.debRUN apt install -y gdebi-coreRUN gdebi -n rocketchat_3.2.3_amd64.debRUN chmod 4755 /opt/Rocket.Chat/chrome-sandboxRUN sed -i 's+Exec=/opt/Rocket.Chat/rocketchat-desktop %U+Exec=/opt/Rocket.Chat/rocketchat-desktop %U --no-sandbox+g' /usr/share/applications/rocketchat-desktop.desktop RUN cat /usr/share/applications/rocketchat-desktop.desktop
This block of code does the following
- Pulls down the Rocket Chat Deb File from the Git Releases page
- Install Gdebi-core because it installs any additional requirements when installing a deb
- install the rocket chat deb file
- Change the permission on the sandbox
- Change the .desktop file Exec line to have –no-sandbox at the end as you can’t run this feature in a container. (note I’ve used + as the sed delimiter)
- Check the sed worked.
Save this file
Build the image
sudo docker build -t mightywomble/rocketchat:example -f Dockerfile .
This will take a while and is pretty verbose so if it fails you’ll know why. It’s building a new docker image within a container.
View the file using
sudo docker image ls
will show something like this
REPOSITORY TAG IMAGE ID SIZEmightywomble/rocketchat 1.0.2 ab43b6395a2a 1.61GBmightywomble/rocketchat 1.0.1 b8f868e68449 1.61GBmightywomble/rocketchat 1.0.0 ddb563952e03 1.61GBmightywomble/rocketchat example 65c0005bf8ac 3.13GB
Once complete I upload it to my docker hub (free version)
docker login
docker push mightywomble/rocketchat:example
This again will take a while

The next step is to upload the docker image to the Kasm Agent
Login to Kasm as an administrator
In the Admin section click on Images

Find another Desktop App and select Clone

Fill in at least the following.

Provide the docker image name, the URL for the Icon does work as well.

Scroll down

Change the Catagories as needed.

Click on Submit
Head over to workspaces

Under Chat (because I added it as a category) is Rocket Chat
It may take a little while for your KASM agent to pull the image off the docker hub. While it is doing that there will be an orange triangle on the Icon above

Confirm the session launch
A loading screen will appear
Once the Desktop has loaded Open the Menu and head to the Internet

Launch Rocket Chat

Amazing…
What have we done?
So creating a Kasm image is basically docker..
- Created a Dockerfile
- Built an Image
- Uploaded an Image to DockerHub
- Created an Image Template in Kasm
- Pulled the image onto our Kasm server
- Run the Application
Creating a Focal Core Image
The next thing I wanted to do was see if it was possible to create a more up to date Ubuntu Desktop image, So I’ve built a 20.04 (Focal) Image
I have to say Justin Travis and the support even at the Kasm Community level are really helpful here. This is the working information from the following ticket
If you really really wanted to make a Core image based on Focal you could give it a shot by cloning and updating this repo https://github.com/kasmtech/workspaces-core-images.
git clone https://github.com/kasmtech/workspaces-core-images.git
Generally speaking trying to create a custom Core image for a different distro will challenging, but moving from ubuntu 18.04 to 20.04 may be straight forward since we already have a build of KasmVNC available for it.
Here are some places to start looking but this isn’t something we can officially support – so you are largely on your own.
- Change the
BASE_IMAGE
ubuntu:20.04
https://github.com/kasmtech/workspaces-core-images/blob/develop/dockerfile-kasm-core#L1
nano dockerfile-kasm-core
Change the first line of the file from
ARG BASE_IMAGE="ubuntu:18.04"
to
ARG BASE_IMAGE="ubuntu:20.04"
- You likely need to set
START_XFCE4=1
andSTART_PULSEAUDIO=1
or pass it them in as a build argument https://github.com/kasmtech/workspaces-core-images/blob/develop/dockerfile-kasm-core#L22
Scroll down to the Environmental config section and change
ARG START_XFCE4=0ARG START_PULSEAUDIO=0
to
ARG START_XFCE4=1ARG START_PULSEAUDIO=1
- You may need to comment out the cursor updates https://github.com/kasmtech/workspaces-core-images/blob/develop/dockerfile-kasm-core#L102,L103
Comment out the following section
### Install custom cursors#COPY ./src/ubuntu/install/cursors $INST_SCRIPTS/cursors/#RUN bash $INST_SCRIPTS/cursors/install_cursors.sh && rm -rf $INST_SCRIPTS/cursors/
Save this file and exit
- You can update the KasmVNC install script to install the “focal” .deb instead of the “bionic” . just swap the name https://github.com/kasmtech/workspaces-core-images/blob/develop/src/ubuntu/install/kasm_vnc/install_kasm_vnc.sh#L13
Change the line in src/ubuntu/install/kasm_vnc/install_kasm/vnc.sh to pull down the focal version of the VNC file.
BUILD_URL="https://kasmweb-build-artifacts.s3.amazonaws.com/kasmvnc/ec6bd697a8785e2f3ed82cafd3b6a4c47fa43491/kasmvncserver_bionic_0.9.3_master_ec6bd6_amd64.deb"
to
BUILD_URL="https://kasmweb-build-artifacts.s3.amazonaws.com/kasmvnc/ec6bd697a8785e2f3ed82cafd3b6a4c47fa43491/kasmvncserver_centos_core_0.9.3_master_ec6bd6_x86_64.rpm"
The latest release of the VNC is found at

I also updated the install section of the file to use gdebi not dpkg because dpkg wasn’t picking up dependencies.
apt-get updateapt-get install -y gettext ssl-cert gdebi-coregdebi --n /tmp/kasmvncserver.debrm -f /tmp/kasmvncserver.deb
Save and exit
Build the image
sudo docker build -t mightywomble/focal:1.9.1 -f dockerfile-kasm-core .
Once build, push to dockerhub
docker push mightywomble/focal:1.9.1
Back in Kasm clone the existing Ubuntu Desktop Image

Point the Docker image to your Docker Image
Update the Names
I also updated the memory
Save and let the Kasm agent download the image
Head over to the Kasm Workspaces

Launch Ubuntu Focal

And Bingo we have Ubuntu 20.04 XFCE Desktop

What have we done?
- We expanded on building an application
- We edited the code for the 18.04 core build
- We rebuilt the image
- We uploaded it to Kasm via Docker Hub
- We tested the image.
What’s Next
Knowing how to create a focal desktop, the next stage is to rebuild the apps I use for Ubuntu Focal and set up my desktop. It’s possible to point the focal image to use my home DNS (which has some additional security features) and my own background. this is covered under Howto Guides: https://kasmweb.com/docs/latest/how_to.html
At which point Kasm 2 will probably release and it will be done for me 🙂
Thoughts
I love this, I use this, I think this is great. It’s easy to set up, the single-server version is found for home lab use. I love that I can create my own images quickly for apps and I can see huge potential for this software just as I could a year ago.
As users become less desktop needy and are happy to just use the apps, the platform they are served on doesn’t need to be Windows and costs start to go down.
References


