Hardened, minimal IoT/OT security Linux β built from scratch with Buildroot.
Ships the Rust-native sentinel scanner + secrets vault. A secure MQTT edge gateway.
Emberwall is not based on any existing distro. It is assembled from source with Buildroot: its own cross-toolchain, a hardened Linux kernel, and a tiny immutable userland β no package manager, a few MB in size. Every tool inside is chosen; nothing is incidental. It exists to be the hardened edge gateway for the IoT pipelines in my other projects.
| What it is | A whole Linux distribution assembled from source with Buildroot β its own cross-toolchain, a hardened kernel, and an immutable userland of a few MB with no package manager. |
| The one idea | Every tool inside was chosen. Nothing is incidental, because nothing arrived as a dependency of something else β which is the property a general-purpose distro cannot give you at the edge. |
| What it ships | sentinel, a ~0.5 MB static Rust binary that folds a port scanner and a secrets vault into one hardened CLI β the work from pyscan and aegisvault collapsed into a single tool with no runtime. |
| Where it sits | The gateway tier, deliberately not the dashboard tier. Node-RED, InfluxDB and Grafana are heavy Go and Node services; putting them on a hardened edge node defeats the point of hardening it. |
| Hardened | PIE, full RELRO, SSP-strong, FORTIFY_SOURCE=2 Β· KASLR, strict RWX, hardened usercopy, yama + lockdown LSMs, no /dev/mem Β· nftables default-deny, dropbear with no root login |
| Targets | x86-64 and ARM64 Β· live ISO, workstation, or locked appliance β five defconfigs |
| Try it | Build the ISO, boot it in QEMU, log in as root / sentinel, type sentinel-demo |
Contents β Highlights Β· Where it fits Β·
sentinel Β·
Quick start Β· Variants Β·
Hardening Β· Build flow Β· Layout Β·
Status
- Rust-native tooling β the
sentinelbinary (~0.5 MB, static) unifies a port scanner and a secrets vault into one hardened CLI. - OT/ICS aware β Modbus, S7comm, IEC-104, DNP3, BACnet, EtherNet/IP, plus IoT (MQTT, CoAP, LoRaWAN) β TCP and UDP.
- Hardened by default β PIE/RELRO/SSP/FORTIFY, KASLR,
lockdown+yamaLSMs, restrictive sysctl,nftablesdefault-deny, dropbear without root login. - IoT gateway ready β Mosquitto (broker + clients + bridge), WireGuard, Chrony, CAN/IΒ²C tooling.
- Multi-target β x86-64 and ARM64; live ISO, workstation, or locked appliance.
Emberwall is the hardened edge gateway, not the dashboard tier. For a sensor
project like solar-weather-station:
flowchart LR
subgraph EDGE["π± Edge (field)"]
S["ESP32 + sensors<br/>(temp Β· hum Β· lux Β· batt)"]
B["LoRaβMQTT bridge"]
S -- "LoRa P2P" --> B
end
subgraph GW["π₯ Emberwall (hardened gateway)"]
M["mosquitto<br/>MQTT broker"]
F["nftables<br/>default-deny"]
SN["sentinel<br/>scan Β· vault"]
B -- "MQTT wx/#" --> M
M --- F
M --- SN
end
subgraph SRV["π₯οΈ Server / Raspberry Pi"]
NR["Node-RED"] --> IDB["InfluxDB"] --> GRA["Grafana"]
end
M -- "WireGuard (encrypted)" --> NR
The Node-RED / InfluxDB / Grafana stack runs on that server or a Raspberry Pi β
deliberately not on the minimal node (they are heavy Go/Node services; putting them
on a hardened edge node defeats its purpose). Suggested topic contract:
wx/<node-id>/reading β {"tempC":21.4,"hum":58,"batt":3.9,"lux":12000}.
sentinel scan <ip> [--ports top|1-1024|22,80,502] [--udp] [--modbus]
sentinel vault encrypt|decrypt [--input F] [--output F]
- scan β concurrent TCP-connect scanning with OT/ICS + IoT service recognition,
UDP probing (real CoAP
/.well-known/coreprobe) and a Modbus/TCP identification probe. A Rust port of the core ofpyscan. - vault β secrets encryption with argon2id + XChaCha20-Poly1305, secrets
zeroized in memory. The Rust crypto core of
AegisVaultas a native binary.
Hexagonal design: domain (services, modbus) / application (tcp, udp) /
adapters (ui, vault). Built as a Buildroot cargo-package, cross-compiled static,
zero C dependencies.
flowchart TB
CLI["CLI / main.rs<br/>(arg parsing)"]
subgraph APP["Application"]
TCP["tcp engine<br/>(concurrent connect)"]
UDP["udp engine<br/>(CoAP probe)"]
end
subgraph DOM["Domain"]
SVC["services<br/>(OT/IoT ports)"]
MOD["modbus<br/>(MBAP probe)"]
VLT["vault<br/>(argon2id + XChaCha20)"]
end
subgraph ADP["Adapters"]
UI["ui (amber output)"]
end
CLI --> TCP & UDP & VLT
TCP --> SVC & MOD
UDP --> SVC
TCP & UDP & VLT --> UI
Host requirements (Ubuntu):
sudo apt install -y build-essential git wget cpio unzip rsync bc \
libncurses-dev file python3 libelf-dev libssl-dev flex bison \
mtools dosfstools qemu-system-x86
sudo update-alternatives --install /usr/bin/install install /usr/bin/gnuinstall 100 || trueBuild the bootable ISO:
git clone https://gitlab.com/buildroot.org/buildroot.git
cd buildroot
make BR2_EXTERNAL=/path/to/emberwall emberwall_live_x86_64_defconfig
make -j$(nproc)
# β output/images/rootfs.iso9660 (hybrid: also dd-able to USB)Run it (QEMU windowed, or attach the ISO to a VirtualBox VM):
/path/to/emberwall/board/emberwall/x86_64/run-qemu-iso.sh
# login: root / sentinel β type: sentinel-demoWrite to USB and boot on real hardware:
sudo dd if=output/images/rootfs.iso9660 of=/dev/sdX bs=4M status=progress conv=fsyncRust dependencies are vendored in
package/sentinel/src/vendor/, so the build works offline. Full guide:docs/BUILD.mdΒ· diagrams:docs/DIAGRAMS.md.
flowchart TB
EXT["BR2_EXTERNAL<br/>(one source tree)"]
EXT --> L["live<br/>rootfs.iso9660<br/>(boot / USB)"]
EXT --> W["workstation<br/>ext4 + cpio<br/>(analyst)"]
EXT --> A["appliance<br/>squashfs (RO)<br/>(locked node)"]
L --> AR1["x86-64"]
W --> AR2["x86-64 Β· ARM64"]
A --> AR3["x86-64 Β· ARM64"]
| defconfig | Arch | Output | Use |
|---|---|---|---|
emberwall_live_x86_64 |
x86-64 | rootfs.iso9660 |
Live ISO (boot / USB) |
emberwall_workstation_x86_64 |
x86-64 | ext4 + cpio |
Analyst workstation |
emberwall_workstation_aarch64 |
ARM64 | ext4 |
Same, on SBC / QEMU virt |
emberwall_appliance_x86_64 |
x86-64 | squashfs (RO) |
Locked IoT node |
emberwall_appliance_aarch64 |
ARM64 | squashfs (RO) |
Locked IoT node (ARM) |
Toolchain: PIE, full RELRO, SSP-strong, FORTIFY_SOURCE=2.
Kernel: KASLR, strict RWX, hardened usercopy, init-on-alloc/free, yama+lockdown
LSMs, no /dev/mem, netfilter/nftables. Runtime: restricted ptrace/kptr/dmesg,
hardened BPF, anti-spoofing sysctl, nftables default-deny input, dropbear without
root login.
Planned for production appliances: dm-verity read-only root, verified boot, signed A/B OTA (swupdate).
flowchart LR
SRC["emberwall<br/>(BR2_EXTERNAL)"] --> BR["Buildroot<br/>make defconfig"]
BR --> TC["cross toolchain<br/>+ hardened kernel<br/>+ rootfs"]
TC --> RUST["sentinel<br/>(cargo, vendored)"]
RUST --> IMG["output/images/<br/>rootfs.iso9660"]
IMG --> QEMU["QEMU / VirtualBox"]
IMG --> USB["dd β USB β real HW"]
emberwall/
βββ configs/ # defconfigs (5 variants)
βββ board/emberwall/ # overlay, kernel/sysctl hardening, QEMU + demo scripts
βββ package/
β βββ sentinel/ # the Rust tool (source + vendored deps)
β βββ pyscan/ # optional Python packages (opt-in)
β βββ aegisvault/
βββ docs/ # BUILD.md Β· DIAGRAMS.md Β· demo.gif
βββ external.desc / external.mk / Config.in
The distribution builds and boots today: five defconfigs across x86-64 and ARM64, a
hardened kernel, the immutable userland, sentinel compiled from vendored sources, and
a live ISO that is also dd-able to USB.
Still open, and all of it belongs to the same theme β making an appliance you can trust after it leaves your hands:
- dm-verity read-only root, so a modified rootfs fails to mount rather than booting quietly.
- Verified boot, so the kernel that runs is the kernel that was signed.
- Signed A/B OTA via swupdate, so an update that fails rolls back instead of bricking a device in the field.
Until those land, Emberwall is hardened against what happens while it runs, not against someone who can rewrite its storage offline.
Part of a larger body of work β see my profile for the full edge β gateway β dashboard picture.
MIT Β© Zoel Arias ManchΓ³n