mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-13 10:19:07 +02:00
Add a small proof-of-concept command (client/embed/example/agentproxy) that embeds the NetBird client in userspace/netstack mode and exposes a local HTTP listener on 127.0.0.1:8080. Incoming requests are reverse-proxied over the encrypted NetBird tunnel to an upstream Agent Network endpoint (e.g. https://mirror.netbird.ai). The embedded client authenticates like a regular client: interactive SSO by default, or a setup key supplied via NB_SETUP_KEY. Because it runs entirely in userspace and only binds a loopback socket, it works without root and in rootless containers (OpenShift, Podman). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
95 lines
3.7 KiB
Markdown
95 lines
3.7 KiB
Markdown
# agentproxy — a rootless local gateway into a NetBird Agent Network
|
|
|
|
`agentproxy` is a small proof-of-concept that turns any machine into a local
|
|
HTTP gateway into a [NetBird Agent Network](../../../../agent-network). It:
|
|
|
|
1. embeds the NetBird client in **userspace / netstack** mode — no TUN device,
|
|
no `CAP_NET_ADMIN`, **no root**;
|
|
2. connects to NetBird the way a regular client does — **interactive SSO** by
|
|
default, or a **setup key** from the environment when one is supplied;
|
|
3. runs a plain HTTP listener on `127.0.0.1:8080` and **reverse-proxies every
|
|
request over the encrypted NetBird tunnel** to an upstream Agent Network
|
|
endpoint (e.g. `https://mirror.netbird.ai`).
|
|
|
|
Because it only binds a loopback socket and never touches the kernel network
|
|
stack, it runs on locked-down laptops and in **rootless containers**
|
|
(OpenShift, Podman, distroless) where the standard agent cannot.
|
|
|
|
Point an AI agent (Claude Code, Codex, …) at `http://localhost:8080` and its
|
|
traffic flows through the identity-aware Agent Network proxy — with no API keys
|
|
handed to the agent.
|
|
|
|
## Build
|
|
|
|
```bash
|
|
go build -o agentproxy ./client/embed/example/agentproxy
|
|
```
|
|
|
|
## Run
|
|
|
|
Interactive SSO login (opens a browser, or prints the URL + device code when
|
|
there is no desktop session):
|
|
|
|
```bash
|
|
./agentproxy -upstream https://mirror.netbird.ai
|
|
```
|
|
|
|
Non-interactive, with a setup key (ideal for containers/CI):
|
|
|
|
```bash
|
|
NB_SETUP_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
|
|
./agentproxy -upstream https://mirror.netbird.ai
|
|
```
|
|
|
|
Then use it:
|
|
|
|
```bash
|
|
export ANTHROPIC_BASE_URL=http://localhost:8080
|
|
# ... run your agent ...
|
|
```
|
|
|
|
## Configuration
|
|
|
|
Flags take precedence over environment variables.
|
|
|
|
| Flag | Env var | Default | Description |
|
|
| --- | --- | --- | --- |
|
|
| `-upstream` | `NB_AGENT_UPSTREAM` | _required_ | Upstream agent network URL |
|
|
| `-listen` | `NB_LISTEN_ADDR` | `127.0.0.1:8080` | Local listen address |
|
|
| `-management-url` | `NB_MANAGEMENT_URL` | `https://api.netbird.io:443` | Management server URL |
|
|
| `-device-name` | `NB_DEVICE_NAME` | `agent-proxy` | Peer name in the network |
|
|
| `-no-browser` | — | `false` | Don't try to open the SSO URL |
|
|
| — | `NB_SETUP_KEY` | _unset_ | Setup key; when set, SSO is skipped |
|
|
| — | `NB_CONFIG_PATH` | in-memory | Persist client config to this path |
|
|
| — | `NB_STATE_PATH` | _unset_ | Persist client state to this path |
|
|
| — | `NB_HINT` | _unset_ | IdP login hint (email) for the SSO screen |
|
|
| — | `NB_LOG_LEVEL` | `warn` | Embedded client log level |
|
|
|
|
By default nothing is written to disk (config and keys live only in memory);
|
|
set `NB_CONFIG_PATH` / `NB_STATE_PATH` to persist the peer identity across
|
|
restarts.
|
|
|
|
## How it works
|
|
|
|
```
|
|
AI agent ──HTTP──▶ 127.0.0.1:8080 (agentproxy)
|
|
│ httputil.ReverseProxy
|
|
│ Transport.DialContext = embedded client dialer
|
|
▼
|
|
NetBird overlay (userspace WireGuard, netstack)
|
|
│ magic DNS resolves e.g. mirror.netbird.ai
|
|
▼
|
|
Agent Network reverse proxy (identity, policy, limits)
|
|
▼
|
|
LLM API / AI gateway
|
|
```
|
|
|
|
The reverse proxy's `Transport.DialContext` is the embedded client's dialer, so
|
|
every upstream connection is established inside the WireGuard tunnel. The
|
|
upstream hostname is resolved by NetBird's magic DNS via the netstack dialer,
|
|
and the outgoing `Host` header is set to the upstream host so TLS SNI and the
|
|
Agent Network's identity-aware routing see the real endpoint.
|
|
|
|
> **Proof of concept.** Intended to demonstrate the embedded-client + local
|
|
> forward-proxy pattern for rootless environments. Not hardened for production.
|