Documentation
¶
Index ¶
- func SaveAgentConfig(path string, cfg *AgentConfig) error
- func SaveServerConfig(path string, cfg *ServerConfig) error
- func ValidateAgentServerURL(serverURL string, allowInsecure bool) error
- func ValidateWebhookURL(field, rawURL string, allowPrivate bool) error
- type AgentConfig
- type AlertsConfig
- type CAAutoRotateConfig
- type CAImportConfig
- type MetricsConfig
- type OIDCConfig
- type PasswordConfig
- type RateLimitConfig
- type RateLimitGroupConfig
- type ServerConfig
- type WebhooksConfig
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func SaveAgentConfig ¶
func SaveAgentConfig(path string, cfg *AgentConfig) error
SaveAgentConfig writes cfg to path atomically (tmp + fsync + rename) with mode 0600. The parent directory is created with mode 0755 if missing. The server URL is validated with the same rules as LoadAgentConfig so a config that would be refused at the next startup is never written.
func SaveServerConfig ¶
func SaveServerConfig(path string, cfg *ServerConfig) error
SaveServerConfig writes the config to path atomically (temp file + rename). Existing comments and unknown fields in the file are not preserved.
func ValidateAgentServerURL ¶ added in v0.4.0
ValidateAgentServerURL guards the agent's management-server URL. The URL must be http/https with a host. A plaintext http:// URL is accepted only for a loopback host (local testing, an on-host TLS-terminating proxy) unless allowInsecure opts out — everywhere else the enrollment token and the host's rendered Nebula config would transit a real network in cleartext. The CLI and the server already carry the equivalent guards (#219, #179); this covers the agent.
Exposed as a function rather than only a load-time check so the enroll path can validate the --server flag before the token is sent, when no config file exists yet.
func ValidateWebhookURL ¶ added in v0.6.0
ValidateWebhookURL guards a webhook URL against SSRF (#188): the URL must be http/https with a host, and (unless allowPrivate) must not target a private/loopback/link-local address. field names the offending config key in errors so both alerts.webhook_url and webhooks.url can reuse it. DNS names are not resolved here — this is the config-load layer; the delivery-time layer (post-resolution dialer guard + per-redirect-hop re-check) lives in the alerts WebhookSink and the webhook.Dispatcher.
Types ¶
type AgentConfig ¶
type AgentConfig struct {
ServerURL string `yaml:"server_url"`
DataDir string `yaml:"data_dir"`
SigningKeyPath string `yaml:"signing_key_path"`
PollInterval time.Duration `yaml:"poll_interval"`
NebulaConfigPath string `yaml:"nebula_config_path"`
NebulaCAPath string `yaml:"nebula_ca_path,omitempty"`
NebulaCertPath string `yaml:"nebula_cert_path,omitempty"`
NebulaKeyPath string `yaml:"nebula_key_path,omitempty"`
ImportSessionID string `yaml:"import_session_id,omitempty"`
NebulaPIDFile string `yaml:"nebula_pid_file"`
// NebulaReloadCommand, when set, is run through the system shell after
// config/cert changes instead of sending SIGHUP to nebula_pid_file
// (which it takes precedence over). Lets operators hook their service
// manager (e.g. "systemctl reload nebula") and gives Windows — where
// SIGHUP does not exist — a working reload path.
NebulaReloadCommand string `yaml:"nebula_reload_command,omitempty"`
// AllowInsecureHTTP opts out of the https-required guard on server_url.
// Without it a plaintext http:// URL is only accepted for loopback
// hosts — over any other network the enrollment token, certificates,
// and the Nebula config the agent installs would transit in cleartext,
// where an on-path attacker can steal the token or inject a malicious
// config. Mirrors the server's allow_insecure_http (#179).
AllowInsecureHTTP bool `yaml:"allow_insecure_http,omitempty"`
}
func DefaultAgentConfig ¶
func DefaultAgentConfig() *AgentConfig
DefaultAgentConfig returns a config populated with the defaults the agent applies when fields are missing.
SigningKeyPath defaults to /etc/nebula-agent/host.signing.key — agent's Ed25519 poll-signature key lives next to agent.yml, deliberately *not* in /etc/nebula where Nebula's own secrets live (ADR 0004 + #88).
func LoadAgentConfig ¶
func LoadAgentConfig(path string) (*AgentConfig, error)
func (*AgentConfig) ResolvedNebulaCAPath ¶ added in v0.8.0
func (c *AgentConfig) ResolvedNebulaCAPath() string
func (*AgentConfig) ResolvedNebulaCertPath ¶ added in v0.8.0
func (c *AgentConfig) ResolvedNebulaCertPath() string
func (*AgentConfig) ResolvedNebulaKeyPath ¶ added in v0.8.0
func (c *AgentConfig) ResolvedNebulaKeyPath() string
type AlertsConfig ¶
type AlertsConfig struct {
Enabled bool `yaml:"enabled,omitempty"`
Interval string `yaml:"interval,omitempty"`
Threshold string `yaml:"threshold,omitempty"`
WebhookURL string `yaml:"webhook_url,omitempty"`
WebhookHMACSecret string `yaml:"webhook_hmac_secret,omitempty"`
// AllowPrivateWebhook permits webhook_url to point at a loopback/private/
// link-local address. Default false rejects such targets at startup as an
// SSRF guard (#188); set true for an intentional internal sink (e.g. a
// co-located Alertmanager).
AllowPrivateWebhook bool `yaml:"allow_private_webhook,omitempty"`
}
AlertsConfig drives the periodic cert-expiry scanner and its sinks. Threshold and Interval are parsed as Go durations (e.g. "72h", "5m").
func (AlertsConfig) IntervalDuration ¶
func (a AlertsConfig) IntervalDuration() time.Duration
IntervalDuration returns Interval as a time.Duration. Falls back to 5m when unset or unparseable, matching the documented default.
func (AlertsConfig) ThresholdDuration ¶
func (a AlertsConfig) ThresholdDuration() time.Duration
ThresholdDuration returns Threshold as a time.Duration. Falls back to 72h (three days) when unset or unparseable, matching the documented default.
type CAAutoRotateConfig ¶
type CAAutoRotateConfig struct {
Enabled bool `yaml:"enabled,omitempty"`
Interval time.Duration `yaml:"interval,omitempty"`
Threshold float64 `yaml:"threshold,omitempty"`
}
CAAutoRotateConfig configures the CA auto-rotation scanner: interval between scans, and threshold (as fraction of total lifetime) to trigger rotation. Defaults: Interval=6h, Threshold=0.20 (applied at runtime in the scanner).
type CAImportConfig ¶ added in v0.8.0
type CAImportConfig struct {
MaxArgon2MemoryKiB uint32 `yaml:"max_argon2_memory_kib,omitempty"`
MaxArgon2Iterations uint32 `yaml:"max_argon2_iterations,omitempty"`
MaxArgon2Parallelism uint8 `yaml:"max_argon2_parallelism,omitempty"`
}
CAImportConfig bounds server-side Argon2 work for encrypted CA keys. Zero values use the conservative defaults from internal/caimport.
type MetricsConfig ¶
type MetricsConfig struct {
// Prometheus is a pointer so an unset value (yaml omitted) is treated
// as the default (true). A user setting `prometheus: false` cleanly
// disables the exporter.
Prometheus *bool `yaml:"prometheus,omitempty"`
// RequireAuth gates the /metrics endpoint behind the same bearer auth as
// the API (#187). It is a pointer so an unset value (yaml omitted) takes
// the default (true, #262): the metric labels expose host/network/CA IDs
// and operational counters, so unauthenticated scraping is opt-in. Set
// `require_auth: false` to allow it on a trusted network.
RequireAuth *bool `yaml:"require_auth,omitempty"`
}
MetricsConfig toggles the Prometheus exporter and whether it requires auth.
func (MetricsConfig) PrometheusEnabled ¶
func (m MetricsConfig) PrometheusEnabled() bool
PrometheusEnabled returns whether the Prometheus exporter should be served. Defaults to true when unset.
func (MetricsConfig) RequireAuthEnabled ¶ added in v0.7.0
func (m MetricsConfig) RequireAuthEnabled() bool
RequireAuthEnabled returns whether /metrics must be bearer-authenticated. Defaults to true when unset (#262); set `require_auth: false` to opt into unauthenticated scraping on a trusted network.
type OIDCConfig ¶
type OIDCConfig struct {
Enabled bool `yaml:"enabled"`
Issuer string `yaml:"issuer"`
ClientID string `yaml:"client_id"`
ClientSecret string `yaml:"client_secret"`
RedirectURL string `yaml:"redirect_url"`
Scopes []string `yaml:"scopes,omitempty"`
UsernameClaim string `yaml:"username_claim,omitempty"` // default "preferred_username"
NameClaim string `yaml:"name_claim,omitempty"` // default "name"
GroupsClaim string `yaml:"groups_claim,omitempty"` // default "groups"
AllowedGroups []string `yaml:"allowed_groups,omitempty"`
AllowedEmails []string `yaml:"allowed_emails,omitempty"`
DefaultRole string `yaml:"default_role,omitempty"`
// RequireEmailVerified gates the post-callback email_verified claim
// check. Pointer-bool to distinguish unset (default true: the IdP
// must assert email_verified before the address counts toward
// AllowedEmails) from an explicit `false` opt-out. The explicit
// opt-out is the escape hatch for legacy IdPs that omit the claim
// or send it in a shape HandleCallback can't decode (numeric,
// nested object, etc). emailVerifiedRequired() resolves nil → true.
RequireEmailVerified *bool `yaml:"require_email_verified,omitempty"`
// TLSCACert optionally pins the IdP's TLS trust to a PEM CA bundle at this
// path (#264). When set, OIDC discovery, JWKS fetch, and token exchange use
// a dedicated HTTP client whose RootCAs is this bundle, so a CA compromise
// in the system trust store cannot MITM the IdP. Empty = use the system
// trust store (default). The system store is untouched for every other
// connection.
TLSCACert string `yaml:"tls_ca_cert,omitempty"`
}
OIDCConfig configures an OpenID Connect identity provider for operator login. If nil or Enabled=false, OIDC login is not offered.
func (*OIDCConfig) EmailVerifiedRequired ¶
func (o *OIDCConfig) EmailVerifiedRequired() bool
EmailVerifiedRequired reports whether HandleCallback must enforce the email_verified claim. Defaults to true when RequireEmailVerified is unset.
func (*OIDCConfig) Validate ¶
func (o *OIDCConfig) Validate() error
Validate refuses configurations that would silently auto-provision the first OIDC user as admin. Either constrain who can log in (allowed_groups or allowed_emails), or auto-provision as a lower-privileged role (default_role != "admin"). Setting default_role: admin with empty allowlists is permitted only as a deliberate two-field opt-in to "anyone-who-can-log-in-is-admin".
type PasswordConfig ¶
type PasswordConfig struct {
MinLength *int `yaml:"min_length,omitempty"`
RequireClasses *int `yaml:"require_classes,omitempty"`
BlockCommon *bool `yaml:"block_common,omitempty"`
BlockUsername *bool `yaml:"block_username,omitempty"`
}
PasswordConfig overrides the password policy defaults.
type RateLimitConfig ¶
type RateLimitConfig struct {
// Enabled is a pointer so an absent YAML block defaults to "true"
// (issue #52 requires on-by-default) while still allowing a
// `rate_limit: { enabled: false }` to disable it.
Enabled *bool `yaml:"enabled,omitempty"`
TrustProxyHeader bool `yaml:"trust_proxy_header,omitempty"`
Groups map[string]RateLimitGroupConfig `yaml:"groups,omitempty"`
}
RateLimitConfig drives the rate-limit middleware. Enabled defaults to true; turn it off in trusted-network deployments by setting `rate_limit: { enabled: false }`. Set `trust_proxy_header: true` when running behind a reverse proxy that adds X-Forwarded-For.
func (RateLimitConfig) IsEnabled ¶
func (c RateLimitConfig) IsEnabled() bool
IsEnabled returns whether the limiter should run. Default: true.
type RateLimitGroupConfig ¶
RateLimitGroupConfig is the per-group rate/burst pair.
type ServerConfig ¶
type ServerConfig struct {
Listen string `yaml:"listen"`
DataDir string `yaml:"data_dir"`
DBPath string `yaml:"db_path"`
UIPassword string `yaml:"ui_password,omitempty"`
LogLevel string `yaml:"log_level"`
TLSCert string `yaml:"tls_cert,omitempty"`
TLSKey string `yaml:"tls_key,omitempty"`
OIDC *OIDCConfig `yaml:"oidc,omitempty"`
// AllowInsecureHTTP opts out of the plaintext-HTTP guard (#179). Without
// TLS, the server only binds a loopback address (safe behind a local
// reverse proxy); binding a routable address in cleartext is refused
// unless this is set true (or the --insecure-http flag is passed). Keep
// it false in production — credentials would otherwise transit in the clear.
AllowInsecureHTTP bool `yaml:"allow_insecure_http,omitempty"`
// TrustedSecretIngressProxy allows a local TLS-terminating proxy to mark
// private-key import requests with X-Forwarded-Proto: https. The request
// policy additionally requires a loopback listener and peer and a public
// Host value. The proxy must overwrite, not append, the header.
TrustedSecretIngressProxy bool `yaml:"trusted_secret_ingress_proxy,omitempty"`
// CAImport sets resource caps for encrypted CA private-key import.
CAImport CAImportConfig `yaml:"ca_import,omitempty"`
// MasterKey is a base64-encoded 32-byte AES-256 key used to wrap
// per-CA DEKs in the cas table. May be supplied via the
// NEBULA_MGMT_MASTER_KEY env var instead.
MasterKey string `yaml:"master_key,omitempty"`
// AllowSelfRegistration controls whether unauthenticated visitors can
// create their own operator account through /ui/register. Defaults to
// false so closed deployments stay closed by default; administrators
// can still create operators manually via the existing
// `nebula-mgmt user create` CLI or `POST /api/v1/operators` API.
AllowSelfRegistration bool `yaml:"allow_self_registration,omitempty"`
// Metrics configures the optional /metrics Prometheus exporter. Default
// is "enabled" so out-of-the-box installs can be scraped immediately;
// air-gapped deployments can set Prometheus=false to drop the route.
Metrics MetricsConfig `yaml:"metrics,omitempty"`
// Alerts configures the cert-expiry alerter (see issue #41). Disabled
// by default — operators must opt in by setting Enabled=true.
Alerts AlertsConfig `yaml:"alerts,omitempty"`
// Webhooks configures outbound lifecycle-event delivery (#256). Disabled
// by default — operators opt in by setting Enabled=true and a URL.
Webhooks WebhooksConfig `yaml:"webhooks,omitempty"`
// RateLimit configures the per-IP, per-route-group token-bucket
// limiter that fronts the Web UI and API (see issue #52). Enabled
// by default so login + enrolment endpoints are protected from
// online brute-force out of the box.
RateLimit RateLimitConfig `yaml:"rate_limit,omitempty"`
// Password configures the password policy applied to every server-
// side password-setting path (see issue #48). All knobs are
// optional: unset values fall back to the production defaults
// (10-char min, 3-of-4 classes, common-pw + username block on).
Password PasswordConfig `yaml:"password,omitempty"`
// EnforceTOTP toggles admin-enforced 2FA (issue #49). When set, the
// value is written into the server_settings table on startup so it
// stays in effect across restarts. A nil pointer (unset YAML) leaves
// the DB value alone — the future Settings UI (#47) will edit the
// same row at runtime.
EnforceTOTP *bool `yaml:"enforce_2fa,omitempty"`
// EnrollmentTokenTTL is the default lifetime applied to freshly minted
// enrollment tokens (ADR 0004 / #75). Per-network overrides live in
// the `network_config` table under the `enrollment_token_ttl` key.
// Empty / unparseable value falls back to 24h.
EnrollmentTokenTTL string `yaml:"enrollment_token_ttl,omitempty"`
// CAAutoRotate configures the periodic CA auto-rotation scanner (issue #110).
// Disabled by default — operators must opt in by setting Enabled=true.
CAAutoRotate CAAutoRotateConfig `yaml:"ca_auto_rotate,omitempty"`
// CookieSecure controls the `Secure` attribute on session and OIDC
// state cookies (GHSA-rqfj-vv8r-xhqc). When unset, the effective
// value is inferred from the TLS configuration: true if both
// tls_cert and tls_key are populated, false otherwise. Operators
// terminating TLS at a reverse proxy must set this to true
// explicitly — `rate_limit.trust_proxy_header` is not a reliable
// signal that the proxy speaks TLS to clients.
CookieSecure *bool `yaml:"cookie_secure,omitempty"`
// contains filtered or unexported fields
}
func LoadServerConfig ¶
func LoadServerConfig(path string) (*ServerConfig, error)
func (ServerConfig) CookieSecureResolved ¶
func (c ServerConfig) CookieSecureResolved() bool
CookieSecureResolved returns the effective Secure-cookie flag for this configuration. Explicit value wins; if unset, infer from the presence of TLS material on the server itself.
func (ServerConfig) EnrollmentTokenTTLDuration ¶
func (c ServerConfig) EnrollmentTokenTTLDuration() time.Duration
EnrollmentTokenTTLDuration returns the configured default token TTL parsed as a Go duration. Falls back to 24h when unset or invalid so the server always has a sane default.
func (*ServerConfig) HasLegacyAPIKey ¶
func (c *ServerConfig) HasLegacyAPIKey() bool
HasLegacyAPIKey reports whether the YAML config contained a top-level `api_key:` key. The field was removed per #127 in favor of one-time stdout output and recovery via `nebula-mgmt ops mint-admin-key`.
func (*ServerConfig) RequireSecureBind ¶ added in v0.3.7
func (c *ServerConfig) RequireSecureBind() error
RequireSecureBind enforces the plaintext-HTTP guard (#179). It returns an error when the server would serve cleartext on a routable address:
- TLS configured (tls_cert+tls_key) → always allowed.
- No TLS, AllowInsecureHTTP set → allowed (explicit opt-out).
- No TLS, Listen bound to a loopback address → allowed (proxy-friendly).
- No TLS, Listen bound to anything else → refused.
Called at startup after the --insecure-http flag has been folded into AllowInsecureHTTP, so the CLI flag and the config field share one code path.
type WebhooksConfig ¶ added in v0.6.0
type WebhooksConfig struct {
Enabled bool `yaml:"enabled,omitempty"`
URL string `yaml:"url,omitempty"`
HMACSecret string `yaml:"hmac_secret,omitempty"`
AllowPrivate bool `yaml:"allow_private,omitempty"`
Events []string `yaml:"events,omitempty"`
}
WebhooksConfig configures the outbound lifecycle-event webhook (#256). The dispatcher signs each delivery (HMACSecret), filters by event type (Events; empty means all), and SSRF-guards the target unless AllowPrivate is set.