mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-29 01:59:07 +02:00
The debug-bundle paths that upload without a human picking a destination compiled the vendor endpoint in: the mobile clients and the desktop UI hold `https://upload.debug.netbird.io/upload-url` as a constant, the CLI defaults its flag to it, and the remote job falls back to it when nothing else is set. A self-hosted deployment therefore shipped peer logs, routes, DNS and firewall state to NetBird-run infrastructure without its operator ever configuring that, and had no way to point those paths anywhere else. #7147 and #7153 gave the remote job a per-job URL and an MDM override, but neither reaches the mobile, UI or CLI paths, and both fail open when unset. Publish the destination from the management server instead, on the channel that already carries stun/turn/signal/relay/flow/metrics: - `NetbirdConfig.debug.upload_url`, sourced from the new account setting `debug_bundle_upload_url` (REST + dashboard) and falling back to the new `DebugUpload.URL` in the management server config, which a self-hosted install can set once so a fresh account is not left on the vendor default. Both are validated as https-with-host where they are written; a change fans out to connected peers rather than waiting for the next login. - One resolver on the client, `debug.ResolveUploadURL`, used by every path: MDM override > explicitly named URL > destination published by management > the NetBird service, but only for a peer enrolled with NetBird's cloud. Anything else fails closed with ErrNoUploadDestination and the bundle stays local, which is the behaviour change: a self-hosted deployment that names no upload service no longer uploads at all. - The engine keeps the published value (`Engine.DebugUploadURL`) so the bundle paths, which run off the engine loop, do not have to read it back out of the opt-in sync-response store. - The daemon request grows `upload`, so "upload to wherever this deployment says" is expressible; an empty `uploadURL` no longer has to mean "no upload". The privilege gate is unchanged and still applies only to a URL the local caller named — a destination published by management is the operator naming their own service. - The desktop UI stops carrying a vendor URL of its own and sends the intent. Reported privately as GHSA-hf99-43rj-h577.
287 lines
10 KiB
Go
287 lines
10 KiB
Go
package config
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/netip"
|
|
"net/url"
|
|
|
|
"github.com/netbirdio/netbird/management/server/idp"
|
|
"github.com/netbirdio/netbird/management/server/types"
|
|
"github.com/netbirdio/netbird/shared/management/client/common"
|
|
"github.com/netbirdio/netbird/util"
|
|
)
|
|
|
|
type (
|
|
// Protocol type
|
|
Protocol string
|
|
|
|
// Provider authorization flow type
|
|
Provider string
|
|
)
|
|
|
|
const (
|
|
UDP Protocol = "udp"
|
|
DTLS Protocol = "dtls"
|
|
TCP Protocol = "tcp"
|
|
HTTP Protocol = "http"
|
|
HTTPS Protocol = "https"
|
|
NONE Provider = "none"
|
|
)
|
|
|
|
const (
|
|
// DefaultDeviceAuthFlowScope defines the bare minimum scope to request in the device authorization flow
|
|
DefaultDeviceAuthFlowScope string = "openid"
|
|
)
|
|
|
|
var MgmtConfigPath string
|
|
|
|
// Config of the Management service
|
|
type Config struct {
|
|
Stuns []*Host
|
|
TURNConfig *TURNConfig
|
|
Relay *Relay
|
|
Signal *Host
|
|
|
|
Datadir string
|
|
DataStoreEncryptionKey string
|
|
|
|
HttpConfig *HttpServerConfig
|
|
|
|
IdpManagerConfig *idp.Config
|
|
|
|
DeviceAuthorizationFlow *DeviceAuthorizationFlow
|
|
|
|
PKCEAuthorizationFlow *PKCEAuthorizationFlow
|
|
|
|
StoreConfig StoreConfig
|
|
|
|
ReverseProxy ReverseProxy
|
|
|
|
AgentNetwork AgentNetwork
|
|
|
|
// DebugUpload configures where the peers of this deployment send their
|
|
// debug bundles. See DebugUpload.
|
|
DebugUpload DebugUpload
|
|
|
|
// disable default all-to-all policy
|
|
DisableDefaultPolicy bool
|
|
|
|
// EmbeddedIdP contains configuration for the embedded Dex OIDC provider.
|
|
// When set, Dex will be embedded in the management server and serve requests at /oauth2/
|
|
EmbeddedIdP *idp.EmbeddedIdPConfig
|
|
|
|
HighestSupportedSyncMessageVersion *int
|
|
|
|
PerAccountHighestSupportedSyncMessageVersion map[string]int
|
|
}
|
|
|
|
// GetAuthAudiences returns the audience from the http config and device authorization flow config
|
|
func (c Config) GetAuthAudiences() []string {
|
|
audiences := []string{c.HttpConfig.AuthAudience}
|
|
|
|
if c.HttpConfig.ExtraAuthAudience != "" {
|
|
audiences = append(audiences, c.HttpConfig.ExtraAuthAudience)
|
|
}
|
|
|
|
if c.DeviceAuthorizationFlow != nil && c.DeviceAuthorizationFlow.ProviderConfig.Audience != "" {
|
|
audiences = append(audiences, c.DeviceAuthorizationFlow.ProviderConfig.Audience)
|
|
}
|
|
|
|
return audiences
|
|
}
|
|
|
|
// TURNConfig is a config of the TURNCredentialsManager
|
|
type TURNConfig struct {
|
|
TimeBasedCredentials bool
|
|
CredentialsTTL util.Duration
|
|
Secret string
|
|
Turns []*Host
|
|
}
|
|
|
|
// Relay configuration type
|
|
type Relay struct {
|
|
Addresses []string
|
|
CredentialsTTL util.Duration
|
|
Secret string
|
|
}
|
|
|
|
// HttpServerConfig is a config of the HTTP Management service server
|
|
type HttpServerConfig struct {
|
|
LetsEncryptDomain string
|
|
// CertFile is the location of the certificate
|
|
CertFile string
|
|
// CertKey is the location of the certificate private key
|
|
CertKey string
|
|
// AuthClientID is the client id used for proxy SSO auth
|
|
AuthClientID string
|
|
// AuthAudience identifies the recipients that the JWT is intended for (aud in JWT)
|
|
AuthAudience string
|
|
// CLIAuthAudience identifies the client app recipients that the JWT is intended for (aud in JWT)
|
|
// Used only in conjunction with EmbeddedIdP
|
|
CLIAuthAudience string
|
|
// AuthIssuer identifies principal that issued the JWT
|
|
AuthIssuer string
|
|
// AuthUserIDClaim is the name of the claim that used as user ID
|
|
AuthUserIDClaim string
|
|
// AuthKeysLocation is a location of JWT key set containing the public keys used to verify JWT
|
|
AuthKeysLocation string
|
|
// OIDCConfigEndpoint is the endpoint of an IDP manager to get OIDC configuration
|
|
OIDCConfigEndpoint string
|
|
// IdpSignKeyRefreshEnabled identifies the signing key is currently being rotated or not
|
|
IdpSignKeyRefreshEnabled bool
|
|
// Extra audience
|
|
ExtraAuthAudience string
|
|
// AuthCallbackDomain contains the callback domain
|
|
AuthCallbackURL string
|
|
}
|
|
|
|
// Host represents a Netbird host (e.g. STUN, TURN, Signal)
|
|
type Host struct {
|
|
Proto Protocol
|
|
// URI e.g. turns://stun.netbird.io:4430 or signal.netbird.io:10000
|
|
URI string
|
|
Username string
|
|
Password string
|
|
}
|
|
|
|
// DeviceAuthorizationFlow represents Device Authorization Flow information
|
|
// that can be used by the client to login initiate a Oauth 2.0 device authorization grant flow
|
|
// see https://datatracker.ietf.org/doc/html/rfc8628
|
|
type DeviceAuthorizationFlow struct {
|
|
Provider string
|
|
ProviderConfig ProviderConfig
|
|
}
|
|
|
|
// PKCEAuthorizationFlow represents Authorization Code Flow information
|
|
// that can be used by the client to login initiate a Oauth 2.0 authorization code grant flow
|
|
// with Proof Key for Code Exchange (PKCE). See https://datatracker.ietf.org/doc/html/rfc7636
|
|
type PKCEAuthorizationFlow struct {
|
|
ProviderConfig ProviderConfig
|
|
}
|
|
|
|
// ProviderConfig has all attributes needed to initiate a device/pkce authorization flow
|
|
type ProviderConfig struct {
|
|
// ClientID An IDP application client id
|
|
ClientID string
|
|
// ClientSecret An IDP application client secret
|
|
ClientSecret string
|
|
// Domain An IDP API domain
|
|
// Deprecated. Use TokenEndpoint and DeviceAuthEndpoint
|
|
Domain string
|
|
// Audience An Audience for to authorization validation
|
|
Audience string
|
|
// TokenEndpoint is the endpoint of an IDP manager where clients can obtain access token
|
|
TokenEndpoint string
|
|
// DeviceAuthEndpoint is the endpoint of an IDP manager where clients can obtain device authorization code
|
|
DeviceAuthEndpoint string
|
|
// AuthorizationEndpoint is the endpoint of an IDP manager where clients can obtain authorization code
|
|
AuthorizationEndpoint string
|
|
// Scopes provides the scopes to be included in the token request
|
|
Scope string
|
|
// UseIDToken indicates if the id token should be used for authentication
|
|
UseIDToken bool
|
|
// RedirectURL handles authorization code from IDP manager
|
|
RedirectURLs []string
|
|
// DisablePromptLogin makes the PKCE flow to not prompt the user for login
|
|
DisablePromptLogin bool
|
|
// LoginFlag is used to configure the PKCE flow login behavior
|
|
LoginFlag common.LoginFlag
|
|
}
|
|
|
|
// StoreConfig contains Store configuration
|
|
type StoreConfig struct {
|
|
Engine types.Engine
|
|
}
|
|
|
|
// AgentNetwork contains agent-network (LLM gateway) configuration.
|
|
type AgentNetwork struct {
|
|
// PricingDefaultsFile is the path to the YAML file holding the default
|
|
// LLM pricing table (defaults_llm_pricing.yaml). A relative path is
|
|
// resolved against <Datadir>, so a bare filename lands alongside the
|
|
// store. Empty falls back to probing <Datadir>/defaults_llm_pricing.yaml;
|
|
// with no file present the compiled-in defaults serve. Schema: surface ("openai"/"anthropic"/
|
|
// "bedrock") -> model -> rates in USD per 1k tokens (input_per_1k,
|
|
// output_per_1k, and the optional cached_input_per_1k /
|
|
// cache_read_per_1k / cache_creation_per_1k). File entries replace the
|
|
// compiled-in entry for the same surface+model whole; everything else
|
|
// keeps the compiled-in rates. The file is re-read periodically (mtime
|
|
// poll), and the live table feeds both the synthesizer (what proxies
|
|
// bill with) and the dashboard's catalog endpoint (what model rows
|
|
// prefill with). An explicitly configured path that fails to load
|
|
// fails startup; runtime reload errors keep the previous table.
|
|
PricingDefaultsFile string
|
|
}
|
|
|
|
// DebugUpload configures the debug-bundle upload service this deployment
|
|
// publishes to its peers.
|
|
//
|
|
// The client paths that upload without a human picking a destination — the
|
|
// remote debug-bundle job, the mobile clients and the desktop UI — take the
|
|
// destination from here. It exists so a self-hosted deployment keeps its
|
|
// bundles, which carry peer logs, routes, DNS and firewall state, inside the
|
|
// operator's own control sphere instead of reaching the upload service NetBird
|
|
// runs. Leaving it unset publishes no destination: a peer enrolled with
|
|
// NetBird's cloud still uses NetBird's service, a self-hosted peer keeps the
|
|
// bundle local.
|
|
//
|
|
// Set URL to the upload service's get-URL endpoint, e.g.
|
|
// https://upload.example.com/upload-url (see the upload-server component).
|
|
type DebugUpload struct {
|
|
// URL is the get-URL endpoint of the upload service. Must be https: the
|
|
// client fetches an upload URL from it and then PUTs the bundle to whatever
|
|
// that fetch returns, so a plaintext hop is a place to intercept both.
|
|
URL string
|
|
}
|
|
|
|
// Validate rejects a destination the client would refuse anyway, so a typo in
|
|
// management.json surfaces at startup instead of at the first bundle upload.
|
|
func (d DebugUpload) Validate() error {
|
|
if d.URL == "" {
|
|
return nil
|
|
}
|
|
|
|
parsed, err := url.Parse(d.URL)
|
|
if err != nil {
|
|
return fmt.Errorf("parse debug upload URL: %w", err)
|
|
}
|
|
if parsed.Scheme != "https" {
|
|
return fmt.Errorf("debug upload URL must use https, got scheme %q", parsed.Scheme)
|
|
}
|
|
if parsed.Host == "" {
|
|
return errors.New("debug upload URL must have a host")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ReverseProxy contains reverse proxy configuration in front of management.
|
|
type ReverseProxy struct {
|
|
// TrustedHTTPProxies represents a list of trusted HTTP proxies by their IP prefixes.
|
|
// When extracting the real IP address from request headers, the middleware will verify
|
|
// if the peer's address falls within one of these trusted IP prefixes.
|
|
TrustedHTTPProxies []netip.Prefix
|
|
|
|
// TrustedHTTPProxiesCount specifies the count of trusted HTTP proxies between the internet
|
|
// and the server. When using the trusted proxy count method to extract the real IP address,
|
|
// the middleware will search the X-Forwarded-For IP list from the rightmost by this count
|
|
// minus one.
|
|
TrustedHTTPProxiesCount uint
|
|
|
|
// TrustedPeers represents a list of trusted peers by their IP prefixes.
|
|
// These peers are considered trustworthy by the gRPC server operator,
|
|
// and the middleware will attempt to extract the real IP address from
|
|
// request headers if the peer's address falls within one of these
|
|
// trusted IP prefixes.
|
|
TrustedPeers []netip.Prefix
|
|
|
|
// AccessLogRetentionDays specifies the number of days to retain access logs.
|
|
// Logs older than this duration will be automatically deleted during cleanup.
|
|
// A value of 0 will default to 7 days. Negative means logs are kept indefinitely (no cleanup).
|
|
AccessLogRetentionDays int
|
|
|
|
// AccessLogCleanupIntervalHours specifies how often (in hours) to run the cleanup routine.
|
|
// Defaults to 24 hours if not set or set to 0.
|
|
AccessLogCleanupIntervalHours int
|
|
}
|