diff options
| author | Fuwn <[email protected]> | 2026-01-20 16:15:50 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-01-20 16:15:50 -0800 |
| commit | b147654b8aed7005760017f604aae58637ac7767 (patch) | |
| tree | 77cad60fc8eff8bd6c18a9846307e02bf1d6ba32 /internal/config | |
| parent | feat: Add all remaining monitor options to group defaults (diff) | |
| download | kaze-b147654b8aed7005760017f604aae58637ac7767.tar.xz kaze-b147654b8aed7005760017f604aae58637ac7767.zip | |
feat: Add API access control (public/private/authenticated)
Add configurable access control for /api/* endpoints:
- public: Anyone can access (default, backwards compatible)
- private: API endpoints return 403 Forbidden
- authenticated: Requires API key via X-API-Key header or ?api_key= param
Config example:
api:
access: authenticated
keys:
- "secret-key-1"
- "secret-key-2"
Diffstat (limited to 'internal/config')
| -rw-r--r-- | internal/config/config.go | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/internal/config/config.go b/internal/config/config.go index d82fee0..5f05b96 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -15,10 +15,22 @@ type Config struct { Server ServerConfig `yaml:"server"` Storage StorageConfig `yaml:"storage"` Display DisplayConfig `yaml:"display"` + API APIConfig `yaml:"api"` Groups []GroupConfig `yaml:"groups"` Incidents []IncidentConfig `yaml:"incidents"` } +// APIConfig contains settings for the JSON API endpoints +type APIConfig struct { + // Access controls who can access /api/* endpoints: + // "public" - Anyone can access (default) + // "private" - API endpoints are disabled (return 403) + // "authenticated" - Requires API key via X-API-Key header or ?api_key= query param + Access string `yaml:"access"` + // Keys is a list of valid API keys (only used when access is "authenticated") + Keys []string `yaml:"keys"` +} + // DisplayConfig contains display/UI settings type DisplayConfig struct { // TickMode controls how history is aggregated: ping, minute, hour, day @@ -241,6 +253,11 @@ func (c *Config) applyDefaults() { c.Display.Scale = 2.0 } + // Apply API defaults + if c.API.Access == "" { + c.API.Access = "public" + } + // Apply group defaults for i := range c.Groups { grp := &c.Groups[i] @@ -456,6 +473,18 @@ func (c *Config) validate() error { return fmt.Errorf("tick_count must be between 1 and 200, got %d", c.Display.TickCount) } + // Validate API config + switch c.API.Access { + case "", "public", "private", "authenticated": + // Valid modes ("" defaults to "public") + default: + return fmt.Errorf("invalid api.access %q (must be public, private, or authenticated)", c.API.Access) + } + + if c.API.Access == "authenticated" && len(c.API.Keys) == 0 { + return fmt.Errorf("api.access is 'authenticated' but no api.keys provided") + } + return nil } |