systemd Service Hardening
Introduction
Stock Torizon OS enables a set of platform services for development convenience, covering discovery, console access, removable media, and optional radios, alongside the services you genuinely need in the field such as Docker, over-the-air updates, and networking.
This article gives some guidance about which of those services can be considered for removal/masking in production. Apply the masks that match your product, and capture the resulting /etc changes with TorizonCore Builder.
This article is part of the Production Hardening Checklist, which also explains how to persist these changes across a fleet.
This article complies with the Typographic Conventions for the Toradex Documentation.
Masking the serial and virtual terminal login prompts belongs to Boot and Hardware Hardening, which is the reference for console lockdown.
Units to Keep in Production
| Unit | Role |
|---|---|
aktualizr-torizon.service | Over-the-air update client, which starts when provisioning certificates are present |
docker.service, containerd.service, docker.socket | Container runtime |
docker-compose.service | Starts Compose from /var/sota/storage/docker-compose/ when that file exists. Keep it if you deploy applications that way. |
NetworkManager.service, plus the dispatcher and wait-online units as needed | Host networking |
wpa_supplicant.service | Wi-Fi, where used. NetworkManager often pulls it in. |
systemd-resolved, systemd-timesyncd, systemd-journald, systemd-udevd, dbus | Core operating system services |
ostree-remount.service | OSTree filesystem layout |
greenboot-* and redboot-* | Boot health checks and update rollback helpers, which belong with OSTree |
auto-provisioning.service | One-shot unit that runs only when auto-provisioning files exist |
set-hostname.service | One-shot unit that runs only when the hostname is unset |
Avoid masking systemd-networkd, which is enabled alongside NetworkManager on Torizon OS by default, or the iptables and ip6tables one-shot units, without a tested networking and firewall plan of your own.
Units Covered by Other Articles
| Unit | Action |
|---|---|
sshd.socket | Mask, as described in Network Hardening |
avahi-daemon.service and avahi-daemon.socket | Mask in production, as described in Network Hardening |
getty@tty1.service and the serial-getty@ instance for your board | Mask, as described in Boot and Hardware Hardening |
Units to Mask Unless the Product Needs Them
| Unit | Guidance |
|---|---|
bluetooth.service | Mask unless the product uses Bluetooth. The unit carries ConditionPathIsDirectory=/sys/class/bluetooth. |
ModemManager.service | Mask unless you use a cellular modem |
usermount.service, and usually udisks2.service | See Removable Media following |
Units to Keep Enabled by Default
| Unit | Guidance |
|---|---|
remote-access.service and tzn-mqtt.service | Keep enabled. Both are gated on device certificates under /var/sota/import/, and they provide break-glass access and cloud-side operations when interactive login is rare. Mask them only if you have explicitly decided never to use Torizon Remote Access. |
fluent-bit.service | Keep enabled when /etc/fluent-bit/enabled is present, which is the stock state. It provides the device metrics that help you operate a hardened fleet. If you do not use that telemetry, remove the enabled flag or mask the unit. See Logging and Observability. |
Removable Media
The usermount service watches udisks2 and automatically mounts removable disks, including USB drives and USB SD card readers. That is convenient in the lab, and it is a common route for introducing untrusted filesystems onto a production device.
If you also set usbcore.authorized_default=0, as described in Kernel Configuration Hardening, unauthorized USB devices never configure at all, which stops most media that usermount would otherwise pick up.
The trade-offs are:
| Masking usermount, and udisks2 if unused | Keeping automatic mounting |
|---|---|
| Removable filesystems are not mounted automatically, so unexpected media is less likely to appear on the device | USB and SD devices appear under /media without any custom mount logic |
| Pairs well with USB authorization when the product needs no removable storage | Required for typical Secure Offline Updates with Lockboxes, unless you replace automatic mounting with an equivalent tested mount path for offline_updates_source |
| Breaks workflows that expect to import data by plugging in a USB or SD device | Still worth combining with USB allow-listing, so that only expected devices authorize |
If the product needs neither removable media nor Lockboxes, mask usermount, and consider masking udisks2 when nothing else requires it:
# sudo systemctl mask usermount.service
# sudo systemctl mask udisks2.service
If you use Lockboxes, or intentionally import data from USB or SD, keep automatic mounting and harden USB authorization instead of assuming that nobody plugs anything in.
Applying Masks to a Fleet
Mask the units your product does not need, for example:
# sudo systemctl mask bluetooth.service ModemManager.service
Then capture the resulting /etc changes with TorizonCore Builder and merge them into a custom image, as described in Applying and Persisting Changes.
Confirm the result on a deployed device:
# systemctl list-units --type=service --state=running
# systemctl list-unit-files --state=enabled