Inside Ubuntu Core
Ubuntu Core 22 (UC22) and Ubuntu Core 20 (UC20) are built on the foundations of Ubuntu 22.04 LTS (Jammy Jellyfish) and Ubuntu 20.04 LTS (Focal Fossa), respectively. These are the current generation of Ubuntu Linux for embedded devices.
The kernel, boot assets, runtime environment, applications and device enablement capabilities are all delivered as snaps that are controlled by snapd (the snap daemon), which is itself packaged as a snap.
See below for how these elements combine in Ubuntu Core:
Ubuntu Core snaps
The following components make up Ubuntu Core:
snapd is the system daemon that supervises all other snaps on Ubuntu Core. It exposes a REST API that makes Ubuntu Core appliances IP-addressable by default. This API facilitates device management.
application snaps define the functionality of an embedded device and are confined with all their dependencies to their own sandbox. Interfaces to other applications or to the system must be explicitly defined.
system snaps are considered critical to the function of the system, and include the snaps for network-manager, modem-manager and bluez.
Related to system snaps, but in a less critical category, are snaps that enable device capabilities like audio, power and disk storage, alongside Docker container orchestration and virtualisation capabilities, including Microk8s and LXD.
boot assets come from the gadget snap and include board-specific binaries and data, such as bootloader, device tree, configuration files, and cloud-init configuration for edge virtualisation use cases. The gadget snap is typically issued and signed by board OEM/ODMs.
base snap holds the execution environment inside which applications run. It also serves as the root file system for Ubuntu Core images. Core snaps include basic Ubuntu 2x.04 LTS packages.
kernel snap holds the kernel image and associated modules. It will also contain an initial ramdisk image for system initialisation. Firmware and device tree files can optionally be packaged here. The kernel snap can be updated but it cannot be swapped.
The above snaps are combined using the
ubuntu-image tool to create the Ubuntu Core installation image.
The REST API
Ubuntu Core exposes a built-in REST API for secure device command and control. Authenticated and authorised clients can perform software management and configuration tasks on their Ubuntu Core devices remotely. Devices running Ubuntu Core can be configured remotely via the REST API.
See Snaps in Ubuntu Core for a general overview, and see below for details on the UC2x specific configuration.
The storage layout of the generated image used to install Ubuntu Core (as shown above), and the resultant storage on the device after installation (shown below), is described by the gadget snap and its associated
Ubuntu Core 2x typically uses the following storage partitions:
- ubuntu-seed (role: system-seed; read-only, vfat-formatted): contains the configuration for the first-stage/recovery boot loader and at least one recovery system which is a set of snaps (base, kernel, gadget and application snaps) together with a model assertion and snap assertions that define the device and for which the device can be recovered or reinstalled.
- ubuntu-boot (role: system-boot; read-only, ext4 or vfat): contains the second-state/run bootloader and unpacked kernel(s) to boot and with initramfs which decrypts the ubuntu-data and ubuntu-save partition.
- ubuntu-save (role: system-save; writable, ext4): stores device identity backup data and data to facilitate recovery or re-install. This partition is mandatory on encrypted systems where it should have a minimum size of approximately 20+MB to handle volume and file system creation.
- ubuntu-data (role: system-data; writable, ext4): stores user and system data. This partition is often minimally sized in the image but extended during device initialisation to use all the space available.
The system boot process:
- verifies the bootloaders and kernel signatures
- measures the above and the kernel command line with the TPM
- on top of the above trusted set the snapd initrd code measures the snap device model
- snapd then separately verifies other snaps with their assertions as needed
snap-bootstrap is the main executable that is run during the early initramfs booting stage of UC2x. It has the following responsibilities:
- Mounting selected partitions from the disk that UC2x is on. Partitions include data, system-boot, seed, and if present, save (optional on unencrypted devices).
- As part of mounting those partitions, snap-bootstrap may perform the necessary steps to unlock any encrypted partitions such as ubuntu-data and ubuntu-save (see Full disk encryption).
- After unlocking and mounting all such partitions, snap-bootstrap then chooses which base snap is to be used for the root filesystem of userspace (the root filesystem of the initramfs is just a static set of files built into the initramfs and is not the final root filesystem), and mounts this base snap file.
- snap-bootstrap then chooses which kernel snap is to be used to mount and find additional kernel modules that are not compiled into the kernel or shipped as modules inside the initramfs or otherwise loaded as DTBs, etc.
- snap-bootstrap will then mount the ubuntu-data partition such that either the writable components of the root filesystem come from this actual partition, or if the mode the system is booting into is an ephemeral system such as install or recover, will mount a temporary filesystem for this.
- snap-bootstrap on kernel and base snap upgrades will also handle updating bootloader environment variables to implement A/B or try-boot functionality.
- snap-bootstrap then finally may do some additional setup of the root filesystem such as copying some default files for ephemeral system modes such as recover.
There are several layers of isolation that make snaps strictly confined.
The first layer of isolation is logical: a snap is a self-contained file system mounted on a Linux system. Snaps are immutable with least privileges by default, which make it easy to build tamper-proof devices.
Isolation mechanisms rooted in the Linux kernel add an additional layer of isolation through Cgroups and Namespaces:
|Cgroups Limit the amount of resources the process confined to a snap can consume (CPU, memory, network bandwidth, and so on).||Namespaces Make sure processes in a snap see their own personal view of the system (files, processes, network interfaces, hostname, and so on).|
|AppArmor Allows system administrators to restrict snap capabilities with default security profiles that can be extended.||Seccomp Isolates processes running in a snap by limiting the system calls they are allowed to make.|
See Security and sandboxing for further details on how confinement is implemented.