How to configure kasm in Oracle cloud

In this post, we will see what are the steps to install a kasm workspace within a machine in Oracle Cloud to have a free install that we can use to play, the stack is

  • OS Oracle Linux 8
  • CPU ARM64 16GB RAM 100GB HDD
  • Kasm 1.5
  • docker + docker-compose
  • iptables
  • cerbot for encryption

Creation of VM

The first step is to create the VM where everything will be installed, important notes, to make the installation free we need to constrain our VM to only free resources, we will not use block volume because that costs depend on the availability zone, that means we can incur in costs if the availability domain does not have “free” block volume available or if the VM is created in a different domain than the block volume

Notice that in boot volume we choose “Specify a custom boot volume” and we specify 100GB

After the VM creation is finished we can go to the instances and inspect the storage, it will have the label aways free

Then we will setup the firewall rules, specifically the firewall to open the 80 and 433 ports

with this we finish with the VM setup, the next step is to configure the DNS to point to our VM

DNS A record creation

we create a new “A” record that points to the public IP of the machine we just configured

A record kasm pointing to 150.33.33.33
kasm.example.com

do not attempt to enter to the domain yet as it will not do anything yet, we need to install the service

Extend the current disk partition

By default the boot partition will only take the first 46GB of disk space and since we have a 100GB we want to use the rest, otherwise the installation will fail.

The disk partition looks like this before starting

[opc@kasm-vm-vnic ~]$ df -h
Filesystem                  Size  Used Avail Use% Mounted on
devtmpfs                    7.3G     0  7.3G   0% /dev
tmpfs                       7.3G     0  7.3G   0% /dev/shm
tmpfs                       7.3G   18M  7.3G   1% /run
tmpfs                       7.3G     0  7.3G   0% /sys/fs/cgroup
/dev/mapper/ocivolume-root   36G   12G   25G  32% /
/dev/mapper/ocivolume-oled   10G  160M  9.8G   2% /var/oled
/dev/sda2                   924M  585M  340M  64% /boot
/dev/sda1                   100M  7.2M   93M   8% /boot/efi
tmpfs                       1.5G     0  1.5G   0% /run/user/1000
tmpfs                       1.5G     0  1.5G   0% /run/user/986
[opc@kasm-vm-vnic tmp]$ sudo lsblk
NAME               MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
loop0                7:0    0 33.7M  1 loop /var/lib/snapd/snap/snapd/21761
loop1                7:1    0 59.8M  1 loop /var/lib/snapd/snap/core20/2321
loop2                7:2    0 42.9M  1 loop /var/lib/snapd/snap/certbot/3832
loop3                7:3    0   92M  1 loop /var/lib/snapd/snap/core/17201
sda                  8:0    0  100G  0 disk 
├─sda1               8:1    0  100M  0 part /boot/efi
├─sda2               8:2    0    1G  0 part /boot
└─sda3               8:3    0 45.5G  0 part 
  ├─ocivolume-root 252:0    0 35.5G  0 lvm  /
  └─ocivolume-oled 252:1    0   10G  0 lvm  /var/oled

only about 35GB are utilized, we can reclaim another 66GB, the default partition type is XFS we only have one device /dev/sda and 3 partitions, we will create a new partition /dev/sd4 that we will use to extend the logical volume ocivolume-root

###Step 1: Create a New Partition
#Launch fdisk on your disk:
sudo fdisk /dev/sda

#Create a new partition:

#Type n to create a new partition.
#Select the default options to use the remaining space.
#Write the changes to the disk by typing w.

###Step 2: Create a Physical Volume
#Create a physical volume on the new partition:
sudo pvcreate /dev/sda4

###Step 1: Extend the Logical Volume
#Extend your volume group to include the new physical volume:
#First, extend the logical volume to use the free space:
sudo lvextend -l +100%FREE /dev/mapper/ocivolume-root

###Step 2: Resize the XFS Filesystem
#Then, resize the XFS filesystem:
sudo xfs_growfs /

#This command will grow the XFS filesystem to use the newly allocated space. Here’s the complete process:
#Extend the logical volume:
sudo lvextend -l +100%FREE /dev/mapper/ocivolume-root

#This command will extend the logical volume to use all available free space.
sudo xfs_growfs /





This command will grow the filesystem to occupy the new space added to the logical volume.

After running these commands, you should see the additional space available on your root filesystem.

[opc@kasm-vm-vnic tmp]$ sudo lsblk
NAME               MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
loop0                7:0    0 33.7M  1 loop /var/lib/snapd/snap/snapd/21761
loop1                7:1    0 59.8M  1 loop /var/lib/snapd/snap/core20/2321
loop2                7:2    0 42.9M  1 loop /var/lib/snapd/snap/certbot/3832
loop3                7:3    0   92M  1 loop /var/lib/snapd/snap/core/17201
sda                  8:0    0  100G  0 disk 
├─sda1               8:1    0  100M  0 part /boot/efi
├─sda2               8:2    0    1G  0 part /boot
├─sda3               8:3    0 45.5G  0 part 
│ ├─ocivolume-root 252:0    0 88.9G  0 lvm  /
│ └─ocivolume-oled 252:1    0   10G  0 lvm  /var/oled
└─sda4               8:4    0 53.4G  0 part 
  └─ocivolume-root 252:0    0 88.9G  0 lvm  /

[opc@kasm-vm-vnic tmp]$ df -h
Filesystem                  Size  Used Avail Use% Mounted on
devtmpfs                    7.3G     0  7.3G   0% /dev
tmpfs                       7.3G     0  7.3G   0% /dev/shm
tmpfs                       7.3G   18M  7.3G   1% /run
tmpfs                       7.3G     0  7.3G   0% /sys/fs/cgroup
/dev/mapper/ocivolume-root   89G   34G   56G  38% /         # <----------------------- now is 89GB
/dev/mapper/ocivolume-oled   10G  160M  9.8G   2% /var/oled
/dev/sda2                   924M  585M  340M  64% /boot
/dev/sda1                   100M  7.2M   93M   8% /boot/efi
tmpfs                       1.5G     0  1.5G   0% /run/user/1000
tmpfs                       1.5G     0  1.5G   0% /run/user/986
/dev/loop0                   34M   34M     0 100% /var/lib/snapd/snap/snapd/21761
/dev/loop1                   60M   60M     0 100% /var/lib/snapd/snap/core20/2321
/dev/loop2                   43M   43M     0 100% /var/lib/snapd/snap/certbot/3832
/dev/loop3                   93M   93M     0 100% /var/lib/snapd/snap/core/17201

bellow is the same code with like a script that you run with root

# Create a new partition using fdisk
sudo fdisk /dev/sda <<EOF
n
p
4


t
4
8e
w
EOF

# Inform the OS of partition table changes
sudo partprobe /dev/sda

# Create a physical volume on the new partition
sudo pvcreate /dev/sda4

# Extend the volume group to include the new physical volume
sudo vgextend ocivolume /dev/sda4

# Extend the logical volume to use all the free space
sudo lvextend -l +100%FREE /dev/mapper/ocivolume-root

# Resize the XFS filesystem to use the new space
sudo xfs_growfs /

Install EPEL and update the machine

# update the machine
sudo dnf update -y

# install epel repo
dnf config-manager --enable ol8_developer_EPEL

# install utilities
sudo dnf install htop iotop curl -y

# disable firewalld
sudo systemctl stop firewalld
sudo systemctl disable firewalld

# install snap
sudo dnf install -y snapd
sudo systemctl enable snapd.socket
sudo systemctl start snapd.socket
sudo ln -s /var/lib/snapd/snap /snap
sudo snap install core
sudo snap refresh core

Docker Install

Now let’s install docker and docker-compose

# install docker
sudo dnf install -y dnf-utils zip unzip
sudo dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
sudo dnf remove -y runc
sudo dnf install -y docker-ce --nobest


# user creations
sudo groupadd docker
sudo usermod -aG docker $USER

# re-login to activate new group
# id
# uid=1000(opc) gid=1000(opc) groups=1000(opc),4(adm),190(systemd-journal),982(docker) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

After the installation, before starting docker we will customize some things

# change local location for storage
sudo mkdir -p /docker/files
sudo vim /etc/docker/daemon.json
#/etc/docker/daemon.json
{
  "data-root": "/docker/files"
}

After this the installation of docker and docker-compose is complete

#[opc@kasm-vm-vnic tmp]$ docker --version
#Docker version 26.1.3, build b72abbb
#[opc@kasm-vm-vnic tmp]$ docker composer --version
#Docker version 26.1.3, build b72abbb

sudo systemctl enable docker.service
sudo systemctl start docker
docker run hello-world

Then we need to add iptables awareness in docker

# iptables configuration
sudo dnf install -y iptables
sudo iptables -t nat -L

the output must look like this, there should be a chain called DOCKER

[opc@kasm-vm-vnic tmp]$ sudo iptables -t nat -L
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
DOCKER     all  --  anywhere             anywhere             ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  172.17.0.0/16        anywhere            

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
DOCKER     all  --  anywhere            !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain DOCKER (2 references)
target     prot opt source               destination         
RETURN     all  --  anywhere             anywhere       

Then we modify the daemon.json to include iptables as true

# /etc/docker/daemon.json
"iptables": true

and we restart docker

# restart docker
sudo systemctl restart docker

Cerbot install and configuration

# configure cerbot
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

Kasm install and configuration

cd /tmp
curl -O https://kasm-static-content.s3.amazonaws.com/kasm_release_1.15.0.06fdc8.tar.gz
curl -O https://kasm-static-content.s3.amazonaws.com/kasm_release_service_images_arm64_1.15.0.06fdc8.tar.gz
curl -O https://kasm-static-content.s3.amazonaws.com/kasm_release_workspace_images_arm64_1.15.0.06fdc8.tar.gz
tar -xf kasm_release_1.15.0.06fdc8.tar.gz
sudo bash kasm_release/install.sh --offline-workspaces /tmp/kasm_release_workspace_images_arm64_1.15.0.06fdc8.tar.gz --offline-service /tmp/kasm_release_service_images_arm64_1.15.0.06fdc8.tar.gz

After the installation succeeds before starting to use we need to add SSL, for this, we will use cerbot, we will use HTTP challenge, and we will assume that the domain for which we will create the certificates is kasm.example.com for this, we will simulate before running the command to make sure it all works

# run thus command
sudo /usr/bin/certbot certonly --standalone --agree-tos --register-unsafely-without-email --preferred-challenges http -d kasm.example.com --dry-run

#Saving debug log to /var/log/letsencrypt/letsencrypt.log
#Account registered.
#Simulating a certificate request for portal.donhk.dev
#The dry run was successful.

Now this is the actual execution

# stop kasm
sudo /opt/kasm/bin/stop

sudo /usr/bin/certbot certonly --standalone --agree-tos --register-unsafely-without-email --preferred-challenges http -d kasm.example.com

# replace the self-signed certs
cd /opt/kasm/current/certs
sudo mv kasm_nginx.crt kasm_nginx.crt.bk 
sudo mv kasm_nginx.key kasm_nginx.key.bk

sudo ln -s /etc/letsencrypt/live/portal.donhk.dev/privkey.pem kasm_nginx.key
sudo ln -s /etc/letsencrypt/live/portal.donhk.dev/fullchain.pem kasm_nginx.crt

# start kasm
sudo /opt/kasm/bin/start

[Update 11/02/2024]

After the first renewal of the certs kasm failed due to the certificates being unreadable the fix is below

sudo groupadd certaccess
sudo usermod -aG certaccess kasm
sudo usermod -aG certaccess my_user

sudo chgrp -R certaccess /etc/letsencrypt/live/kasm.example.com
sudo chgrp -R certaccess /etc/letsencrypt/archive/kasm.example.com

sudo chmod 640 /etc/letsencrypt/live/kasm.example.com/*.pem
sudo chmod 640 /etc/letsencrypt/archive/kasm.example.com/*.pem
sudo touch /etc/letsencrypt/renewal-hooks/post/fix_permissions.sh
sudo chmod +x /etc/letsencrypt/renewal-hooks/post/fix_permissions.sh
#!/bin/bash
chgrp certaccess /etc/letsencrypt/live/kasm.example.com/*.pem
chmod 640 /etc/letsencrypt/live/kasm.example.com/*.pem
chgrp certaccess /etc/letsencrypt/archive/kasm.example.com/*.pem
chmod 640 /etc/letsencrypt/archive/kasm.example.com/*.pem

/opt/kasm/bin/stop
/opt/kasm/bin/start

the file /etc/letsencrypt/renewal-hooks/post/fix_permissions.sh will automatically be executed by Certbot after every successful renewal. Certbot runs any executable scripts placed in the following directories as part of its renewal process:

  • Pre-Renewal Hooks: /etc/letsencrypt/renewal-hooks/pre/
  • Post-Renewal Hooks: /etc/letsencrypt/renewal-hooks/post/
  • Deployment Hooks: /etc/letsencrypt/renewal-hooks/deploy/