Commit Graph
7 Commits
Author SHA1 Message Date
mlsmaycon d2f93fcd90 [management] Confine the activity writes to the reverse proxy
The user half reused nothing: SaveUserLastLogin already exists and is the
same call the dashboard and device login paths make, so the parallel
RefreshUserLastLogin is gone and the proxy uses the established one.

Reaching it no longer widens shared interfaces. The proxy service already
receives the store, narrowed to ProxyTokenChecker; that interface now
carries the two writes the proxy makes, so users.Manager, peers.Manager and
Peer are untouched and the exclusion predicate moved into the proxy package
next to its only caller.

RefreshPeerLastSeen stays on the store because nothing there fits:
SavePeerStatus rewrites the connected flag and session token from a caller
snapshot, which would race the sync stream that owns them.
2026-08-09 08:11:30 +00:00
mlsmaycon 48d9161056 [management] Stamp proxy peer activity with the database clock
The activity write took a Go-side timestamp, which is exactly what
MarkPeerConnectedIfNewerSession documents as the cause of previous ordering
bugs: a value read before the write can land after a connect that stamped
CURRENT_TIMESTAMP, dragging LastSeen backwards.

The write now uses the database clock like the other status writers, so the
column only ever moves forward. The throttle is unaffected; it reads the
peer already in hand and never needed the write's timestamp.
2026-08-09 07:38:35 +00:00
mlsmaycon 356f6bdda0 [management] Record proxy logins and mesh activity for active-user accounting
Activity accounting counts a user as active from their last login or from a
peer of theirs being seen. Neither timestamp moved when someone reached a
service through the reverse proxy, so a person who only ever uses
proxy-protected services and never opens the dashboard has no login on
record at all and is skipped outright.

The two proxy entry points mean different things, so they write different
things. GenerateSessionToken is only reached after an ID token was verified,
so a completed SSO sign-in records a login on the user. ValidateTunnelPeer
authorises by tunnel IP with no IdP involved, so it records that the peer
was seen instead; the owner counts through that. Both write on the granted
path only, in UTC, and log and drop failures — no authorisation decision
reads them back.

The peer write is throttled to once an hour against the peer already in
hand, so a busy peer does not rewrite its row behind every request. Both
store methods update one column and leave the session-ownership fields to
the sync stream that owns them.

Peers that accounting excludes, embedded proxy peers and browser clients,
are skipped rather than written for nothing.
2026-08-09 07:31:18 +00:00
Maycon Santos 7aebdd69dd [management, client, proxy] add expose NetBird-only services over tunnel peers (#6226)
Adds a new "private" service mode for the reverse proxy: services reachable exclusively over the embedded WireGuard tunnel, gated by per-peer group membership instead of operator auth schemes.

Wire contract
- ProxyMapping.private (field 13): the proxy MUST call ValidateTunnelPeer and fail closed; operator schemes are bypassed.
- ProxyCapabilities.private (4) + supports_private_service (5): capability gate. Management never streams private mappings to proxies that don't claim the capability; the broadcast path applies the same filter via filterMappingsForProxy.
- ValidateTunnelPeer RPC: resolves an inbound tunnel IP to a peer, checks the peer's groups against service.AccessGroups, and mints a session JWT on success. checkPeerGroupAccess fails closed when a private service has empty AccessGroups.
- ValidateSession/ValidateTunnelPeer responses now carry peer_group_ids + peer_group_names so the proxy can authorise policy-aware middlewares without an extra management round-trip.
- ProxyInboundListener + SendStatusUpdate.inbound_listener: per-account inbound listener state surfaced to dashboards.
- PathTargetOptions.direct_upstream (11): bypass the embedded NetBird client and dial the target via the proxy host's network stack for upstreams reachable without WireGuard.

Data model
- Service.Private (bool) + Service.AccessGroups ([]string, JSON- serialised). Validate() rejects bearer auth on private services. Copy() deep-copies AccessGroups. pgx getServices loads the columns.
- DomainConfig.Private threaded into the proxy auth middleware. Request handler routes private services through forwardWithTunnelPeer and returns 403 on validation failure.
- Account-level SynthesizePrivateServiceZones (synthetic DNS) and injectPrivateServicePolicies (synthetic ACL) gate on len(svc.AccessGroups) > 0.

Proxy
- /netbird proxy --private (embedded mode) flag; Config.Private in proxy/lifecycle.go.
- Per-account inbound listener (proxy/inbound.go) binding HTTP/HTTPS on the embedded NetBird client's WireGuard tunnel netstack.
- proxy/internal/auth/tunnel_cache: ValidateTunnelPeer response cache with single-flight de-duplication and per-account eviction.
- Local peerstore short-circuit: when the inbound IP isn't in the account roster, deny fast without an RPC.
- proxy/server.go reports SupportsPrivateService=true and redacts the full ProxyMapping JSON from info logs (auth_token + header-auth hashed values now only at debug level).

Identity forwarding
- ValidateSessionJWT returns user_id, email, method, groups, group_names. sessionkey.Claims carries Email + Groups + GroupNames so the proxy can stamp identity onto upstream requests without an extra management round-trip on every cookie-bearing request.
- CapturedData carries userEmail / userGroups / userGroupNames; the proxy stamps X-NetBird-User and X-NetBird-Groups on r.Out from the authenticated identity (strips client-supplied values first to prevent spoofing).
- AccessLog.UserGroups: access-log enrichment captures the user's group memberships at write time so the dashboard can render group context without reverse-resolving stale memberships.

OpenAPI/dashboard surface
- ReverseProxyService gains private + access_groups; ReverseProxyCluster gains private + supports_private. ReverseProxyTarget target_type enum gains "cluster". ServiceTargetOptions gains direct_upstream. ProxyAccessLog gains user_groups.
2026-05-25 17:41:50 +02:00
f53155562f [management, reverse proxy] Add reverse proxy feature (#5291)
* implement reverse proxy


---------

Co-authored-by: Alisdair MacLeod <git@alisdairmacleod.co.uk>
Co-authored-by: mlsmaycon <mlsmaycon@gmail.com>
Co-authored-by: Eduard Gert <kontakt@eduardgert.de>
Co-authored-by: Viktor Liu <viktor@netbird.io>
Co-authored-by: Diego Noguês <diego.sure@gmail.com>
Co-authored-by: Diego Noguês <49420+diegocn@users.noreply.github.com>
Co-authored-by: Bethuel Mmbaga <bethuelmbaga12@gmail.com>
Co-authored-by: Zoltan Papp <zoltan.pmail@gmail.com>
Co-authored-by: Ashley Mensah <ashleyamo982@gmail.com>
2026-02-13 19:37:43 +01:00
Zoltan Papp 58daa674ef [Management/Client] Trigger debug bundle runs from API/Dashboard (#4592) (#4832)
This PR adds the ability to trigger debug bundle generation remotely from the Management API/Dashboard.
2026-01-19 11:22:16 +01:00
Pascal Fischer 7193bd2da7 [management] Refactor network map controller (#4789) 2025-12-02 12:34:28 +01:00