Build the install image¶
Gateways are installed from a zero-keystroke USB image: it installs OpenBSD,
drops in the agent, and enrolls the device into the
holding zone on first boot, with nobody at the keyboard. The
build tooling lives in
digilan/provisioning/openbsd-autoinstall
(profile gateway).
What goes into the image¶
scripts/build-usb.sh takes the stock OpenBSD installXX.img and adds:
site<ver>.tgzbuilt fromprofiles/gateway/site/, holding theedge-agentbinary (/usr/local/sbin/edge-agent), itsrc.dscript, thedigilan-statusbanner and root's.kshrc(with theeaalias);/etc/edge-enroll.conf(mode 0600) withNEXUS_ADDR,REALTIME_ADDRandENROLL_TOKEN;auto_install.conf(the answer file) inside thebsd.rdramdisk, viardsetroot. The installer only looks for it in the ramdisk root; a copy on the media root is ignored and the installer stops at its prompt;/etc/boot.confon the media, pinning the console (see below).
The agent binary and edge-enroll.conf are generated at build time and are
gitignored.
Build it¶
build-usb.sh must run on OpenBSD as root (it needs vnconfig, an FFS mount and
rdsetroot). From macOS, scripts/build-image.sh does the whole thing: it
fetches and checks the agent, starts the local QEMU OpenBSD VM from
edge/gateway/dev/openbsd-vm.sh, runs build-usb.sh inside it and copies the
image back.
cd openbsd-autoinstall
ENROLL_TOKEN=<bootstrap-token> \
AGENT_VERSION=v0.1.99 \
NEXUS_TOKEN=<system-admin API token> \
./scripts/build-image.sh
# -> gateway-installer-amd64-78.img (CONSOLE=serial, the default)
On an OpenBSD host, call the low-level script directly with a release agent
(fetch it with scripts/fetch-agent.sh on any machine, see below):
doas env NEXUS_ADDR=https://dev.nexus.digilan-edge.com \
REALTIME_ADDR=wss://dev.realtime.digilan-edge.com \
ENROLL_TOKEN=<bootstrap-token> \
AGENT_BIN=/path/to/edge-agent-openbsd-amd64-v0.1.99 \
CONSOLE=serial \
./scripts/build-usb.sh
| Variable | Default | Meaning |
|---|---|---|
ENROLL_TOKEN |
required | Bootstrap token from Admin → Enrollment in the target environment |
NEXUS_ADDR |
dev Nexus (build-image.sh); required for build-usb.sh |
Nexus URL the box enrolls with |
REALTIME_ADDR |
dev Realtime (build-image.sh); required for build-usb.sh |
Realtime URL |
AGENT_VERSION |
none | build-image.sh only: release tag of the agent to fetch and bake in |
AGENT_BIN |
none | A release agent binary already on disk; required for build-usb.sh |
EXPECT_SHA256, NEXUS_TOKEN |
none | How AGENT_VERSION is verified; one is required, see below |
ALLOW_UNSIGNED_AGENT |
0 |
1 accepts an agent without the release key (bench only, see below) |
DRY_RUN |
0 |
build-image.sh only: 1 checks the agent and stops before the VM |
CONSOLE |
serial |
serial or vga, see below |
ROOT_PW |
locked (*) on serial, DEFAULT_VGA_ROOT_PW from config.sh on vga |
Root password on the installed system |
OBSD_ARCH |
amd64 |
Target architecture |
BASE_IMG |
downloaded | A pre-downloaded installXX.img to start from |
GATEWAY_REPO, OUT_DIR |
sibling edge/gateway checkout, repo root |
build-image.sh only |
Point NEXUS_ADDR / REALTIME_ADDR at the environment the token was minted in;
see the environment URL table.
The agent must be a release build¶
Only an agent built by the gateway tag pipeline carries the release signing
key; without it the device refuses every over-the-air update until it is
reflashed. Both build-image.sh and build-usb.sh read the key embedded in the
agent binary and compare its sha256 with RELEASE_KEY_SHA256 in config.sh.
An agent with no key (such as a make build-openbsd build) or another key stops
the build before anything is written.
build-image.sh takes the agent from exactly one of:
| Set | Agent baked in |
|---|---|
AGENT_VERSION=vX.Y.Z |
that release, fetched and verified by scripts/fetch-agent.sh |
AGENT_BIN=/path |
a release binary you already have |
ALLOW_UNSIGNED_AGENT=1 and neither of the above |
a make build-openbsd build of GATEWAY_REPO |
With none of them it stops and says so.
scripts/fetch-agent.sh vX.Y.Z [arch] downloads edge-agent-openbsd-<arch>
from the build:<arch> job of that tag's pipeline in edge/gateway (with
glab, or GITLAB_TOKEN with read_api), into agents/, and checks:
- its sha256 against
EXPECT_SHA256, or, when that is unset, against the release registry ofNEXUS_ADDR(ListAgentReleases, which needs a system-admin API token inNEXUS_TOKEN); this is the sha256 Nexus serves to devices for that version; - that it carries the release signing key;
- when
gois installed, that it is a clean build of that tag.
Any failed check stops it. Use it on its own to get a binary for build-usb.sh.
Bench images
ALLOW_UNSIGNED_AGENT=1 lets the build continue with an agent that has no
release key, and prints a BENCH IMAGE warning block. A device installed
from that image can never be updated over the air. Do not flash it for a
site.
The first run of build-image.sh installs the VM and takes 15 to 20 minutes;
later runs are faster. The VM's own downloads stall under emulation, so place a
copy of install78-amd64.img in edge/gateway/dev/.vm/ (or set BASE_IMG)
first.
Serial or VGA console¶
The image pins, at build time, the one console the bootloader, the installer and the installed system all use. Picking the wrong one looks like a dead box: it installs and enrolls normally while showing nothing.
CONSOLE=serial (default) |
CONSOLE=vga |
|
|---|---|---|
| For | headless box with a COM port | box with a monitor and no usable COM port |
| Output file | gateway-installer-<arch>-<ver>.img |
gateway-installer-<arch>-<ver>-vga.img |
Media boot.conf |
stty com0 115200, set tty com0 |
default console (pc0) |
| Installed console | com0 at 115200 baud |
VGA |
| Root console login | locked unless ROOT_PW is set |
enabled with DEFAULT_VGA_ROOT_PW unless ROOT_PW is set |
Both variants are otherwise identical. Root SSH login is disabled in both.
The VGA image has a known root password
A VGA build exists to debug a box that looks dead, so it ships a console
login whose password is public (DEFAULT_VGA_ROOT_PW in config.sh, and
printed at the end of the build). Do not leave a VGA-installed box at a
customer site: build CONSOLE=serial, or pass an explicit ROOT_PW
(ROOT_PW='*' locks it).
How to attach to each console: Write the image to a USB stick.
Firmware: UEFI or legacy¶
The answer file leaves partitioning unanswered on purpose, so the OpenBSD installer chooses from how the box booted: GPT with an EFI system partition under UEFI, whole-disk MBR under legacy/CSM. One image installs a bootable system in both modes.
On hardware you control, prefer UEFI with CSM disabled. In every case, put the internal disk ahead of USB in the boot order, or pull the stick at the first reboot.
What the box shows¶
- First boot prints a banner and numbered steps:
[1/3] waiting for network(up to 60 s for a default route),[2/3] enrolling,[3/3] starting edge_agent. A failure names the likely cause and the command to retry. A copy is kept in/var/log/digilan-enroll.log. - Every boot ends with a status box from
/etc/rc.local: enrolled (with the gateway id), agent running, Nexus link, reachability of the Nexus host baked in at flash time, and the WAN address. Rundigilan-statusto print it again. On a VGA console, scroll back with Shift+PgUp.
Once enrolled, the device appears on Admin → Devices under Holding. Assign it there; see Device lifecycle.