Ship a Korthveil firewall to a site, plug it in, and it sets itself up with no one at the site typing anything. It provisions itself from a document your organization signs. The document gives the firewall its management port, host name and administrator. It can also enroll the firewall in Korthveil Central or SentinelOps, which then send the rest of the configuration.

You need:

How it works

 your office                                    the site
 ┌──────────────────────────┐                   ┌────────────────────────────────┐
 │ org.key (kept offline)   │  ztp.json         │ unclaimed Korthveil firewall   │
 │ korthveil-ztp sign ──────┼──────────────────▶│  trusts org.pem                │
 └──────────────────────────┘  USB stick or     │  checks the signature, device, │
                               HTTPS via DNS    │  and expiry, then commits it   │
                                                └────────────────────────────────┘

When it applies: only while the firewall is unclaimed, meaning freshly installed or factory-reset, with no administrator and no configuration of its own. Once set up, it never looks for documents again.

What is trusted: only the signature. A document signed with another key, meant for another device, or expired is ignored and logged. Whoever controls the site's DHCP or DNS cannot take a firewall over.

Step 1: Make your organization key

korthveil-ztp keygen -out org

This writes:

Step 2: Make the firewalls trust it

Pick one:

The key the installer stored survives a factory reset: a reset firewall provisions itself again.

Step 3: Write and sign the document

korthveil-ztp template > doc.json
echo 'the administrator password' | korthveil-ztp hash      # paste into seed.admin.passwordHash
korthveil-ztp sign -key org.key doc.json > ztp.json
korthveil-ztp verify -trust org.pem -serial G6JY1234 ztp.json

The document's fields:

Field Meaning
devices serial:<system serial> or mac:<address> of any port. Leave it empty for any of your firewalls.
notAfter When the document expires; at most 400 days ahead.
seed.hostname The firewall's name.
seed.management The management port: interface (e.g. enp1s0), or mac, or neither when the document comes through DNS (the port it arrived on is used). Then ipv4Mode dhcp or static (ipv4, gateway4), and ipv6Mode slaac, static, or none.
seed.admin name and passwordHash (from korthveil-ztp hash). Without it, the console's setup code stays the way to create the administrator.
seed.modules Add-ins to turn on. Use central-management (with its enrollment token) or sentinelops to enroll; they then deliver the full configuration.
seed.zones, rules, sourceNat, portForwards, interfaces, dns, sshKeys Optional first policy, the same as in an answers file.

Enrollment tokens in the document are secrets:

Step 4: Deliver it

USB stick (simplest):

  1. Format a stick as FAT or exFAT with the label KV-ZTP (FAT labels hold at most 11 characters).
  2. Copy ztp.json to it.
  3. Plug it into the firewall before or after power-on.

The firewall reads the stick read-only. It is safe to leave it in.

DNS and HTTPS (no one on site):

  1. Put ztp.json on an HTTPS server with a publicly trusted certificate.
  2. Add a TXT record in the site's DNS domain (the one DHCP or IPv6 router advertisements hand out):

_korthveil-ztp.branch17.example.com. TXT "v=kztp1 url=https://ztp.example.com/fw/G6JY1234.json"

While unclaimed, the firewall runs DHCPv4 and SLAAC on every port. Only the web UI and SSH answer, so someone on site can still set it up by hand with the setup code shown on the console. Nothing is forwarded. It learns DNS servers and the search domain from DHCP or router advertisements (RDNSS/DNSSL), looks up the record, and fetches the document. IPv4-only, IPv6-only, and dual-stack sites all work.

Step 5: Watch it

At the firewall: the console shows Zero-touch provisioning: looking for a USB stick labelled KV-ZTP or DNS _korthveil-ztp.\ until a document is applied. It then shows the web UI address. The first revision in System › Revisions reads Zero-touch provisioning from usb (or dns:<domain>).

In Central or SentinelOps: the firewall appears as soon as it enrolls.

Troubleshooting

Symptom Check
Nothing happens The firewall must trust a key (step 2) and be unclaimed. A firewall with an administrator never provisions itself.
document ignored: not signed by a trusted key (log) It was signed with another org.key, or the firewall trusts another org.pem.
the document is for other devices The serial: must match the system serial (dmidecode -s system-serial-number), or a mac: must match a port.
the document has expired Sign it again with a later notAfter.
The USB stick is not read The label must be exactly KV-ZTP, the file system FAT or exFAT, and the file ztp.json at the top, under 1 MiB.
DNS discovery does not start The site's DHCP (option 15 or 119) or router advertisements (DNSSL) must give the domain, and the TXT record must be at _korthveil-ztp.<that domain>.

More: adr/0062 describes the design and its security.