[doc] Document per-target reverse proxy access control (#1014)

* [doc] Document per-target reverse proxy access control

* docs: screenshots, when-to-use and Bypass warning for target access actions

- Add screenshots of the target Access setting and the target-list indicators
- Add "When to use per-target access actions"
- Warn that Bypass authentication makes the path public
- Note that a Block on /admin/ does not cover /admin
- Access logs: describe the User-column icon and tooltip; document access_action=invalid_path

* docs: tighten target access wording

* docs: say where the access log icons appear

---------

Co-authored-by: Jack Carter <128555021+SunsetDrifter@users.noreply.github.com>
This commit is contained in:
Maycon Santos
2026-10-15 16:07:02 +02:00
committed by GitHub
co-authored by Jack Carter
parent 6f6ad52072
commit cd63a59360
5 changed files with 73 additions and 14 deletions
@@ -37,9 +37,10 @@ Every log entry (HTTP and L4) shares a common set of fields. Some fields are onl
| **Bytes Downloaded** | Bytes sent from backend to client | Yes | Yes |
| **Source IP** | The client's IP address | Yes | Yes |
| **Location** | Country, city, and subdivision based on source IP geolocation | Yes | Yes |
| **Auth Method** | Raw `auth_method_used` value: `oidc` (shown as SSO in the dashboard), `password`, `pin`, or `header`. For denied requests, carries the restriction code instead (e.g. `ip_restricted`, `crowdsec_ban`). Omitted from the API response when empty | Yes | Restriction code on denials |
| **Auth Method** | Raw `auth_method_used` value: `oidc` (shown as SSO in the dashboard), `password`, `pin`, `header`, or a target access action such as `path_bypass` or `path_block`. For denied requests, carries the restriction code instead (e.g. `ip_restricted`, `crowdsec_ban`). Omitted from the API response when empty | Yes | Restriction code on denials |
| **User** | The authenticated user's ID, set when `oidc` authentication was used. Omitted from the API response when empty | Yes | N/A |
| **Reason** | Exactly one of two values: `Authentication failed` when authentication or an access restriction rejected the request, or `Request failed` when an authenticated request returned `4xx`/`5xx`. Set for HTTP entries only and omitted from the API response when empty. Never a specific denial code: see the note under [Deny reasons](#deny-reasons) | Yes | Omitted |
| **Metadata** | Additional decision details. Target access records `access_action` as `bypass`, `block`, or `invalid_path` (an ambiguous request path rejected with `400`); CrowdSec records its mode and verdict here | Yes | Yes |
## Understanding log entries
@@ -47,8 +48,8 @@ Every log entry (HTTP and L4) shares a common set of fields. Some fields are onl
HTTP log entries fall into three categories based on the status code:
- **Allowed requests**: successful requests show a `2xx` status code along with the authentication method used to access the service.
- **Denied requests**: failed authentication or access restriction blocks show `401` or `403` status codes with `reason` set to `Authentication failed`. The specific cause (invalid password, missing SSO session, IP restricted, country restricted, CrowdSec verdict) is carried in `auth_method_used`, not in `reason`.
- **Allowed requests**: successful requests show a `2xx` status code along with the authentication method used to access the service. A target that bypasses authentication records `path_bypass`. The dashboard marks these entries with a small open-lock icon in the **User** column, at the right end of the row, labeled **Auth Bypassed** on hover.
- **Denied requests**: failed authentication, access restriction blocks, and blocked target paths show `401` or `403` status codes with `reason` set to `Authentication failed`. The specific cause (invalid password, missing SSO session, blocked path, IP restricted, country restricted, CrowdSec verdict) is carried in `auth_method_used`, not in `reason`. A blocked target path records `path_block`. The dashboard marks these entries with a small shield icon in the **User** column, at the right end of the row, labeled **Path Blocked** on hover.
- **Errors**: backend errors or proxy issues show `5xx` status codes. These typically indicate that the target service is unreachable or returned an error.
### L4 log entries
@@ -63,6 +64,7 @@ The following deny reasons identify why a connection was rejected. Note that for
| Reason | Description |
|--------|-------------|
| `path_block` | The matching HTTP target is configured to block access |
| `ip_restricted` | The client IP was blocked by a CIDR access restriction |
| `country_restricted` | The client's country was blocked by a country access restriction |
| `geo_unavailable` | Country restrictions are configured but the GeoIP database is unavailable (fail-closed) |
@@ -1,11 +1,11 @@
import {Note, Warning} from "@/components/mdx"
export const description =
'Configure SSO, password, PIN, and header authentication methods, plus IP and country access restrictions, for NetBird Reverse Proxy services.'
'Configure service authentication, per-target access actions, and IP, country, and reputation restrictions for NetBird Reverse Proxy services.'
# Reverse Proxy Authentication and Access Restrictions
NetBird Reverse Proxy supports multiple authentication methods and connection-level access restrictions to control who can access your exposed services. You can enable one or more methods on each service, or leave a service completely public. Authentication and access restrictions are configured per service in the **Authentication** tab when creating or editing a service.
NetBird Reverse Proxy supports multiple authentication methods and connection-level access restrictions to control who can access your exposed services. You can enable one or more methods on each service, leave a service completely public, or choose a different authentication action for an individual HTTP target path. Authentication and access restrictions are configured when creating or editing a service.
<p>
<img src="/docs-static/img/manage/reverse-proxy/authentication/reverse-proxy-add-service-auth.png" alt="Authentication tab showing all available authentication methods" className="imagewrapper"/>
@@ -175,6 +175,59 @@ Services can also be configured without any authentication. When no authenticati
**Best for:** Public-facing websites, APIs that handle their own authentication internally, or services that are intentionally open to the internet.
## Per-target access actions
HTTP targets can override the service authentication behavior for their matching path. Open or add a target, expand **Optional Settings**, and choose **Access**:
| Action | Behavior |
|--------|----------|
| **Use service authentication** | Apply the authentication configured on the service. This is the default. |
| **Bypass authentication** | Skip SSO, password, PIN, and header authentication for requests routed to this target. Service-level access restrictions still apply. |
| **Block access** | Return `403` for requests routed to this target without contacting its backend. |
<p>
<img src="/docs-static/img/manage/reverse-proxy/authentication/target-access-setting.png" alt="Edit Target modal with Optional Settings expanded, showing the Access dropdown and its three options: Use service authentication, Bypass authentication, and Block access" className="imagewrapper"/>
</p>
For example, a service can require SSO on its `/` target, use **Bypass authentication** for `/public/`, and use **Block access** for `/admin/`. Target selection uses the longest matching, case-sensitive literal prefix. It does not support glob patterns or regular expressions. See [Path-based routing](/manage/reverse-proxy#path-based-routing) for matching examples and forwarding behavior.
The action only controls reverse proxy authentication for the selected target. **Bypass authentication** does not bypass CIDR, country, or CrowdSec restrictions configured on the service. It also does not change path rewriting; the existing **Preserve Full Path** setting continues to control whether the matched prefix is sent to the backend.
Targets that override the default are marked in target lists. Hover the access indicator to see its action.
<p>
<img src="/docs-static/img/manage/reverse-proxy/authentication/target-access-badges.png" alt="Services list with a service expanded to show its three targets: / with no indicator, /public/ with an open-lock indicator whose tooltip reads Bypass authentication, and /admin/ with a red shield indicator for Block access" className="imagewrapper"/>
</p>
### When to use per-target access actions
Most services need one rule for every path, so leave targets on **Use service authentication** unless a specific path has to behave differently from the rest of the service.
Use **Bypass authentication** when clients that cannot complete a login must reach a path, and the path either holds nothing sensitive or the backend authorizes requests itself:
- **Webhook receivers**, such as `/webhooks/`, where a third-party service posts events and the backend verifies the request signature.
- **Health checks**, such as `/healthz`, polled by an external uptime monitor.
- **Public assets**, such as `/public/` or `/static/`, that hold nothing sensitive.
Use **Block access** when a path should never be reachable through the public domain, even by users who pass service authentication, such as `/admin/` or `/metrics`. Reach those paths over NetBird instead, for example through a [NetBird-Only](#net-bird-only-access-private-services) service or a [Network resource](/manage/networks).
For **Block access**, prefer the broader prefix. A target on `/admin/` blocks `/admin/users` but not `/admin` itself, which falls through to the next matching target, such as the `/` target with service authentication. To block both, use `/admin`, which also matches `/administrator`.
Do not use **Bypass authentication** to make a whole application public. If every path should be public, create the service without authentication, so the service settings show its real exposure.
<Warning>
**Bypass authentication makes the path public.** Anyone who can reach the service domain and passes its CIDR, country, and CrowdSec restrictions can request every path under the bypassed prefix. Requests arrive at the backend with no NetBird user identity, so the backend must authorize them on its own.
- Bypass the narrowest prefix that works. Prefixes match as text, so `/public` also matches `/public-admin`; end the path with `/` to match a single segment.
- Disabling or deleting a **Block access** target removes its rule. Requests for that path then fall through to the next matching target, which may be a bypassed one.
- **Custom Headers** configured on the target are still sent to the backend. Do not attach credentials to a bypassed target through headers.
- When any target uses an access action, the proxy rejects ambiguous request paths, such as those with `..` segments, `//`, or encoded separators, with `400` before matching. This stops a request like `/public/../admin/` from reaching a protected path through a bypassed prefix.
</Warning>
<Note>
Per-target access actions are available only for HTTP services. Upgrade all proxy instances in the selected cluster before using them. Older proxies ignore these actions and continue applying the service's authentication settings. **Bypass authentication** is unavailable for NetBird-Only services and Agent Network targets.
</Note>
## Combining authentication methods
You can enable multiple **operator auth methods** on a single service simultaneously. When more than one is active, users authenticate using **any** of the enabled methods — they choose which one to use when accessing the service.
@@ -201,6 +254,8 @@ Access restrictions control which connections are allowed to reach your service
Access restrictions are evaluated **before** authentication. If a connection is blocked by an access restriction rule, it is rejected immediately without any authentication check.
These restrictions also apply to targets set to **Bypass authentication**. A target action cannot relax a service-level CIDR, country, or CrowdSec denial.
<p>
<img src="/docs-static/img/manage/reverse-proxy/authentication/access-restrictions-geo-ip.png" alt="Authentication tab showing all available authentication methods" className="imagewrapper"/>
</p>
+11 -9
View File
@@ -92,6 +92,7 @@ Target properties vary by service mode:
- **Path** (optional) - a URL path prefix for path-based routing (e.g., `/api`). See [Path-based routing](#path-based-routing) below.
- **Protocol** - `HTTP` or `HTTPS`, depending on what the backend service speaks
- **Port** - the port on the target machine (defaults to `80` for HTTP, `443` for HTTPS)
- **Access** (optional) - use the service authentication, bypass authentication, or block access for the target's matching path. Configure this under **Optional Settings**. See [Per-target access actions](/manage/reverse-proxy/authentication#per-target-access-actions).
- **Enabled/Disabled toggle** - individually enable or disable targets without removing them
**L4 services (TCP, UDP, TLS):**
@@ -263,6 +264,7 @@ In the **Details** tab:
6. In the target configuration, select the **type** (Peer, Host, Domain, Subnet, or Proxy Cluster), then choose the specific peer, resource, or cluster.
7. For HTTP services, set the **protocol** (HTTP or HTTPS) and **port** for the target. Optionally, enter a **path** for path-based routing. For L4 services, set the target **host/IP** and **port**. For **Proxy Cluster** targets, the host field accepts any hostname or IP the cluster's embedded proxy can resolve from its own host stack — see [Private services](/manage/reverse-proxy/bring-your-own-proxy#private-services-net-bird-only-access) for details.
8. For an HTTP target, expand **Optional Settings** and choose an **Access** action if this path should differ from the service default. **Use service authentication** is the default. See [Per-target access actions](/manage/reverse-proxy/authentication#per-target-access-actions).
<p>
<img src="/docs-static/img/manage/reverse-proxy/reverse-proxy-add-target.png" alt="Add Target configuration modal showing the unified Peer / Resource / Proxy Cluster picker" className="imagewrapper"/>
@@ -405,21 +407,21 @@ The proxy's main port always runs an SNI router that peeks at the TLS ClientHell
## Path-based routing
When a service has multiple targets, you can assign each target a unique path prefix to route different URL paths to different backends. For example:
When a service has multiple targets, you can assign each target a unique path prefix to route different URL paths to different backends. Each HTTP target can also choose what happens after its path matches:
| Path | Target | Description |
|------|--------|-------------|
| `/` | Peer A (port 3000) | Main web application |
| `/api` | Peer B (port 8080) | API service |
| `/docs` | Resource C (port 80) | Documentation server |
| Path | Target | Access | Example result |
|------|--------|--------|----------------|
| `/` | Peer A (port 3000) | Use service authentication | `/account` uses the authentication configured on the service |
| `/public/` | Peer B (port 8080) | Bypass authentication | `/public/logo.svg` reaches Peer B without service authentication |
| `/admin/` | Resource C (port 80) | Block access | `/admin/users` returns `403`; Resource C is not contacted |
Incoming requests are matched against the configured path prefixes and forwarded to the corresponding target. Each path must be unique within a service.
Incoming requests are matched against the configured path prefixes. When an enabled target uses **Bypass authentication** or **Block access**, all enabled target paths must be unique within the service. If more than one prefix matches, the **longest matching prefix** wins. In the example above, `/public/logo.svg` matches both `/` and `/public/`, so the `/public/` target and its access action are selected.
This is useful for consolidating multiple internal services under a single public domain, reducing the number of domains and TLS certificates you need to manage.
Prefixes match the request path as text, not by path segment, so a target on `/api` also receives `/api-docs`. To match a whole segment, end the path with a slash: a target on `/api/` receives `/api/x`, but not `/api-docs` or `/api` itself.
Prefix matching is literal and case-sensitive. Glob patterns such as `*` or `**` and regular expressions are not supported. Prefixes match the request path as text, not by path segment, so a target on `/api` also receives `/api-docs`. To match a whole segment, end the path with a slash: a target on `/api/` receives `/api/x`, but not `/api-docs` or `/api` itself. Likewise, `/Public/x` does not match `/public/`.
By default, the matched prefix is removed before the request reaches the backend: `/api/x` arrives as `/x`, and `/api-docs` as `/-docs`. To keep the full path, turn on **Preserve Full Path** for the target (`path_rewrite: preserve` in the API).
The access action does not change how paths are forwarded. By default, the matched prefix is removed before the request reaches the backend: `/api/x` arrives as `/x`, and `/api-docs` as `/-docs`. To keep the full path, use the existing **Preserve Full Path** target setting (`path_rewrite: preserve` in the API).
## Integration with Networks