Node Access Control
Every noBGP node ships ready to be operated remotely: your AI assistant can run commands and read or write files on it, and the event bus can watch paths and dispatch work. That is the point of the product, and it is why an agent behind CGNAT (carrier-grade NAT) is useful at all.
It is also more reach than some machines should offer. Three settings on the node let its owner narrow that reach — from the box itself, in the agent's own config, where nothing on the network can override them.
The three settings
| Setting | Governs | Default |
|---|---|---|
allow-tools | Which capability domains this node serves: fs, command | both |
allow-roots | Which filesystem roots the fs tools and the fs event source may touch — never the agent's own directory | / (everything else) |
allow-admin | Whether work may run as root / Administrator | true |
Both user and allow-admin are set on the machine and only there. There is deliberately no tool to change them: altering the identity that gates a channel, through that channel, is using a tool to widen what the tool may do.
They are ANDed: any one of them saying no is a refusal. The values of allow-tools are domains, not tool names — fs covers fs_read, fs_write, file, fs_subscribe and friends; command covers command, command_subscribe and the shell behind a published terminal service.
# Read-only node: files may be read and watched, nothing may be executed
sudo nobgp config --allow-tools=fs
# Confine file access to one tree
sudo nobgp config --allow-roots=/var/log,/etc/myapp
# No root: work drops to the account named by --user
sudo nobgp config --allow-admin=false --user=deploy
# Read them back at any time
nobgp show
nobgp status # includes an `allow:` block
Changes take effect without a restart — the agent watches its own config.
A node that upgraded into a denied state would need someone physically at it, which on a NAT'd machine is not a conservative default — it is an unrecoverable one. So all three ship permissive, and tightening is always an explicit act by the node's owner.
What these settings govern
Every remote path onto the node — the MCP tools your AI assistant calls, the event-bus sources the router dispatches, and, since agent 0.4.33, published terminal services as well.
So on a node with allow-tools emptied:
| Access path | Result |
|---|---|
AI assistant calling the command tool | refused |
AI assistant reading files via fs_read | refused |
| Event-bus source (fs watch, dispatched command) | refused, with the reason |
| Browser terminal from a published service | refused |
The same goes for allow-admin: anything that would run as uid 0 is refused, whether it comes from an MCP caller, a dispatched command, a file operation, or a terminal service published with admin. That includes an unelevated request on a node with no usable user configured — a container, a bare-root install — because there is nothing lesser to fall back to there, which is why the veto is an off switch on those nodes rather than a narrowing. It also covers a node whose configured user is a superuser account: the gate asks what uid the work resolves to, never how the account is spelled.
Before agent 0.4.33 a published terminal service was not governed by these keys, on the reasoning that it kept a locked-down node recoverable without a trip to the machine.
That exemption also meant allow-admin: false could not do the one thing its name promises: a service published to run as root handed out root on a node whose owner had refused exactly that. The exemption is gone, and the recovery advice moved to the moment of the change — nobgp config now warns when a write leaves a node serving nothing, and asks before turning off superuser execution on a node where that removes remote execution entirely.
On a machine behind CGNAT, sudo nobgp config --allow-tools=fs (dropping command) closes the browser terminal too, and allow-admin: false with no user configured — a container, a bare-root install — or on Windows refuses every session outright. In those cases the only way back is console, RDP or SSH access to the box.
The usual answer is to keep the veto and give it somewhere to land: sudo nobgp config --allow-admin=false --user=deploy refuses the superuser while leaving the node fully operable as deploy. The --user account must already exist on the machine — nobgp config refuses a name it cannot resolve rather than letting every later session fail to start.
The agent's own directory is never served
Since agent 0.4.34 the fs tools and fs event sources refuse every path inside the agent's own configuration directory, whatever the three settings say:
| Platform | Directory |
|---|---|
| Linux | /etc/nobgp |
| macOS | /usr/local/etc/nobgp |
| Windows | C:\ProgramData\nobgp |
allow-roots cannot widen it and allow-admin: true does not open it — the refusal is a property of the path, and symlinks are resolved first, so a link pointing into that directory is refused the same way. The reason is what lives there: the node's network key and its JWT, and the config file these very settings are read from. Defaults are permissive, so on a stock node each of those was one fs_read away, and a caller holding fs could have edited away the veto meant to confine it.
The refusal names itself, so it is not mistaken for a narrow allow-roots and answered by widening one. And it bounds the file tools, not the machine: a command session running as an account with permission to read those files still can — closing that door is what allow-tools without command, or allow-admin: false, is for.
Recovering a node you have locked down
If you drop command from allow-tools, or set allow-admin: false on a node with no unprivileged user to fall back to, remote execution is gone until you change the setting back — including from a published terminal service. nobgp config warns you at the moment of the change for exactly this reason, and asks for confirmation when the change turns remote execution off.
The way back in is on the machine itself (console, RDP, SSH, local keyboard):
sudo nobgp config --allow-tools=fs,command
sudo nobgp config --allow-admin=true
A published terminal service still reaches a node that kept command — narrowing allow-roots, or dropping only fs, leaves the terminal working.
Diagnostics keep answering either way: presence events are published by the router, and net_peers / net_metrics are served by the agent outside the allow-tools domains (which cover only fs and command) — so you can still see that the node is alive and connected while its tools are off.
Checking what a node will refuse
nobgp status reports the effective settings and warns when a node has narrowed its own remote access:
nobgp status
allow:
tools: [fs]
roots: [/]
admin: true
warning: 'allow-tools excludes "command": remote execution is off on this node,
published terminal services included.'
A node that serves neither domain reports the stronger form instead — allow-tools is empty: this node serves no commands, terminal sessions or file access. Nothing remote reaches it — re-enable on-device.
From the calling side, a node that refuses a bus source says so rather than going quiet — the subscription reports refused with the reason, so "this node is not doing what I asked" is never something you have to infer from silence.
Related
- Interactive Terminals — the two access paths these settings govern
- Publishing Services — how terminal services are created and authorized
- CLI Reference — full flag reference