README
ยถ
Pulumi NetBird Native Provider
NetBird is a modern, WireGuard-based mesh VPN. This provider integrates NetBird into Pulumi for seamless infrastructure automation.
This repository contains the Pulumi NetBird Provider, a native Pulumi provider built in Go using the pulumi-go-provider SDK. It enables you to manage NetBird resourcesโlike networks, peers, groups, and access rulesโdeclaratively using Pulumi's infrastructure-as-code framework.
โจ Features
- Manage 23 NetBird resource types declaratively using Pulumi (Go, Python, YAML, TypeScript, C#)
- 9 read-only invoke functions (data sources) for referencing existing NetBird objects by name, email, CIDR, or country
- Built natively with Pulumi's Go SDK
- Works with NetBird Cloud (
https://api.netbird.io) and self-hosted management servers
๐ฆ Installing plugin
To install the Pulumi NetBird resource plugin, replace the version number with the desired release if needed. The plugin will be downloaded from the specified GitHub repository.
pulumi plugin install resource netbird 0.5.4 --server github://api.github.com/mbrav/pulumi-netbird
๐งช Build and Test
make help # View available build/test commands
๐๏ธ Examples
All runnable examples live in examples/. The table below summarises what is available:
| Example | Runtime | Description |
|---|---|---|
yaml |
Pulumi YAML | All resources in a single Pulumi.yaml |
yaml-yq |
Pulumi YAML + yq |
Resources split across src/*.yaml, assembled by make build |
go |
Pulumi Go | Provider usage via the generated Go SDK |
python |
Pulumi Python | Provider usage via the generated Python SDK |
See examples/README.md for setup instructions for each example.
๐ Example Usage with Pulumi YAML
You can use this provider with Pulumi YAML to manage NetBird infrastructure declaratively.
1. Setup
Install the plugin (required before first pulumi up):
pulumi plugin install resource netbird 0.5.4 --server github://api.github.com/mbrav/pulumi-netbird
Note:
--serveris a CLI-only flag. Do not add it toPulumi.yamlโ theplugins.providersblock only acceptsname,path(local binary), andversion. For GitHub-hosted plugins, the CLI install above is sufficient.
Navigate to the YAML example directory:
cd examples/yaml
Initialize a new stack. If you are using the local file backend (pulumi login --local), the organization is always the literal string organization โ use a simple name or the organization/<project>/<stack> form:
# Pulumi Cloud
pulumi stack init myorg/myproject/dev
# Local backend
pulumi stack init dev
# or fully qualified:
pulumi stack init organization/myproject/dev
Configure your credentials. Always use --secret for the token so it is encrypted in the stack config file:
pulumi config set --secret netbird:token YOUR_TOKEN
pulumi config set netbird:url https://nb.domain:33073
2. Deploy
pulumi up
This deploys a sample NetBird environment with networks, groups, network resources, a router, and a policy.
3. Import existing resources
If resources already exist in NetBird, import them before running pulumi up so Pulumi adopts the live resources instead of creating duplicates.
- Define the resource in your Pulumi program with the same logical name you will use in the import command.
- Find the resource ID in the NetBird UI, API, or exported state from the tool that currently manages it.
- Run
pulumi import <type> <name> <id>. - Run
pulumi previewand adjust the program until there are no unintended changes. - Run
pulumi upto persist the reconciled inputs.
For most resources, the import ID is the NetBird resource ID:
pulumi import netbird:resource:Group group-admin <GROUP_ID>
pulumi import netbird:resource:Network net-r1 <NETWORK_ID>
pulumi import netbird:resource:Policy policy-admin <POLICY_ID>
pulumi import netbird:resource:Peer peer-mp1 <PEER_ID>
NetworkRouter and NetworkResource belong to a NetBird network, so their import IDs must include both the parent network ID and the child resource ID:
pulumi import netbird:resource:NetworkRouter router-r1 <NETWORK_ID>/<ROUTER_ID>
pulumi import netbird:resource:NetworkResource netres-r1-net-01 <NETWORK_ID>/<RESOURCE_ID>
Peers must be imported. They cannot be created through the NetBird management API, so pulumi up for a new Peer resource will fail unless the peer already exists in state. A minimal YAML declaration for an imported peer can look like this:
resources:
peer-mp1:
type: netbird:resource:Peer
properties:
name: mp1
options:
protect: true
For policies, keep the intended rules in your Pulumi program after import. The provider can reconstruct rule inputs during import, but declaring the rules explicitly keeps future previews understandable and makes drift intentional.
For ongoing drift detection:
pulumi refresh # pull live NetBird state into Pulumi state (detects out-of-band changes)
pulumi preview # show what pulumi up would change
pulumi up # apply
Example Pulumi.yaml (published plugin)
When using the released plugin installed via pulumi plugin install, no plugins: block is needed. Use typed config entries so the token is encrypted in the stack config file:
name: netbird
description: NetBird infrastructure managed via Pulumi
runtime: yaml
config:
netbird:token:
type: string
secret: true
netbird:url:
type: string
default: https://api.netbird.io
resources:
group-admin:
type: netbird:resource:Group
properties:
name: Admin
outputs: {}
Example Pulumi.yaml (local dev build)
When developing the provider locally, point plugins.providers at the compiled binary. The path field is the only supported alternative to CLI-installed plugins โ server is not a valid key here:
name: provider-netbird
runtime: yaml
plugins:
providers:
- name: netbird
path: ../../bin # path to locally compiled binary
config:
netbird:token:
type: string
secret: true
netbird:url:
type: string
default: https://api.netbird.io
outputs:
networkR1:
value:
name: ${net-r1.name}
id: ${net-r1.id}
resources:
group-devops:
type: netbird:resource:Group
properties:
name: DevOps
# peers and resources are optional. Omit them to let membership be
# managed externally; declare them to manage membership from here.
peers: []
resources: []
group-dev:
type: netbird:resource:Group
properties:
name: Dev
group-backoffice:
type: netbird:resource:Group
properties:
name: Backoffice
group-hr:
type: netbird:resource:Group
properties:
name: HR
net-r1:
type: netbird:resource:Network
properties:
name: R1
description: Network for Region 1
netres-r1-net-01:
type: netbird:resource:NetworkResource
properties:
name: Region 1 Net 01
description: Network 01 in Region 1
networkID: ${net-r1.id}
address: 10.10.1.0/24
enabled: true
groupIDs:
- ${group-devops.id}
netres-r1-net-02:
type: netbird:resource:NetworkResource
properties:
name: Region 1 Net 02
description: Network 02 in S1 Region 1
networkID: ${net-r1.id}
address: 10.10.2.0/24
enabled: true
groupIDs:
- ${group-devops.id}
netres-r1-net-03:
type: netbird:resource:NetworkResource
properties:
name: Region 1 Net 03
description: Network 03 in Region 1
networkID: ${net-r1.id}
address: 10.10.3.0/24
enabled: true
groupIDs:
- ${group-devops.id}
router-r1:
type: netbird:resource:NetworkRouter
properties:
networkID: ${net-r1.id}
enabled: true
masquerade: true
metric: 10
peer: ""
peerGroups:
- ${group-devops.id}
policy-ssh-grp-src-net-dest:
type: netbird:resource:Policy
properties:
name: "SSH Policy - Group to Subnet"
description: "Allow SSH (22/TCP) from DevOps and Dev groups to Region 1 Net 02"
enabled: true
postureChecks: []
rules:
- name: "SSH Access - Group โ Subnet"
description: "Allow unidirectional SSH from DevOps & Dev groups to Net 02"
bidirectional: false
action: accept
enabled: true
protocol: tcp
ports:
- "22"
sources:
- ${group-devops.id}
- ${group-dev.id}
destinationResource:
type: subnet
id: ${netres-r1-net-02.id}
policy-ssh-grp-src-grp-dest:
type: netbird:resource:Policy
properties:
name: "SSH Policy - Group to Group"
description: "Allow SSH (22/TCP) from DevOps to Backoffice group resources"
enabled: true
postureChecks: []
rules:
- name: "SSH Access - Group โ Group"
description: "SSH from DevOps group to Backoffice group"
bidirectional: false
action: accept
enabled: true
protocol: tcp
ports:
- "22"
sources:
- ${group-devops.id}
destinations:
- ${group-backoffice.id}
๐ฆซ Example Usage with Pulumi Go
You can use this provider with Pulumi Go to manage NetBird infrastructure declaratively.
The SDK is accessible through the generated github.com/mbrav/pulumi-netbird/sdk/go/netbird module.
SDK versions are available to Go with tags that are prefixed with sdk/vx.x.x and can be listed with the following command:
go list -m -versions github.com/mbrav/pulumi-netbird/sdk
Output:
github.com/mbrav/pulumi-netbird/sdk v0.3.6 v0.3.7 v0.3.8 v0.4.1 v0.5.0 v0.5.1 v0.5.2 v0.5.3 v0.5.4 # ... and so on
1. Setup
Navigate to the Go example directory:
cd examples/go
Initialize a new stack and configure your credentials:
pulumi stack init test
pulumi config set --secret netbird:token YOUR_TOKEN
pulumi config set netbird:url https://nb.domain:33073
2. Deploy
pulumi up
๐ Example Usage with Pulumi Python
You can use this provider with Pulumi Python to manage NetBird infrastructure declaratively.
1. Setup
First, you must generate the python SDK:
make provider
make sdk_python
Then install the wheel:
pip install sdk/python/bin/dist/pulumi_netbird-0.5.4.tar.gz
Navigate to the Python example directory:
cd examples/python
Initialize a new stack and configure your credentials:
pulumi stack init test
pulumi config set --secret netbird:token YOUR_TOKEN
pulumi config set netbird:url https://nb.domain:33073
2. Deploy
pulumi up
๐ Supported Resources
| Resource | Pulumi type |
|---|---|
| Azure AD (Entra ID) IdP sync | netbird:resource:AzureIDP |
| DNS nameserver group | netbird:resource:DNS |
| DNS record | netbird:resource:DNSRecord |
| DNS settings | netbird:resource:DNSSettings |
| DNS zone | netbird:resource:DNSZone |
| Google Workspace IdP sync | netbird:resource:GoogleIDP |
| Group | netbird:resource:Group |
| Identity provider (OIDC) | netbird:resource:IdentityProvider |
| Ingress peer | netbird:resource:IngressPeer |
| Network | netbird:resource:Network |
| Network resource | netbird:resource:NetworkResource |
| Network router | netbird:resource:NetworkRouter |
| Okta SCIM sync | netbird:resource:OktaScimIDP |
| Peer | netbird:resource:Peer |
| Personal access token | netbird:resource:Token |
| Policy | netbird:resource:Policy |
| Posture check | netbird:resource:PostureCheck |
| Reverse proxy domain | netbird:resource:ReverseProxyDomain |
| Reverse proxy service | netbird:resource:ReverseProxyService |
| Route | netbird:resource:Route |
| SCIM integration | netbird:resource:ScimIntegration |
| Setup key | netbird:resource:SetupKey |
| User | netbird:resource:User |
๐ Invoke Functions (Data Sources)
Invoke functions are read-only โ they query live NetBird state and return data without managing any resources. Use them to reference existing objects by a human-readable key rather than a hardcoded ID.
| Function | Pulumi type | Looks up by | Key output fields |
|---|---|---|---|
| Get countries | netbird:function:getCountries |
none | countries[] (code, name) |
| Get country cities | netbird:function:getCountryCities |
country code | cities[] (name, geonameId) |
| Get peers | netbird:function:getPeers |
optional group ID filter | peers[] (id, name, ip, connected, groups) |
| Get reverse proxy clusters | netbird:function:getReverseProxyClusters |
optional type filter | clusters[] (id, address, type, online) |
| Lookup group | netbird:function:lookupGroup |
group name | groupId, peers[], resources[] |
| Lookup peer | netbird:function:lookupPeer |
peer name | peerId, ip, dnsLabel, connected, groups[] |
| Lookup route | netbird:function:lookupRoute |
network CIDR | routeId, peerGroups[], groups[] |
| Lookup setup key | netbird:function:lookupSetupKey |
key name | setupKeyId, state, expires |
| Lookup user | netbird:function:lookupUser |
email address | userId, role, autoGroups[] |
Example: cross-referencing an existing group in YAML
variables:
devopsGroup:
fn::invoke:
function: netbird:function:lookupGroup
arguments:
name: DevOps
resources:
setup-key-devops:
type: netbird:resource:SetupKey
properties:
name: devops-onboarding
type: reusable
expiresIn: 86400
autoGroups:
- ${devopsGroup.groupId}
Example: cross-referencing in Go
devopsGroup, err := netbird.LookupGroup(ctx, &netbird.LookupGroupArgs{
Name: "DevOps",
}, nil)
if err != nil {
return err
}
_, err = netbird.NewSetupKey(ctx, "setup-key-devops", &netbird.SetupKeyArgs{
Name: pulumi.String("devops-onboarding"),
Type: pulumi.String("reusable"),
ExpiresIn: pulumi.Int(86400),
AutoGroups: pulumi.StringArray{pulumi.String(devopsGroup.GroupId)},
})
๐งช Experimental Components
These components are a proof of concept. They explore the
pulumi-go-providercomponent API and demonstrate how multiple resources can be bundled into a single declaration. The interface may change without notice. Do not rely on them in production.
Components are higher-level abstractions that create several NetBird resources together and wire them automatically. They appear in the schema under the netbird:component:* token prefix.
| Component | Pulumi type | Creates |
|---|---|---|
| Network bundle | netbird:component:NetworkBundle |
Network + NetworkRouter + N NetworkResource subnets |
| DNS zone bundle | netbird:component:DNSZoneBundle |
DNSZone + N DNSRecords |
Example: NetworkBundle in YAML
resources:
r1:
type: netbird:component:NetworkBundle
properties:
name: Region1
router:
enabled: true
masquerade: true
metric: 10
peerGroups:
- ${group-devops.id}
subnets:
- name: Net01
address: 10.10.1.0/24
enabled: true
groupIDs:
- ${group-devops.id}
- name: Net02
address: 10.10.2.0/24
enabled: true
groupIDs:
- ${group-devops.id}
outputs:
networkId: ${r1.networkId}
subnetIds: ${r1.subnetIds}
Example: DNSZoneBundle in YAML
resources:
corp-zone:
type: netbird:component:DNSZoneBundle
properties:
name: corp-internal
domain: corp.example.com
enabled: true
enableSearchDomain: true
distributionGroups:
- ${group-devops.id}
records:
- name: gw.corp.example.com
type: A
content: 10.10.1.1
ttl: 300
- name: api.corp.example.com
type: CNAME
content: gw.corp.example.com
ttl: 300
outputs:
zoneId: ${corp-zone.zoneId}
๐ Repository Structure
provider/โ Go implementation of the providersdk/go/netbird/โ Go SDK for the NetBird providerexamples/โ Example Pulumi projects using the provider
๐ References
Directories
ยถ
| Path | Synopsis |
|---|---|
|
Package provider package provider provides the NetBird Pulumi provider implementation.
|
Package provider package provider provides the NetBird Pulumi provider implementation. |
|
cmd/pulumi-resource-netbird
command
Package main is the entry point for the Pulumi NetBird provider.
|
Package main is the entry point for the Pulumi NetBird provider. |
|
component
Package component provides composite components for the NetBird Pulumi provider.
|
Package component provides composite components for the NetBird Pulumi provider. |
|
config
Package config provideds configuration and error handling for the NetBird Pulumi provider.
|
Package config provideds configuration and error handling for the NetBird Pulumi provider. |
|
function
Package function provides the NetBird Pulumi provider functions (invokes / data sources).
|
Package function provides the NetBird Pulumi provider functions (invokes / data sources). |
|
resource
Package resource provides the NetBird resource types
|
Package resource provides the NetBird resource types |
|
sdk
module
|