Check a running router against the configuration it should have#
You will end up with a command that answers one question: does this router still have everything the OPNsense configuration said it should? It prints every line the import expects and the router does not have, prints anything set beyond the import in the areas the import covers, and exits non-zero when something is missing — which makes it something you can run from a scheduled task after a migration until you trust the result.
Before you start#
- The original OPNsense
config.xml. If you built the seed with--include-sourceit is already on the machine's seed medium asopnsense-config.xml. - Shell access to the router: the console, or SSH if you have turned it on.
- The same
--mapyou used for the import. A different mapping compares against a different router.
Step 1 — Get the running configuration as set commands#
On the router:
show configuration commands > /tmp/liveOver SSH, show configuration commands is a shell function of the operational CLI rather
than a program, so it needs the wrapper:
ssh wheelhouse@<router> '/opt/vyatta/bin/vyatta-op-cmd-wrapper show configuration commands' > live.txtYou can also take it through the agent's API, which does not need SSH at all:
R=https://<router>:8443
T=wh_... # an API token with the viewer role
curl -sk -H "Authorization: Bearer $T" "$R/api/config/commands" > live.jsonStep 2 — Compare#
tools/opnsense-import.py config.xml --map lan=eth0,wan=eth1 --check-against /tmp/livemissing: set nat destination rule 150 destination port 8443
missing: set nat destination rule 150 translation address 192.0.2.20
also set: set service dns forwarding name-server 1.1.1.1
147 expected, 2 missing, 1 set beyond the import in the areas it coversTwo kinds of line:
missing: — the import expects this and the router does not have it. Either somebody
deleted it, or it was never applied. This is what makes the command exit 1.
also set: — the router has this and the import does not expect it, within an area
the import has an opinion about. That is usually fine and often correct: a resolver
added later, a firewall rule you wrote after the migration. It is there so a change you
did not make gets noticed.
The comparison is deliberately loose in two places, so that it reports differences rather than punctuation:
- Quoting is ignored. A router quotes the values it prints (
inet '192.0.2.10'); the import quotes only what has to be quoted. Both sides are compared as words. - Settings VyOS writes for itself are ignored. Anything whose last two words include
offload,hw-id,mtu,duplexorspeedappears on every interface on a running router and never in an import.
And it only reports extras in areas the import covers, worked out from the first two words of every expected line. A router has plenty of settings the imported file never mentions; listing all of them would bury the two lines that matter.
Step 3 — On the router itself#
On a machine installed from a seed built with --include-source, the whole check is two
commands with nothing to fetch:
sudo mount /dev/sr1 /mnt
/opt/vyatta/bin/vyatta-op-cmd-wrapper show configuration commands > /tmp/live
sudo wheelhouse-opnsense-import /mnt/opnsense-config.xml --map lan=eth1,wan=eth0 \
--hostname "$(hostname)" --check-against /tmp/live--hostname "$(hostname)" keeps the host-name line from being reported as missing when
you renamed the box during the install.
Step 4 — Run it on a schedule, for a while#
The command exits non-zero when something is missing, so it works as a check. Put the
config.xml somewhere readable only by root, and use a scheduled task:
set system task-scheduler task migration-check crontab-spec '17 6 * * *'
set system task-scheduler task migration-check executable path /config/scripts/migration-check.sh#!/bin/sh
/opt/vyatta/bin/vyatta-op-cmd-wrapper show configuration commands > /tmp/live
wheelhouse-opnsense-import /config/migration/opnsense-config.xml \
--map lan=eth0,wan=eth1 --hostname "$(hostname)" --check-against /tmp/live \
|| logger -t migration-check "the router no longer matches the imported configuration"/config/scripts is on the persistent partition, so the script survives an image
upgrade. More on this in Run something on a schedule.
Turn it off once the migration has settled. A check that has passed every day for two months and will pass for ever is noise, and the comparison drifts as you make real changes the old router never had.
What this check does not tell you#
- Whether it works. It compares configuration to configuration. A port forward can be present and still not reachable because the provider blocks the port. For that, publish a service and test from outside.
- Anything on the Not translated list. The import never expected those lines, so their absence is not a difference. That list is the report's, and you work through it by hand.
- The state of anything that is not configuration. Leases, sessions, routes the kernel installed, container images. Those are on the dashboard and the pages that own them.
Undoing it#
Nothing to undo — the check reads and prints. Delete the scheduled task when you are done with it:
delete system task-scheduler task migration-checkSee also#
- Read the migration report
- Build a seed that installs the replacement —
--include-sourceis what makes this a two-command job later - Config as code with
agent.yaml— the ongoing version of this idea, for a router you did not migrate - Alert on drift
- Turn SSH on, and restrict it
Checked against tools/opnsense-import.py ·
docs/unattended-install.md ·
ui/src/pages/SystemSettings.tsx ·
docs/security.md