D-113(a2) PROVEN: the OPNsense REST API round-trips the edge config
The API path adopted in D-113 is now demonstrated working against the LIVE Office1 edge,
closing the question that gated the ruling.

Measured:
  GET  core/firmware/status     -> HTTP 200, OPNsense 26.1 (auth works)
  GET  kea/dhcpv4/get           -> dhcpv4.general.enabled=1, interfaces=lan
  POST kea/dhcpv4/search_subnet -> 1 row: subnet 10.10.0.0/24, pools 10.10.0.100-10.10.0.199,
                                   option_data.routers 10.10.0.1, dns 10.10.0.1,
                                   domain office1.vr1.cloud.neumatrix.local, descr "LAN DHCP"

The API reads back EXACTLY what we pushed via config.xml yesterday, and exposes it as TYPED,
NAMED FIELDS -- not free-form XML. That is the (a2) argument made concrete: DOCFIX-191 (missing
sshd), DOCFIX-192 (silenced console) and DOCFIX-193 (an inert ISC <dhcpd> block against a Kea
backend) are NOT EXPRESSIBLE here. You cannot omit a typed field that has a default, and you
cannot address the wrong DHCP backend when the endpoint IS the backend.

GUI gotcha worth recording (26.1): API keys are NOT created in the user-edit dialog, and NOT in
the ApiKeys tab -- that tab wires only search_api_key + del_api_key, so it can list and delete
but CANNOT create. Creation is a ROW ACTION on the Users list: the fa-ticket icon, "Create and
download API key for this user" (source: mvc/app/views/OPNsense/Auth/user.volt). Any instruction
saying "edit user -> API keys -> +" describes the OLD UI and is wrong for 26.1. ApiKeyField::add()
mints key+secret as base64(random_bytes(60)) and stores key|crypt(secret,'$6$') -- the secret is
shown EXACTLY ONCE.

API gotchas: response root key is `dhcpv4`, NOT `dhcp4` (the config XML element name differs from
the API key name -- do not infer one from the other). camelCase actions map to snake_case URLs:
searchSubnetAction -> POST /api/kea/dhcpv4/search_subnet.

SEC-007 amended: ~/vr1-office1-creds/ now also holds the OPNsense API key/secret (0600).

NOT DONE: no WRITE through the API yet -- that is a live mutation and stays gated. And the
config.xml template is still in place: DO NOT push a full rendered config.xml now, it would
clobber API-managed state. Next step is reducing the template to a MINIMAL bootstrap (sshd +
root key + console) and moving DHCP/firewall/interfaces to the API.

Revert: read-only against the edge + docs; nothing to undo. To revoke the credential: GUI ->
System > Access > Users > root row > ApiKeys tab -> delete, then rm ~/vr1-office1-creds/opnsense-api.txt

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B6Fzre1CxCY8tzwFCudu57
1 parent 268eb03 commit cdc31b3221d7cb7e722b146a6bfcb17cfe3c7d13
@JANeumatrix JANeumatrix authored 15 hours ago
Showing 3 changed files
View
docs/changelog-20260713-opnsense-api-proven.md 0 → 100644
View
docs/security-ledger.md
View
docs/session-ledger.md