Skip to main content

Overview

NetBird provides WireGuard-based mesh networking for NeoSC, enabling secure peer-to-peer connectivity between demo workspaces, orchestration nodes, and control plane services. It implements network-level isolation and Zero Trust access controls.

Architecture

NetBird creates an encrypted mesh network using WireGuard:
┌─────────────────────────────────────────────────────────────────┐
│                    NetBird Control Plane                         │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐         │
│  │ Management   │  │ Signal       │  │ TURN/STUN    │         │
│  │ Server       │  │ Server       │  │ (Coturn)     │         │
│  │ :443         │  │ :10000       │  │ :3478        │         │
│  └──────────────┘  └──────────────┘  └──────────────┘         │
└─────────────────────────────────────────────────────────────────┘

                              │ WireGuard Mesh (100.64.0.0/10)

        ┌─────────────────────┼─────────────────────┐
        │                     │                     │
   ┌────▼────┐         ┌──────▼──────┐      ┌──────▼──────┐
   │ Control │         │ Orchestration│      │ Demo        │
   │ Plane   │         │ (Swarm)      │      │ Workspaces  │
   │ Group   │         │ Group        │      │ (Isolated)  │
   └─────────┘         └──────────────┘      └─────────────┘

NetBird Groups

NetBird organizes peers into groups for access control:

Static Groups

GroupPurposePeers
control-planeCore infrastructureZitadel, Pomerium, NetBird management
orchestrationContainer orchestrationDocker Swarm managers and workers

Dynamic Demo Groups

GroupPurposeLifecycle
demo-windowsTSplus/Windows workspacesCreated per session, auto-cleanup
demo-linuxLinux desktop workspacesCreated per session, auto-cleanup
demo-webappWeb application workspacesCreated per session, auto-cleanup

Installation

Self-Hosted NetBird

NeoSC uses a self-hosted NetBird instance at netbird.neosc.com for full control over networking and data.

Management Server

# Deploy NetBird Management Server
docker run -d \
  --name netbird-management \
  --restart unless-stopped \
  -p 443:443 \
  -p 33073:33073 \
  -v netbird-mgmt:/var/lib/netbird \
  -e NETBIRD_DOMAIN=netbird.neosc.com \
  -e NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT=https://manager.kappa4.com/.well-known/openid-configuration \
  -e NETBIRD_AUTH_OIDC_CLIENT_ID=${ZITADEL_CLIENT_ID} \
  -e NETBIRD_AUTH_AUDIENCE=netbird-api \
  netbirdio/management:latest

Signal Server

# Deploy NetBird Signal Server (for peer discovery)
docker run -d \
  --name netbird-signal \
  --restart unless-stopped \
  -p 10000:10000 \
  -v netbird-signal:/var/lib/netbird \
  netbirdio/signal:latest

TURN/STUN Server (Optional)

For NAT traversal when direct peer-to-peer connections fail:
# Deploy Coturn for TURN/STUN
docker run -d \
  --name coturn \
  --restart unless-stopped \
  -p 3478:3478/udp \
  -p 3478:3478/tcp \
  -p 5349:5349/udp \
  -p 5349:5349/tcp \
  -v coturn-config:/etc/coturn \
  coturn/coturn:latest

Access Control Policies

NetBird uses ACL policies to control network traffic between groups:

Policy 1: Control Plane Full Access

# Control plane can reach all groups
policies:
  - name: control-plane-full-access
    enabled: true
    description: "Control plane has full network access"
    source_groups:
      - control-plane
    destination_groups:
      - "*"
    bidirectional: false
    action: accept
    protocol: all
    ports:
      - "1-65535"

Policy 2: Orchestration to Workspaces

# Swarm managers can deploy and manage demo containers
policies:
  - name: orchestration-to-containers
    enabled: true
    description: "Orchestration can manage demo workspaces"
    source_groups:
      - orchestration
    destination_groups:
      - demo-windows
      - demo-linux
      - demo-webapp
    bidirectional: false
    action: accept
    protocol: tcp
    ports:
      - "2377"   # Docker Swarm
      - "7946"   # Container network discovery
      - "4789"   # Overlay network
      - "6900"   # Kasm streaming
      - "443"    # HTTPS

Policy 3: Demo Isolation

Critical Security Policy: Demo workspaces MUST be isolated from each other to prevent lateral movement.
# Demo containers cannot communicate with each other
policies:
  - name: demo-isolation
    enabled: true
    description: "Demos are isolated - no peer-to-peer access"
    source_groups:
      - demo-windows
      - demo-linux
      - demo-webapp
    destination_groups:
      - demo-windows
      - demo-linux
      - demo-webapp
    bidirectional: true
    action: drop
    protocol: all
    ports:
      - "1-65535"

Policy 4: No Internet Access

# Demo containers cannot access external internet
policies:
  - name: demo-no-internet
    enabled: true
    description: "Block demo workspaces from internet"
    source_groups:
      - demo-windows
      - demo-linux
      - demo-webapp
    destination_groups:
      - "*"
    bidirectional: false
    action: drop
    protocol: all
    ports:
      - "1-65535"
    destination_ips:
      - "0.0.0.0/0"
    exceptions:
      # Allow internal DNS only
      - destination_ips: ["100.64.1.53"]
        ports: ["53"]
        protocol: udp

Backend Integration

The NeoSC backend provisions NetBird peers dynamically for each demo session.

API Configuration

import httpx

NETBIRD_API = "https://netbird.neosc.com/api"
NETBIRD_TOKEN = os.getenv("NETBIRD_TOKEN")  # Management API token

headers = {
    "Authorization": f"Bearer {NETBIRD_TOKEN}",
    "Content-Type": "application/json"
}

Create Ephemeral Peer

When a demo session starts, create a temporary NetBird peer:
async def create_netbird_peer(
    session_id: str,
    workspace_type: str,
    netbird_group: str,
    expires_at: datetime
) -> dict:
    """
    Create ephemeral NetBird peer for demo session
    """
    
    # 1. Generate one-time setup key
    setup_key_response = await httpx.post(
        f"{NETBIRD_API}/setup-keys",
        headers=headers,
        json={
            "name": f"demo-{session_id}",
            "type": "one-time",  # Key expires after first use
            "expires_in": 3600,  # 1 hour
            "auto_groups": [netbird_group],  # Automatically join group
            "usage_limit": 1,
            "ephemeral": True  # Peer deleted when disconnected
        }
    )
    
    setup_key = setup_key_response.json()["key"]
    
    # 2. Register peer
    peer_response = await httpx.post(
        f"{NETBIRD_API}/peers",
        headers=headers,
        json={
            "name": f"demo-container-{session_id}",
            "host_name": f"{workspace_type}-{session_id}",
            "groups": [netbird_group],
            "ssh_enabled": False,
            "login_expiration_enabled": True,
            "login_expiration": expires_at.isoformat(),
            "approval_required": False,
            "labels": {
                "session_id": session_id,
                "workspace_type": workspace_type,
                "demo": "true",
                "ephemeral": "true"
            }
        }
    )
    
    peer = peer_response.json()
    
    return {
        "peer_id": peer["id"],
        "peer_ip": peer["ip"],  # IP in 100.64.0.0/10 range
        "setup_key": setup_key,
        "wg_public_key": peer["public_key"]
    }

Configure Session-Specific ACL

Create fine-grained ACL for each session:
async def configure_session_acl(
    session_id: str,
    peer_id: str,
    container_ip: str,
    workspace_type: str
):
    """
    Create ACL rule allowing ONLY this user to access their container
    """
    
    acl_response = await httpx.post(
        f"{NETBIRD_API}/acls",
        headers=headers,
        json={
            "name": f"demo-session-{session_id}",
            "description": f"Temporary ACL for demo {session_id}",
            "enabled": True,
            "rules": [
                {
                    # Allow: user peer → their container
                    "name": f"allow-{session_id}-to-container",
                    "source_peers": [peer_id],
                    "destination_ips": [container_ip],
                    "protocol": "tcp",
                    "ports": ["6900", "443"],  # Kasm + HTTPS
                    "action": "accept"
                },
                {
                    # Deny: user peer → everything else
                    "name": f"deny-{session_id}-lateral",
                    "source_peers": [peer_id],
                    "destination_ips": ["100.64.0.0/10"],  # NetBird range
                    "protocol": "all",
                    "ports": ["1-65535"],
                    "action": "drop",
                    "priority": 1000  # Lower priority than allow rule
                }
            ],
            "metadata": {
                "session_id": session_id,
                "workspace_type": workspace_type,
                "auto_cleanup": True,
                "expires_at": expires_at.isoformat()
            }
        }
    )
    
    return acl_response.json()

Cleanup on Session End

Remove NetBird resources when demo expires:
async def cleanup_netbird_peer(session_id: str, peer_id: str):
    """
    Delete NetBird peer and associated ACL
    """
    
    # 1. Delete peer (ephemeral peers auto-delete, but clean up explicitly)
    await httpx.delete(
        f"{NETBIRD_API}/peers/{peer_id}",
        headers=headers
    )
    
    # 2. Delete session-specific ACL
    acls = await httpx.get(
        f"{NETBIRD_API}/acls",
        headers=headers,
        params={"name": f"demo-session-{session_id}"}
    )
    
    for acl in acls.json():
        await httpx.delete(
            f"{NETBIRD_API}/acls/{acl['id']}",
            headers=headers
        )
    
    logger.info(f"NetBird resources cleaned up for session {session_id}")

Network Topology

NetBird assigns IPs from the 100.64.0.0/10 range (CGNAT space):
100.64.0.0/10 - NetBird Mesh Network
├── 100.64.0.1      - NetBird Management (gateway)
├── 100.64.1.53     - Internal DNS
├── 100.64.10.0/24  - Control Plane
│   ├── 100.64.10.1 - Pomerium
│   ├── 100.64.10.2 - Zitadel
│   └── 100.64.10.3 - NetBird Management
├── 100.64.20.0/24  - Orchestration
│   ├── 100.64.20.1 - Swarm Manager 1
│   ├── 100.64.20.2 - Swarm Manager 2
│   └── 100.64.20.10-50 - Swarm Workers
└── 100.64.100.0/22 - Demo Workspaces (ephemeral)
    ├── 100.64.100.1-254 - Windows demos
    ├── 100.64.101.1-254 - Linux demos
    └── 100.64.102.1-254 - WebApp demos

Security Features

End-to-End Encryption

All traffic encrypted with WireGuard:
  • Protocol: WireGuard (ChaCha20-Poly1305)
  • Key Exchange: Curve25519
  • Perfect Forward Secrecy: Automatic key rotation

Zero Trust Enforcement

Default Deny

All traffic blocked unless explicitly allowed by ACL policy

Peer Isolation

Each demo workspace isolated in its own network segment

Ephemeral Peers

Demo peers auto-deleted when session ends or disconnects

Fine-Grained ACLs

Per-session ACLs ensure users only access their own workspace

Monitoring

Track NetBird peer status:
from prometheus_client import Gauge

# Metrics
netbird_peers = Gauge(
    'netbird_peers_total',
    'Total NetBird peers',
    ['group', 'status']
)

async def update_netbird_metrics():
    """Update Prometheus metrics for NetBird peers"""
    
    peers = await httpx.get(
        f"{NETBIRD_API}/peers",
        headers=headers
    )
    
    # Count by group and status
    for peer in peers.json():
        group = peer.get("groups", ["unknown"])[0]
        status = "online" if peer["connected"] else "offline"
        netbird_peers.labels(group=group, status=status).inc()

Troubleshooting

Symptoms: Peer shows “disconnected” in NetBird dashboard.Checks:
# Check WireGuard interface
ip link show wt0

# Check NetBird service
systemctl status netbird

# View NetBird logs
journalctl -u netbird -f
Common causes:
  • Firewall blocking UDP port 51820
  • Setup key expired
  • Management server unreachable
Cause: ACL policy blocking traffic.Solution:
  1. Check ACL rules in NetBird dashboard
  2. Verify peer is in correct group
  3. Test with ping from source peer:
    ping <destination-ip>
    
  4. Check NetBird logs for dropped packets
Cause: TURN relay being used instead of direct connection.Solution:
  • Configure STUN/TURN servers
  • Check NAT traversal settings
  • Enable UPnP/NAT-PMP on router
  • Use relay server closer to peers

Visual Integration

NetBird provides a web-based dashboard for visual network management at https://netbird.neosc.com.

Dashboard Features

  • Peer Map: Visual topology of mesh network
  • ACL Editor: GUI for creating and editing access policies
  • Real-Time Monitoring: Live peer status and traffic statistics
  • Audit Logs: Complete history of peer connections and policy changes

API-First Design

All dashboard operations available via REST API for automation:
# List all peers
curl -H "Authorization: Bearer $NETBIRD_TOKEN" \
  https://netbird.neosc.com/api/peers

# Get peer details
curl -H "Authorization: Bearer $NETBIRD_TOKEN" \
  https://netbird.neosc.com/api/peers/{peer-id}

# Delete peer
curl -X DELETE \
  -H "Authorization: Bearer $NETBIRD_TOKEN" \
  https://netbird.neosc.com/api/peers/{peer-id}

Best Practices

Use Ephemeral Peers

Enable ephemeral mode for demo workspaces to auto-cleanup on disconnect

Minimize ACL Scope

Create narrow, session-specific ACLs instead of broad group policies

Monitor Peer Count

Alert on unexpected peer growth - may indicate provisioning failures

Regular Audits

Review ACL policies and peer list weekly to remove stale entries

Next Steps

Zero Trust Architecture

Learn how NetBird fits into the Zero Trust model

Docker Swarm

Integrate NetBird with container orchestration

Build docs developers (and LLMs) love