feat: deliver Sense audits to Bell (T-016)
This commit is contained in:
@@ -26,6 +26,7 @@ const (
|
||||
defaultOrphanScanPeriod = time.Minute
|
||||
defaultONVIFMode = "disabled"
|
||||
defaultControlAuthMode = "static-sha256"
|
||||
defaultAuditRelayPeriod = time.Second
|
||||
)
|
||||
|
||||
var instanceIDPattern = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$`)
|
||||
@@ -53,6 +54,11 @@ type Config struct {
|
||||
ControlAuthFile string
|
||||
ControlCursorKeyFile string
|
||||
ControlAllowInsecureHTTP bool
|
||||
AuditRelayEnabled bool
|
||||
AuditRelayURL string
|
||||
AuditRelayKeyFile string
|
||||
AuditRelayKeyID string
|
||||
AuditRelayInterval time.Duration
|
||||
}
|
||||
|
||||
func Load() (Config, error) {
|
||||
@@ -92,6 +98,14 @@ func Load() (Config, error) {
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
auditRelayEnabled, err := boolEnv("SENSE_AUDIT_RELAY_ENABLED", false)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
auditRelayInterval, err := durationEnv("SENSE_AUDIT_RELAY_INTERVAL", defaultAuditRelayPeriod)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
metricsEnabled, err := boolEnv("SENSE_METRICS_ENABLED", true)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
@@ -130,6 +144,11 @@ func Load() (Config, error) {
|
||||
ControlAuthFile: stringEnv("SENSE_CONTROL_AUTH_FILE", ""),
|
||||
ControlCursorKeyFile: stringEnv("SENSE_CONTROL_CURSOR_KEY_FILE", ""),
|
||||
ControlAllowInsecureHTTP: controlAllowInsecure,
|
||||
AuditRelayEnabled: auditRelayEnabled,
|
||||
AuditRelayURL: stringEnv("SENSE_AUDIT_RELAY_URL", ""),
|
||||
AuditRelayKeyFile: stringEnv("SENSE_AUDIT_RELAY_KEY_FILE", ""),
|
||||
AuditRelayKeyID: stringEnv("SENSE_AUDIT_RELAY_KEY_ID", ""),
|
||||
AuditRelayInterval: auditRelayInterval,
|
||||
}
|
||||
if err := cfg.Validate(); err != nil {
|
||||
return Config{}, err
|
||||
@@ -228,6 +247,31 @@ func (c Config) Validate() error {
|
||||
return fmt.Errorf("non-loopback Control API requires SENSE_CONTROL_ALLOW_INSECURE_HTTP=true")
|
||||
}
|
||||
}
|
||||
if c.AuditRelayEnabled {
|
||||
if databaseDriver != postgresDatabaseDriver {
|
||||
return fmt.Errorf("Sense audit relay requires SENSE_DB_DRIVER=postgres")
|
||||
}
|
||||
if c.AuditRelayKeyFile == "" || !filepath.IsAbs(c.AuditRelayKeyFile) {
|
||||
return fmt.Errorf("SENSE_AUDIT_RELAY_KEY_FILE must be an absolute external path")
|
||||
}
|
||||
if !instanceIDPattern.MatchString(c.AuditRelayKeyID) {
|
||||
return fmt.Errorf("invalid SENSE_AUDIT_RELAY_KEY_ID")
|
||||
}
|
||||
if c.AuditRelayInterval < time.Second {
|
||||
return fmt.Errorf("SENSE_AUDIT_RELAY_INTERVAL must be at least 1s")
|
||||
}
|
||||
relayURL, err := url.Parse(c.AuditRelayURL)
|
||||
if err != nil || relayURL.Host == "" || relayURL.Path != "/internal/v1/audit-events:batch" ||
|
||||
relayURL.RawQuery != "" || relayURL.Fragment != "" || relayURL.User != nil {
|
||||
return fmt.Errorf("invalid SENSE_AUDIT_RELAY_URL")
|
||||
}
|
||||
relayHost := relayURL.Hostname()
|
||||
relayIP := net.ParseIP(relayHost)
|
||||
relayLoopback := relayHost == "localhost" || (relayIP != nil && relayIP.IsLoopback())
|
||||
if relayURL.Scheme != "https" && !(relayURL.Scheme == "http" && relayLoopback) {
|
||||
return fmt.Errorf("SENSE_AUDIT_RELAY_URL requires HTTPS outside loopback")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user