Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d2298c0
feat: add reverse-proxy services and custom domain management
Jul 31, 2026
52d1433
Update README.md
RollLikeRollo Jul 31, 2026
ba6bcf3
Merge branch 'main' into agent-network-proxy
Aug 3, 2026
7c0172e
Fix CodeRabiit suggestion: A failed re-create leaves no domain at all…
Aug 3, 2026
cc82af5
Fix CodeRabbit suggestion: Guard the id lookup on the create response…
Aug 3, 2026
4ad8a94
Fix CodeRabbit suggestion: Report Drift on services - https://github…
Aug 3, 2026
76c5054
Fix CodeRabbit suggestion: Preserve service auth metadata in the expo…
Aug 3, 2026
eff4d1b
Fix CodeRabbit suggestion: Guard the type attribute in selectattr - h…
Aug 3, 2026
adc3e26
Fix CodeRabbit suggestion: The lookup('env') defaults never apply, an…
Aug 3, 2026
2c3ad6d
Fix CodeRabbit suggestion: Later phases depend on resources that this…
Aug 3, 2026
be209f5
Fix CodeRabbit suggestion: These tests leave public services with kno…
Aug 3, 2026
4f68911
Fix Blocker no. 2 - token leak and use delete_proxy_cluster()
Aug 4, 2026
da988c7
Fix README service section duplicate
Aug 4, 2026
4610b0e
Fix Blocker no. 1 - validate: true never fires for its documented use…
Aug 4, 2026
1c4aaee
Fix suggestion no. 3 - find_domain_by_name should filter to type == '…
Aug 4, 2026
e0319ec
Fix suggestion no. 4 - A target_cluster change is delete+recreate (no…
Aug 4, 2026
51196ec
Fix suggestion no. 5 - The export template omits the service auth blo…
Aug 4, 2026
06a3017
Fix suggestion no. 6 - Services are missing from preview_diff_report.yml
Aug 4, 2026
c901350
Fix suggestion no. 7 - The mode: tcp example in defaults/main.yml sen…
Aug 4, 2026
f505579
Changelogs fragments, modules version to 1.4.0
Aug 5, 2026
a82626b
CodeRabbit suggestion https://github.com/netbirdio/ansible-netbird/pu…
Aug 5, 2026
23c4e25
CodeRabbit suggestion https://github.com/netbirdio/ansible-netbird/pu…
Aug 5, 2026
88a6e6c
Fix sanity check pipeline
Aug 5, 2026
2dde30e
Fix: Resolve bearer_auth distribution_groups names to IDs on apply
Aug 24, 2026
4aee3b1
Fix: Service preview diff reports false positives on freshly exported…
Aug 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 52 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ This collection provides comprehensive management of NetBird resources:
- **Tokens** - Create and manage personal access tokens
- **Identity Providers** - Configure identity providers (Google, Okta, Entra, OIDC, etc.)
- **Invites** - Manage user invite links with expiration and regeneration
- **Info** - Gather information about any resource
- **Service Domains** - Manage custom domains for reverse-proxy services
- **Info** - Gather information about any resource (including services, service domains, proxy clusters)

## Requirements

Expand Down Expand Up @@ -579,6 +580,52 @@ Manage NetBird user invites.
state: absent
```

### netbird_service_domain

Manage custom domains for NetBird reverse-proxy services.

```yaml
# Create a custom domain
- name: Add custom domain
community.ansible_netbird.netbird_service_domain:
api_url: "{{ netbird_api_url }}"
api_token: "{{ netbird_api_token }}"
domain: "app.example.com"
target_cluster: "eu.proxy.netbird.io"
state: present

# Create and trigger DNS validation
- name: Add and validate custom domain
community.ansible_netbird.netbird_service_domain:
api_url: "{{ netbird_api_url }}"
api_token: "{{ netbird_api_token }}"
domain: "app.example.com"
target_cluster: "eu.proxy.netbird.io"
validate: true
state: present

# Delete a custom domain
- name: Remove custom domain
community.ansible_netbird.netbird_service_domain:
api_url: "{{ netbird_api_url }}"
api_token: "{{ netbird_api_token }}"
domain: "app.example.com"
state: absent
```

### netbird_proxy_cluster

Remove NetBird self-hosted reverse-proxy clusters.

> **Note:** Proxy clusters are registered automatically by the proxy software; only deletion is available through the API, so this module only supports C(state=absent).

```yaml
- name: "Delete existent cluster"
community.ansible_netbird.netbird_proxy_cluster:
address: "subdomain.proxy.example.com"
state: absent
```

### netbird_info

Gather information about NetBird resources.
Expand Down Expand Up @@ -606,7 +653,7 @@ Gather information about NetBird resources.
register: me
```

Available resources: `accounts`, `users`, `peers`, `groups`, `setup_keys`, `policies`, `networks`, `routes`, `dns_nameservers`, `dns_settings`, `posture_checks`, `events`, `countries`, `current_user`, `identity_providers`, `invites`
Available resources: `accounts`, `users`, `peers`, `groups`, `setup_keys`, `policies`, `networks`, `routes`, `dns_nameservers`, `dns_zones`, `dns_settings`, `posture_checks`, `events`, `countries`, `current_user`, `identity_providers`, `invites`, `services`, `service_domains`, `proxy_clusters`

## Role Usage

Expand Down Expand Up @@ -749,7 +796,7 @@ For inventory-based workflows (e.g., AAP), use the roles directly in your own pl
- **Strict mode** — enforces full IaC by removing resources not defined in YAML
- **Setup key management** — create/rotate enrollment keys with auto_groups name resolution; key values registered for downstream Vault storage
- **Name-based config** — use plain names ("developers") instead of API IDs; resolved automatically
- **Dependency ordering** — resources applied in correct order (settings → posture checks → groups → setup keys → DNS → networks → policies)
- **Dependency ordering** — resources applied in correct order (settings → posture checks → groups → setup keys → DNS → networks → services → policies)
- **Export utility** — captures current API state as clean, ready-to-use YAML config files
- **Roles** — use `community.ansible_netbird.configure` and `community.ansible_netbird.export` directly in your own playbooks for full control

Expand All @@ -759,6 +806,7 @@ For inventory-based workflows (e.g., AAP), use the roles directly in your own pl
my_netbird_config/
├── settings.yml # Account-wide settings
├── networks.yml # Networks with routers and resources
├── services.yml # Reverse-proxy services and custom domains (optional)
├── setup_keys.yml # Peer enrollment keys (optional)
├── access_control/
│ ├── groups.yml # Groups
Expand Down Expand Up @@ -788,6 +836,7 @@ This collection implements the [NetBird REST API](https://docs.netbird.io/api).
- [Networks](https://docs.netbird.io/api/resources/networks)
- [DNS](https://docs.netbird.io/api/resources/dns)
- [Posture Checks](https://docs.netbird.io/api/resources/posture-checks)
- [Services](https://docs.netbird.io/api/resources/services)
- [Identity Providers](https://docs.netbird.io/api/resources/identity-providers)
- [Events](https://docs.netbird.io/api/resources/events)

Expand Down
66 changes: 66 additions & 0 deletions changelogs/fragments/service-domains-and-proxy-clusters.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
major_changes:
- 'Full reverse-proxy service domain and proxy cluster management. Two new
modules (``netbird_service_domain``, ``netbird_proxy_cluster``), two new
``netbird_info`` resource types (``service_domains``, ``proxy_clusters``),
six new API helpers, service ``access_groups`` name resolution, service
drift detection in the diff filter, and end-to-end integration in the
configure role (preview, apply, strict-mode sweep) and export role
(clean + raw output with group-ID-to-name resolution). Includes
integration tests covering domain lifecycle, proxy cluster noop delete,
and service auth variants (bearer, password, PIN). Completes the
``/api/reverse-proxies/*`` surface started in 1.3.0.'

minor_changes:
- 'netbird_service_domain - a ``target_cluster`` change now emits
``module.warn()`` explaining the delete-and-recreate consequences
(new ID, validation reset, bound services may break).'
- 'export role - service and service-domain API fetches are gated so
the role does not 404 on management servers without the reverse-proxy
API.'
- 'export role - service auth metadata (bearer_auth enabled flags and
distribution_groups) is preserved in the exported config.'
- 'defaults/main.yml - added ``netbird_services``,
``netbird_service_domains``, and ``netbird_proxy_clusters_absent``
variables with documented examples.'
- 'config_skeleton/services.yml - added config-as-code skeleton for
services and service domains.'

bugfixes:
- 'netbird_service_domain - ``find_domain_by_name`` now filters to
``type == ''custom''``, skipping free/proxy entries that have an empty
``id``. Matching one of those issued ``DELETE /domains/`` with no ID
path segment.'
- 'netbird_service_domain - ``validate: true`` now triggers validation on
existing unvalidated domains. Previously it only fired on the create
path, where DNS was not yet configured, and was silently ignored on
re-runs when the domain already existed.'
- 'netbird_service_domain - a failed re-create on cluster change now
rolls back to the original cluster instead of leaving the domain
deleted. The create response is also validated before proceeding.'
- 'defaults/main.yml - the ``mode: tcp`` example no longer includes
``path`` and ``protocol: http``, which are L7 options the API rejects
for TCP services.'
- 'export role - password_auth and pin_auth blocks are no longer exported
with empty secrets. An export-then-apply round-trip previously sent
``password: ""`` / ``pin: ""`` to the API, silently producing
unauthenticated services. Only bearer_auth (no secrets) is now
exported; a YAML comment flags the omission.'
- 'export role - guarded the ``type`` attribute in ``selectattr`` filters
for service domains so entries without a type field do not cause
template errors.'
- 'tests/integration/test_services.yml - fixed ``lookup(''env'')``
defaults that never applied and converted string values to proper
types. Conditional blocks now always run so later phases that depend
on their resources are not skipped.'

security_fixes:
- 'tasks/services.yml - the raw ``ansible.builtin.uri`` task for
cluster deletion has been replaced by the new ``netbird_proxy_cluster``
module, which inherits ``no_log: true`` on ``api_token`` from the
shared argument spec. The previous task interpolated
``Authorization: Token ...`` in headers, leaking the PAT under
``-vvvv``.'
- 'tests/integration/test_services.yml - test services with known
credentials (passwords, PINs) are no longer left running on the live
tenant after the test completes.'
38 changes: 38 additions & 0 deletions config_skeleton/services.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
# NetBird Reverse-Proxy Services
#
# Services expose internal resources via the NetBird reverse-proxy
# (Ingress). Each service publishes a domain and forwards to one
# or more backend targets that reference a network resource.
#
# Populate from export: netbird_config_export/services.yml
#
# Services are matched by domain (unique). Targets reference network
# resource IDs (target_id) — find them via export or the dashboard.
# access_groups use plain group names (resolved automatically).
#
# Reference: https://docs.netbird.io/api/resources/services

netbird_services: []
# - domain: "myapp.netbird.example.com"
# name: "My App"
# mode: http # http, tcp, udp, tls
# private: true # overlay-only (http mode only)
# enabled: true
# access_groups:
# - all-users # resolved to ID automatically
# targets:
# - host: "10.0.0.30"
# port: 8080
# protocol: http
# target_id: "subnet-resource-id"
# target_type: subnet # subnet, host, domain, peer, cluster
# enabled: true
# direct_upstream: true
# state: present

netbird_service_domains: []
# - domain: "app.example.com"
# target_cluster: "eu.proxy.netbird.io"
# validate: true
# state: present
64 changes: 64 additions & 0 deletions defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,70 @@ netbird_invites: []
# expires_in: 604800 # 7 days in seconds
# state: present

# Service (reverse-proxy) management
netbird_services: []
# Example:
# netbird_services:
# - domain: "myapp.netbird.example.com"
# name: "My App"
# mode: "http" # http, tcp, udp, tls
# private: true # overlay-only (http)
# enabled: true
# access_groups: # Required when private: true
# - "all-users-group-id"
# targets:
# - host: "10.0.0.30"
# port: 8080
# protocol: http # http, https
# target_id: "subnet-resource-id" # NetBird network resource ID
# target_type: subnet # subnet, host, domain, peer, cluster
# enabled: true
# direct_upstream: true
# skip_tls_verify: false
# path: /
# path_rewrite: preserve
# auth: # public only
# bearer_auth:
# enabled: true
# distribution_groups:
# - "auth-group-id"
# password_auth:
# enabled: false
# password: ""
# pin_auth:
# enabled: false
# pin: ""
# state: present
#
# - domain: "tcp-service.netbird.example.com"
# mode: "tcp"
# private: false
# listen_port: 5432
# targets:
# - host: "10.0.0.50"
# port: 5432
# target_id: "subdomain.netbird.io"
# target_type: cluster
# state: present

# Service custom domain management
# NOTE: Changing target_cluster on an existing domain triggers a
# delete+recreate (no PUT exists). The domain gets a new ID, DNS
# validation is reset, and services bound to it may break.
netbird_service_domains: []
# Example:
# netbird_service_domains:
# - domain: "app.example.com"
# target_cluster: "eu.proxy.netbird.io"
# validate: true
# state: present

# Proxy cluster cleanup (delete-only — no create API)
netbird_proxy_clusters_absent: []
# Example:
# netbird_proxy_clusters_absent:
# - address: "old.proxy.example.com"

# Account settings
netbird_account_settings: {}
# Example:
Expand Down
2 changes: 2 additions & 0 deletions meta/runtime.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ action_groups:
- netbird_peer
- netbird_policy
- netbird_posture_check
- netbird_proxy_cluster
- netbird_route
- netbird_service
- netbird_service_domain
- netbird_setup_key
- netbird_token
- netbird_user
Loading
Loading