Every OPNsense box ships its own Authentication Servers page, and until now that’s exactly where directory login lived: one firewall, one page, one bind password typed in by hand. Fine for a single box. Painful the moment you have five — click into each device, paste the same LDAP settings, remember which ones still have last quarter’s bind password, and hope you didn’t fat-finger the login order on the one box you can’t reach physically. Get that order wrong and you’ve locked yourself out of a firewall over a typo.
NetDefense now manages LDAP and Active Directory authentication the same way it manages firewall rules and aliases: define it once, deliver it through your existing templates, and let it stay in sync across every device that should have it.
TL;DR
- Define an authentication server once and roll it out to any number of devices through templates — no more clicking through each firewall’s own Authentication Servers page.
- Bind passwords are referenced from a secret variable, never pasted into a snippet — the literal password is refused outright if you try.
- Directory group membership can decide who gets WebGUI access, and with which privileges — sync a group instead of managing membership by hand on every box.
- The login order always tries Local Database first. Not a setting you remember to check — enforced on every order NetDefense writes, so a directory outage can’t lock out local admins.
- Manage it from the web app,
ndcli, or an AI assistant through the NetDefense MCP server.
Define it once, deliver it like everything else
An authentication server is a snippet — the same building block behind every firewall rule and alias NetDefense manages. Its content uses the same field names OPNsense stores in its own configuration, so if you’ve configured LDAP or Active Directory by hand before, nothing here is new vocabulary:
{ "name": "Corp AD", "type": "ldap", "host": "dc01.corp.example.com", "ldap_port": "636", "ldap_urltype": "SSL - Encrypted", "ldap_protver": "3", "ldap_scope": "subtree", "ldap_basedn": "DC=corp,DC=example,DC=com", "ldap_authcn": "OU=Staff,DC=corp,DC=example,DC=com", "ldap_attr_user": "sAMAccountName", "ldap_binddn": "CN=svc-netdefense,OU=Service Accounts,DC=corp,DC=example,DC=com", "ldap_bindpw": "${ldap_bind_password}"}Attach that snippet to a template the way you would any other, and every device on NDAgent 1.19.2 or later that the template reaches gets the same directory server — no re-typing per box, and every sync re-applies that one definition instead of trusting each firewall to keep its own copy current.
The bind password lives in one secret variable, not in every snippet
Notice ldap_bindpw above isn’t a password — it’s ${ldap_bind_password}, a reference to a secret variable. That’s not a style choice: a literal password in the snippet content is refused outright. Set the real value once, off the command line entirely so it never lands in shell history or shows up to another user running ps:
NetDefense resolves that reference for each device when it builds that device’s sync. Change the password in your directory, update the variable once, and every device that uses it shows as out of sync and picks up the new value on its next sync — instead of an evening spent updating it on each box by hand.
The snippet itself never holds the password, and once it’s set, the web app, ndcli and the API only ever show the variable back redacted. The password itself still reaches each firewall: OPNsense stores it in plain text in its own config.xml and in the device’s local configuration backups (/conf/backup), and NetDefense’s own encrypted configuration backups carry it too. Anyone with root on the device — including through a full-access remote session — can read it. Rotate the password on the directory side whenever a device that used it leaves your fleet.
Let the directory decide who gets in
Authentication servers pair with NetDefense’s own group management. Mark a GROUP snippet as directory-owned ("external_members": true), give it the privileges you want, and name it in the server’s Limit groups. From then on, the directory decides who’s in that group — not a list you maintain by hand. OPNsense’s built-in admins group and NetDefense’s own netdefense-readonly group are deliberately protected: a directory synced through a server NetDefense manages can never take control of either one.
{ "name": "corp-engineering", "priv": ["page-firewall-rules-edit"], "external_members": true}Add these keys to the server snippet above, naming every group you want it to populate:
{ "ldap_read_properties": true, "ldap_sync_memberof": true, "ldap_sync_memberof_groups": "corp-engineering,corp-support", "ldap_sync_create_local_users": true}(corp-support would be a second directory-owned GROUP snippet, defined the same way as corp-engineering above and delivered to the same device.)
Unscoped group sync is refused, not just discouraged
Every name in ldap_sync_memberof_groups has to be one of these directory-owned GROUP snippets, delivered to the same device — NetDefense checks that on every sync, and a name that doesn’t resolve that way fails the sync outright rather than half-applying. NetDefense also refuses to create a server that syncs memberOf without a scoped list like this one in the first place: an unscoped sync would match a directory group against every local group by name, admins included.
Add someone to corp-engineering in Active Directory and, the next time they sign in, they get that group’s WebGUI access on every firewall that carries the server, the group, and a login order naming the server (more on that next). Take them out of the group and their access follows at their next login. Accounts the directory creates are WebGUI-only: OPNsense gives them no login shell, so they never get password SSH, console, or su/sudo access. Keep each username either local or directory-provisioned, not both. Nobody has to remember to also update a NetDefense group when HR processes an offboarding.
A login order engineered so you can’t lock yourself out
A server only ever takes part in login once an order names it. Which directory (or directories) get tried, and in what order, is a second, deliberately separate piece: the login order.
{ "facilities": { "webadmin": { "order": ["Local Database", "Corp AD", "HQ-LDAP"] } }}(HQ-LDAP here is a second authentication server already delivered to the device — NetDefense-authored or hand-made, either is fine as long as the name resolves.)
The safety property that matters most here isn’t a setting you have to remember — it’s enforced on every order NetDefense writes: Local Database always goes first. A dead directory server costs real seconds on a login attempt while OPNsense waits out its connection timeout, but it never costs you the whole box. A local account keeps working even when every directory behind it is unreachable.
Typos fail safe, not silently
A mistyped server name in an order is caught at sync time, not glossed over — the sync fails with the exact name that didn’t resolve, and the login order is left exactly as it was rather than written half-correct. Everything else in that same sync — firewall rules, aliases, everything else — still applies; only the login-order write is skipped until you fix the typo.
Safety rails, not just a settings page
Handing a directory control over who can log into a firewall is exactly the kind of change that deserves guardrails, so this feature ships with several:
- A version floor. Every device needs OPNsense 26.1.6 or later before NetDefense will write an authentication server or a login order to it. The floor exists in part because 26.1.6 fixed an LDAP login filter-injection vulnerability (CVE-2026-34578) that affects releases up to 26.1.5 and can bypass an Extended Query group restriction. Deleting is always allowed regardless of version; only writes are gated.
- The same consent switch that guards every other privilege-sensitive push. Creating or updating a server, or writing a login order, requires “Allow All Snippet Content” turned on for that device (Services → NetDefense → Settings, Advanced Settings, Configuration Sync, then Apply) — the same gate that already protects against unexpected privilege grants. It’s in the protective state by default on a fresh install; a device upgraded from before agent v1.14.0 may already be permissive, so check the setting rather than assuming. Deleting a server is never gated.
- Hand-made servers get none of NetDefense’s guardrails. If a server already exists on a device because someone configured it by hand through OPNsense’s own page, NetDefense will still include it by name in a login order — and warns you when it does — but it never modifies, adopts, or manages it, and none of NetDefense’s own guardrails apply to it, so checking its settings is on you. A same-named collision between a hand-made server and one NetDefense is about to create fails outright rather than quietly overwriting either one.
- Clean teardown. Decommissioning a device removes the authentication servers NetDefense created on it, and — as long as the login order hasn’t been hand-edited since NetDefense last wrote it — resets that order back to just the local account too. Two things stay yours to handle afterward: rotate the directory-side bind password, since the device’s own configuration backups still hold it, and remove any local accounts the directory auto-created, which NetDefense doesn’t own or clean up.
Manage it from wherever you already work
This isn’t a separate tool bolted onto the side — it’s the same snippet and variable model you already use for everything else, so it’s available everywhere that model is:
- The web app. Authentication servers and login orders show up alongside every other snippet type when you create or manage content.
ndcli, exactly as shown above —snippet create --type AUTH_SERVER,snippet create --type AUTH_ORDER,variable org create --secret.- An AI assistant, through the NetDefense MCP server. The same MCP tools that create, update, or delete any snippet cover authentication servers and login orders too. One thing they deliberately can’t do: write a secret value. Ask an AI assistant to roll out a directory server and it can — but a person sets the bind password itself, either on the web app’s Variables page or from a terminal running
ndcli. Setting it never goes through an MCP tool call.
Getting started
You’ll need NDAgent 1.19.2 or later and OPNsense 26.1.6 or later on any device you want to manage this way, with its Allow All Snippet Content setting turned on — a local, on-device switch NetDefense deliberately can’t flip for you — and the Superuser role in your organization to author authentication servers, login orders, and the directory-owned GROUP snippet (external_members: true) itself; attaching those existing snippets to a device or template only needs Read-Write. Use ndcli 1.35.0 or later if you’re working from the command line or through the MCP server. The web app already has it built in — nothing to install. If your directory’s certificate comes from an internal CA — the common case for Active Directory — import that CA into each device’s trust store first (System > Trust > Authorities); NetDefense doesn’t manage CAs, and OPNsense validates LDAPS/StartTLS against the device’s own trust store.
Read the full Authentication Servers guide for the complete walkthrough, including the recovery steps if a login-order change ever leaves a device’s WebGUI unreachable.
Join the discussion in our Community