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 , so a bare filename lands alongside the // store. Empty falls back to probing /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 an operator who needs the bundles, which // carry peer logs, routes, DNS and firewall state, to stay inside their own // infrastructure can say so once. Leaving it unset publishes no destination and // the peers upload to the service NetBird runs, which keeps the everyday // "collect a bundle and send it to support" flow working out of the box. // // 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) } // Hostname(), not Host: an authority like ":443" is non-empty but has no // host, and the peers reject it (see profilemanager.ValidateBundleUploadURL). // Management must not publish a destination its own clients refuse. if parsed.Hostname() == "" { 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 }