Groundwork for the app gate (item 1): before anything can enforce authentication on app ports, the node has to know which ports are *supposed* to be reachable without it. `PortMapping` grows `auth` (PortAuth::Session | None, defaulting to Session) and `auth_rationale`. The default is deliberately the protected one. Every app port on this node answered with no credential at all over LAN, Tailscale, Tor and the FIPS mesh alike — reproduced 2026-08-03 — precisely because exposure was what you got by saying nothing. Inverting the default means a new app is protected unless its manifest argues for an exemption. Validation makes the argument mandatory: `auth: none` without a rationale is rejected, and so is a rationale without `auth: none` (that combination means the author wrote an exemption and did not get one — shipping it silently would leave them believing otherwise). 17 ports across 12 apps are declared exempt, each with its reason. They are the ports that cannot sit behind an HTTP login page at all: Lightning p2p (BOLT-8 noise), LND gRPC/REST and CLN gRPC (macaroon / mutual TLS — Zeus and remote wallets dial these directly), Bitcoin p2p gossip, electrum wire protocol, Wyoming voice streams, git-over-SSH, and the UDP discovery protocols (mDNS, SSDP, STUN). Everything else — 39 published ports — now defaults to gated. Bitcoin's RPC 8332 is deliberately NOT exempted: it is already `bind: 127.0.0.1`, so the gate never sees it, and claiming an exemption it does not need would put a line in the audit list that means nothing. If the loopback bind is ever dropped, it fails closed. Two corpus tests keep this honest: every shipped manifest must parse under the new rules, and the exempt set is pinned at 17 so any change to the node's unauthenticated surface has to be a deliberate edit. Tests: 73/73 archipelago-container, workspace builds clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
126 lines
4.4 KiB
YAML
126 lines
4.4 KiB
YAML
app:
|
|
id: netbird-server
|
|
name: NetBird Server
|
|
version: "0.71.2"
|
|
description: NetBird combined management / signal / relay server with an embedded identity provider and STUN. Backend for the self-hosted NetBird mesh VPN.
|
|
category: networking
|
|
|
|
# Hyphen name matches the runtime references (crash_recovery / dependencies /
|
|
# config startup order) + the live container, so on an existing node the
|
|
# orchestrator ADOPTS the running server rather than recreating it (data +
|
|
# the sqlite store under /var/lib/netbird preserved). Alias `netbird-server`
|
|
# is the short hostname the proxy's nginx proxies/grpc-passes to.
|
|
container_name: netbird-server
|
|
|
|
container:
|
|
image: docker.io/netbirdio/netbird-server:0.71.2
|
|
pull_policy: if-not-present
|
|
network: netbird-net
|
|
network_aliases: [netbird-server]
|
|
# The relay authSecret and the sqlite store encryptionKey are base64 keys
|
|
# (the server base64-decodes them to recover raw bytes — hex would decode to
|
|
# the wrong value). Generated once and reused: ensure_generated_secrets
|
|
# no-ops when the file already exists, so a re-render of config.yaml on an
|
|
# adopted node keeps the same keys (regenerating would orphan the store).
|
|
generated_secrets:
|
|
- name: netbird-relay-auth-secret
|
|
kind: base64
|
|
- name: netbird-store-encryption-key
|
|
kind: base64
|
|
# Pass the rendered config explicitly, mirroring the legacy `--config` arg.
|
|
custom_args: ["--config", "/etc/netbird/config.yaml"]
|
|
|
|
dependencies:
|
|
- storage: 1Gi
|
|
|
|
resources:
|
|
memory_limit: 1Gi
|
|
|
|
security:
|
|
# cap-drop=ALL is applied by the orchestrator. The server binds :80
|
|
# (management/signal/relay HTTP + gRPC) inside the container — a privileged
|
|
# port — so it needs NET_BIND_SERVICE. STUN is 3478/udp (unprivileged).
|
|
capabilities: [NET_BIND_SERVICE]
|
|
readonly_root: false
|
|
network_policy: isolated
|
|
|
|
ports:
|
|
- host: 8086
|
|
container: 80
|
|
protocol: tcp # management API + embedded OIDC issuer (/oauth2)
|
|
- host: 3478
|
|
container: 3478
|
|
protocol: udp # STUN — must be UDP; tcp here breaks relay discovery
|
|
auth: none
|
|
auth_rationale: >-
|
|
STUN over UDP for NAT traversal; it must answer unauthenticated probes to do its job at all.
|
|
|
|
volumes:
|
|
- type: bind
|
|
source: /var/lib/archipelago/netbird/data
|
|
target: /var/lib/netbird
|
|
options: [rw]
|
|
# The rendered config.yaml, read-only. Re-rendered on every reconcile from
|
|
# host facts + the base64 secrets; idempotent (stable bytes → no restart).
|
|
- type: bind
|
|
source: /var/lib/archipelago/netbird/config.yaml
|
|
target: /etc/netbird/config.yaml
|
|
options: [ro]
|
|
|
|
environment: []
|
|
|
|
# The server's config. {{HOST_IP}} is the node's primary host IP (the proxy's
|
|
# public origin is https on 8087 — the dashboard needs a secure context for
|
|
# OIDC PKCE, issue #15). {{secret:...}} are read 0600 from the secrets dir.
|
|
files:
|
|
- path: /var/lib/archipelago/netbird/config.yaml
|
|
overwrite: true
|
|
content: |
|
|
server:
|
|
listenAddress: ":80"
|
|
exposedAddress: "https://{{HOST_IP}}:8087"
|
|
stunPorts:
|
|
- 3478
|
|
metricsPort: 9090
|
|
healthcheckAddress: ":9000"
|
|
logLevel: "info"
|
|
logFile: "console"
|
|
authSecret: "{{secret:netbird-relay-auth-secret}}"
|
|
dataDir: "/var/lib/netbird"
|
|
auth:
|
|
issuer: "https://{{HOST_IP}}:8087/oauth2"
|
|
localAuthDisabled: false
|
|
signKeyRefreshEnabled: false
|
|
dashboardRedirectURIs:
|
|
- "https://{{HOST_IP}}:8087/nb-auth"
|
|
- "https://{{HOST_IP}}:8087/nb-silent-auth"
|
|
dashboardPostLogoutRedirectURIs:
|
|
- "https://{{HOST_IP}}:8087/"
|
|
cliRedirectURIs:
|
|
- "http://localhost:53000/"
|
|
store:
|
|
engine: "sqlite"
|
|
encryptionKey: "{{secret:netbird-store-encryption-key}}"
|
|
|
|
# TCP liveness on the management port. Binds at startup, stays green; an http
|
|
# check of /oauth2 would false-fail while the issuer warms up.
|
|
health_check:
|
|
type: tcp
|
|
endpoint: localhost:80
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 10
|
|
start_period: 30s
|
|
|
|
metadata:
|
|
author: NetBird
|
|
icon: /assets/img/app-icons/netbird.svg
|
|
website: https://netbird.io
|
|
repo: https://github.com/netbirdio/netbird
|
|
license: BSD-3-Clause
|
|
tags:
|
|
- networking
|
|
- vpn
|
|
- wireguard
|
|
- mesh
|