How to enable SSH with key authentication in Anthias BalenaOS image for Raspberry Pi

Written by - 4 comments

Published on - Listed in Hardware Linux Personal


In December I was asked to look for a Digital Signage solution and after some research I came across Anthias. Anthias is the open sourced and free "brother" of Screenly, the "professional" solution for Digital Signage.

Anthias from Raspberry Pi image

The easiest and fastest way to install Anthias is by using the already prepared Image for Raspberry Pi, which can be selected in the Raspberry Pi Imager software (Choose OS -> Other specific-purpose OS -> Anthias):

Anthias image for Raspberry Pi

Note: The Anthias documentation and community recommends the installation using the "script" way, not using the Raspberry Pi image, as the image is outdated. For a POC it's OK though.

After using Anthias as "OS" and writing this onto a microSD card, it was time to boot up the Raspberry Pi and test Anthias.

The selected Anthias image itself is not installing a typical Raspbian Linux (a Debian-based Linux specific for Raspberry Pi's) as I expected, it installs an appliance-like OS called BalenaOS. This BalenaOS uses Docker containers to start up the application(s).

As I wanted to see how the containers are started, how they communicate and what kind of processes are running, I wanted to SSH into the Raspberry Pi. But... there was no SSH?

BalenaOS configuration in resin-boot partition

This is by design, as BalenaOS (by default) does not behave as a typical Linux system and doesn't expect anyone to log in on the device using SSH. However there's still a possibility as described in the BalenaOS documentation by enabling SSH in the BalenaOS configuration. But where is this configuration?

After the Anthias image was written to the SD card, the following partition layout can be seen (/dev/sdf represents the microSD card here):

ck@mint ~ $ sudo fdisk -l /dev/sdf
Disk /dev/sdf: 29.31 GiB, 31460950016 bytes, 61447168 sectors
Disk model: SD/MMC          
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x3c736e59

Device     Boot   Start     End Sectors  Size Id Type
/dev/sdf1  *       8192   90111   81920   40M  c W95 FAT32 (LBA)
/dev/sdf2         90112  745471  655360  320M 83 Linux
/dev/sdf3        745472 1400831  655360  320M 83 Linux
/dev/sdf4       1400832 8326566 6925735  3.3G  f W95 Ext'd (LBA)
/dev/sdf5       1409024 1449983   40960   20M 83 Linux
/dev/sdf6       1458176 8326566 6868391  3.3G 83 Linux

My Linux Mint automatically mounted most partitions:

ck@mint ~ $ mount|grep media
/dev/sdf6 on /media/ck/resin-data type ext4 (rw,nosuid,nodev,relatime,uhelper=udisks2)
/dev/sdf2 on /media/ck/resin-rootA type ext4 (rw,nosuid,nodev,relatime,uhelper=udisks2)
/dev/sdf3 on /media/ck/resin-rootB type ext4 (rw,nosuid,nodev,relatime,uhelper=udisks2)
/dev/sdf5 on /media/ck/resin-state type ext4 (rw,nosuid,nodev,relatime,uhelper=udisks2)
/dev/sdf1 on /media/ck/resin-boot type vfat (rw,nosuid,nodev,relatime,uid=1000,gid=1000,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,showexec,utf8,flush,errors=remount-ro,uhelper=udisks2)

The interesting partition here is the one labelled "resin-boot" (/dev/sdf1). It contains the boot files for BalenaOS and also a configuration file (config.json):

ck@mint /media/ck/resin-boot $ ls -la
total 6728
drwxr-xr-x  6 ck ck    2048 Jan  1  1970  ./
drwxr-x---+ 9 root  root     4096 Nov 22 19:36  ../
-rw-r--r--  1 ck ck      24 Nov 30  2022  balena-image
-rw-r--r--  1 ck ck   16915 Nov 30  2022  balenaos.fingerprint
-rw-r--r--  1 ck ck   51675 Nov 30  2022  bcm2711-rpi-400.dtb
-rw-r--r--  1 ck ck   51543 Nov 30  2022  bcm2711-rpi-4-b.dtb
-rw-r--r--  1 ck ck   52116 Nov 30  2022  bcm2711-rpi-cm4.dtb
-rw-r--r--  1 ck ck     516 Nov 30  2022  boot.scr
-rw-r--r--  1 ck ck     137 Nov 30  2022  cmdline.txt
-rw-r--r--  1 ck ck     581 Dec 12  2022  config.json
-rw-r--r--  1 ck ck   36287 Nov 30  2022  config.txt
-rw-r--r--  1 ck ck    2068 Nov 30  2022  device-type.json
-rw-r--r--  1 ck ck       0 Nov 30  2022  extra_uEnv.txt
-rw-r--r--  1 ck ck    3145 Nov 30  2022  fixup4cd.dat
-rw-r--r--  1 ck ck    5354 Nov 30  2022  fixup4.dat
-rw-r--r--  1 ck ck    8356 Nov 30  2022  fixup4x.dat
-rw-r--r--  1 ck ck      44 Nov 30  2022  image-version-info
-rw-r--r--  1 ck ck  591288 Nov 30  2022  kernel8.img
-rw-r--r--  1 ck ck     176 Nov 30  2022  os-release
drwxr-xr-x  2 ck ck   22016 Nov 30  2022  overlays/
-rw-r--r--  1 ck ck       0 Nov 30  2022  rpi-bootfiles-20220120.stamp
drwxr-xr-x  2 ck ck     512 Nov 30  2022  splash/
-rw-r--r--  1 ck ck  800028 Nov 30  2022  start4cd.elf
-rw-r--r--  1 ck ck 2240608 Nov 30  2022  start4.elf
-rw-r--r--  1 ck ck 2992584 Nov 30  2022  start4x.elf
drwxr-xr-x  2 ck ck     512 Nov 30  2022  system-connections/
drwxr-xr-x  2 ck ck     512 Nov 22  2023 'System Volume Information'/

The default config.json looks something like this:

ck@mint /media/ckadm/resin-boot $ more config.json
{
  "applicationId": 1971389,
  "deviceType": "raspberrypi4-64",
  "userId": 1375,
  "appUpdatePollInterval": 600000,
  "listenPort": 48484,
  "vpnPort": 443,
  "apiEndpoint": "https://api.balena-cloud.com",
  "vpnEndpoint": "cloudlink.balena-cloud.com",
  "registryEndpoint": "registry2.balena-cloud.com",
  "deltaEndpoint": "https://delta.balena-cloud.com",
  "mixpanelToken": "9ef939ea64cb6cd8bbc96af72345d70d",
  "apiKey": "T4O0nRhnBSmevdnUf1gyFO7QFd9In3mr",
  "files": {
    "network/network.config": "[service_home_ethernet]\nType=ethernet\nNameservers=8.8.8.8,8.8.4.4"
  }
}

Enabling SSH keys in config.json

The BalenaOS documentation mentions to add the os.sshKeys array into config.json. Let's do this with my own SSH public key and edit the config.json file (you need to be root to do that, unless you mounted the boot partition differently):

ck@mint /media/ckadm/resin-boot $ sudo vi config.json

After the change, the config.json content looks like this:

ck@mint /media/ckadm/resin-boot $ cat config.json
{
  "applicationId": 1971389,
  "deviceType": "raspberrypi4-64",
  "os": {
    "sshKeys": [
      "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDUHd13XGHRnVUL8e/T7/zVJk385z4f+NlD0QvfA6t1LwGmsl6yvQK8MVnfAwSqv7HHzMRzd2CJfu4/uBrV6S1QVdtohYb3CU6UVxVLej+9pXEobWYrGV/h7FLna0C5okCAp/X0ZJtC9Mg3BmJYT3o+4D/hxvDVBYRhamDvMdF5edlK2dpqDaU706ktbHvB7DEx7AQcxZW4HxJT17H3OCHXYanpbn6gKpIXPGChGXbpMQAVQAxHe7ark7SiCzOR59UPGcWTUDrp4qMiUn3ZyLWuKWACEcjU/GzuOkmV80jEKMmv8SaYfHBsHeYLS2kvaHf/vvAqAvROXx5zyS2GBxV3 ck@claudiokuenzler.com"
    ]
  },

  "userId": 1375,
  "appUpdatePollInterval": 600000,
  "listenPort": 48484,
  "vpnPort": 443,
  "apiEndpoint": "https://api.balena-cloud.com",
  "vpnEndpoint": "cloudlink.balena-cloud.com",
  "registryEndpoint": "registry2.balena-cloud.com",
  "deltaEndpoint": "https://delta.balena-cloud.com",
  "mixpanelToken": "9ef939ea64cb6cd8bbc96af72345d70d",
  "apiKey": "T4O0nRhnBSmevdnUf1gyFO7QFd9In3mr",
  "files": {
    "network/network.config": "[service_home_ethernet]\nType=ethernet\nNameservers=8.8.8.8,8.8.4.4"
  }
}

After un-mounting the partitions and placing the microSD card back into the Raspberry Pi and booting it, it was time to find out, whether SSH would work now.

SSH session into BalenaOS

You would probably expect that the SSH daemon running in BalenaOS would listen to port 22. But nope! That's another important information which was discovered during my research: The SSH port is tcp/22222 on BalenaOS.

With this information at hand, let's try it:

ck@mint ~ $ ssh -p 22222 192.168.15.16
The authenticity of host '[192.168.15.16]:22222 ([192.168.15.16]:22222)' can't be established.
ECDSA key fingerprint is SHA256:EVwYGpGy7JkeNSRWHe2k5HhX3nETlJKwoX2ZFmhzxf0.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[192.168.15.16]:22222' (ECDSA) to the list of known hosts.
X11 forwarding request failed on channel 0
root@621b11c:~# 

Yes, I'm in!

I expected a docker command to be available, but that isn't the case inside BalenaOS. But there is the balena-engine command, which can be seen as a 1:1 replacement (or alias) of the docker command. So now I can see the Anthias containers and can also check their logs etc. 

root@621b11c:~# balena-engine ps
CONTAINER ID   IMAGE                                                            COMMAND                  CREATED          STATUS                   PORTS                               NAMES
72d44316442a   2b29aa41162a                                                     "/usr/bin/entry.sh n…"   36 seconds ago   Up 32 seconds            0.0.0.0:80->80/tcp, :::80->80/tcp   anthias-nginx_7391455_2756077_0e2032b8d7b2743c2d0f4f25bdf2e212
05a9feb29604   4220520c41ee                                                     "/usr/bin/entry.sh b…"   36 seconds ago   Up 1 second                                                  anthias-wifi-connect_7391449_2756077_0e2032b8d7b2743c2d0f4f25bdf2e212
5da0468d9a3b   6bcd295754fb                                                     "/usr/bin/entry.sh /…"   41 seconds ago   Up 37 seconds                                                anthias-celery_7391453_2756077_0e2032b8d7b2743c2d0f4f25bdf2e212
dfabdbd04fef   2dae5c417d1b                                                     "/usr/bin/entry.sh p…"   41 seconds ago   Up 38 seconds                                                anthias-websocket_7391452_2756077_0e2032b8d7b2743c2d0f4f25bdf2e212
a79df6c83e0c   793c0159fc03                                                     "/usr/bin/entry.sh b…"   41 seconds ago   Up 37 seconds                                                anthias-viewer_7391451_2756077_0e2032b8d7b2743c2d0f4f25bdf2e212
a4e5ba719e76   3cbd1d68e67f                                                     "/usr/bin/entry.sh r…"   44 seconds ago   Up 41 seconds            127.0.0.1:6379->6379/tcp            redis_7391454_2756077_0e2032b8d7b2743c2d0f4f25bdf2e212
801349f361c2   97ee189d56f1                                                     "/usr/bin/entry.sh b…"   44 seconds ago   Up 41 seconds                                                anthias-server_7391450_2756077_0e2032b8d7b2743c2d0f4f25bdf2e212
6199289e8b2d   registry2.balena-cloud.com/v2/a8dcd97d7ce4e1702742090a1935fd7a   "/usr/src/app/entry.…"   8 minutes ago    Up 6 minutes (healthy)                                       balena_supervisor

That's great to continue my work on the Digital Signage proof of concept project. It will help me to figure out technical details I need to know for security and additional configurations such as reverse proxying Anthias, and more.


Add a comment

Show form to leave a comment

Comments (newest first)

CK from Switzerland wrote on Oct 30th, 2024:

You are welcome, Marc. Have a look at a related article I wrote on my company blog (Digital Signage: Open Source vs. Closed source solutions) where I describe the same frustration.


Marc from NL wrote on Oct 30th, 2024:

Thank you for your response! I will check it out. I wonder if the 'BalenaOS-strategy' for Anthias will open new worlds of possibilities, but so far it only frustrates me ;-) Cheers!


CK from Switzerland wrote on Oct 28th, 2024:

Marc, to create a SSH key pair (a private key and a public key) you can launch ssh-keygen -t ed25519 -C "Marc's key". This will create you a private key (which you can securely encrypt with your own personal password) and a public key you copy to the servers/systems you want to connect to. In case your OS is Windows, you can follow the Microsoft howto for Putty.


Marc from NL wrote on Oct 27th, 2024:

You have made it a beautiful study. Thanks! The step when inserting your public ssh key seemed a bit too quick to me. Where or how can you retrieve or create it?


RSS feed

Blog Tags:

  AWS   Android   Ansible   Apache   Apple   Atlassian   BSD   Backup   Bash   Bluecoat   CMS   Chef   Cloud   Coding   Consul   Containers   CouchDB   DB   DNS   Database   Databases   Docker   ELK   Elasticsearch   Filebeat   FreeBSD   Galera   Git   GlusterFS   Grafana   Graphics   HAProxy   HTML   Hacks   Hardware   Icinga   Influx   Internet   Java   KVM   Kibana   Kodi   Kubernetes   LVM   LXC   Linux   Logstash   Mac   Macintosh   Mail   MariaDB   Minio   MongoDB   Monitoring   Multimedia   MySQL   NFS   Nagios   Network   Nginx   OSSEC   OTRS   Office   PGSQL   PHP   Perl   Personal   PostgreSQL   Postgres   PowerDNS   Proxmox   Proxy   Python   Rancher   Rant   Redis   Roundcube   SSL   Samba   Seafile   Security   Shell   SmartOS   Solaris   Surveillance   Systemd   TLS   Tomcat   Ubuntu   Unix   VMWare   VMware   Varnish   Virtualization   Windows   Wireless   Wordpress   Wyse   ZFS   Zoneminder