Keeping an OT scanner's data fresh
A device-discovery product for OT networks needs two bodies of data that will not sit still:
- IEEE OUI / MA-L — the vendor prefixes that turn a MAC address into “this is a Siemens PLC”. New assignments appear continuously; a list a year old reports unknown vendors for equipment that has been on sale for months.
- A vulnerability feed — published daily. Discovering a device is only half the job; the customer bought the other half.
Both must refresh on their own, on gateways that may have no route to the internet, without the scanner going down — and without the possibility of somebody quietly feeding the fleet last March’s vulnerability data.
The shape of it
flowchart LR
IEEE[IEEE OUI] --> B
NVD[CVE / KEV / EPSS] --> B
B[your backend<br/>consolidate + sign] --> H[hub in the plant DMZ]
H --> G1[gateway]
H --> G2[gateway]
H --> G3[gateway]One host per plant reaches the internet, not every gateway. In OT that is usually not a preference, it is the network you are given — and it also keeps a fleet of gateways from hammering an upstream rate limit. Your backend consolidates and signs; the hub serves; the gateways verify your signature and never trust the upstream directly.
Publishing a dataset
Consolidate whatever you ship into a tar, then build and sign a manifest:
--since takes the publication time already in the field. It fails if today’s
manifest is not strictly newer — which is the same rule every agent applies, so
a publication that fails here would have been refused by the whole fleet.
Publish the tar uncompressed
A day-to-day vulnerability bundle is the ideal case for
delta updates — and publishing it gzipped throws that away.
One changed byte reshuffles a gzip stream, so a patch over .tar.gz measures
98% of the full size; over the uncompressed tar of two adjacent versions, 3%.
The recipe
The scanner reads two environment variables the agent sets, both absolute and both pointing at the current version:
On SIGHUP it reopens them. That is the whole contract, and it is what keeps a
nightly feed from becoming a nightly outage.
What a night looks like
Same PID before and after. The OUI dataset is not touched — its own interval has not elapsed.
If the new feed makes the scanner unhealthy inside its grace period:
Yesterday’s data is back and the scanner is serving from it. Worth being precise
about what that restores: the data. If a malformed feed killed the process
outright, restart_policy = "always" is what brings it back — onto the data
that has already been rolled back.
Confirming it, and alerting on it
The alert that matters is not “the agent is down” — you would notice that. It is this one:
A gateway whose feed stopped updating six weeks ago keeps answering scans, keeps reporting healthy, and keeps telling the customer their PLCs have no known vulnerabilities. Nothing else on the device looks wrong. This is the signal.
Air-gapped plants
Where the hub itself has no route out, the same manifests and tars can arrive on
removable media: point manifest at a file:///…-style local path and the
agent reads it from disk, verifying exactly the same signature and applying
exactly the same anti-replay rule. What changes is the transport, not the trust.