Documentation
¶
Overview ¶
Package security implements VORTEX's edge protection (build plan M3.7): an HTTP-layer token-bucket rate limiter keyed per client IP, an IP allowlist/blocklist with Tor-exit and auto-ban support, and an edge middleware that composes them. It is distinct from the M2.5 UDP rate limiter, which guards the UDP data plane. Standard library only.
Index ¶
- Constants
- type APIKeyRateLimiter
- func (l *APIKeyRateLimiter) Allow(key string, admin bool) bool
- func (l *APIKeyRateLimiter) SetClock(now func() time.Time)
- func (l *APIKeyRateLimiter) SetKeyLimit(key string, rpm int)
- func (l *APIKeyRateLimiter) StartCleanup(ctx context.Context)
- func (l *APIKeyRateLimiter) Sweep(idleTTL time.Duration)
- type APIKeyRateLimiterConfig
- type AutoBanConfig
- type Blocklist
- func (b *Blocklist) IsAllowed(ip string) (bool, string)
- func (b *Blocklist) ManualBlock(ip, reason string)
- func (b *Blocklist) ManualUnblock(ip string)
- func (b *Blocklist) RecordRequest(ip string)
- func (b *Blocklist) StartTorRefresh(ctx context.Context, url string)
- func (b *Blocklist) Stats() BlocklistStats
- type BlocklistConfig
- type BlocklistStats
- type BurstProtection
- func (b *BurstProtection) Allow(ip string) bool
- func (b *BurstProtection) Middleware() func(http.Handler) http.Handler
- func (b *BurstProtection) SetClock(now func() time.Time)
- func (b *BurstProtection) SetNotify(fn func(title, body string))
- func (b *BurstProtection) StartCleanup(ctx context.Context)
- func (b *BurstProtection) Sweep()
- type BurstProtectionConfig
- type Edge
- type EdgeConfig
- type EdgeStats
- type GlobalRateLimiter
- type HTTPRateLimiter
- type HTTPRateLimiterConfig
- type PerRouteRateLimiter
Constants ¶
const ( DefaultBurstThreshold = 100 DefaultBurstWindow = 1 * time.Second DefaultBurstBan = 5 * time.Minute )
Burst-protection defaults: an IP making more than DefaultBurstThreshold requests inside DefaultBurstWindow is banned for DefaultBurstBan.
const DefaultAPIKeyRPM = 1000
DefaultAPIKeyRPM is the per-key request budget when none is configured.
const DefaultGlobalRPM = 10000
DefaultGlobalRPM is the whole-server request budget when none is configured.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type APIKeyRateLimiter ¶ added in v0.3.0
type APIKeyRateLimiter struct {
// contains filtered or unexported fields
}
APIKeyRateLimiter applies a token bucket per authenticated API-key identity. Admin keys are never limited; individual keys can carry a custom budget set at creation time via SetKeyLimit. Safe for concurrent use.
func NewAPIKeyRateLimiter ¶ added in v0.3.0
func NewAPIKeyRateLimiter(cfg APIKeyRateLimiterConfig) *APIKeyRateLimiter
NewAPIKeyRateLimiter builds a per-key limiter from cfg.
func (*APIKeyRateLimiter) Allow ¶ added in v0.3.0
func (l *APIKeyRateLimiter) Allow(key string, admin bool) bool
Allow reports whether a request by the given key identity may proceed, consuming one token. Admin keys and keys with a non-positive custom limit are never limited.
func (*APIKeyRateLimiter) SetClock ¶ added in v0.3.0
func (l *APIKeyRateLimiter) SetClock(now func() time.Time)
SetClock overrides the limiter's time source (tests only).
func (*APIKeyRateLimiter) SetKeyLimit ¶ added in v0.3.0
func (l *APIKeyRateLimiter) SetKeyLimit(key string, rpm int)
SetKeyLimit assigns a custom per-minute budget to one key. A non-positive rpm makes the key unlimited. The key's bucket is reset so the new budget takes effect immediately.
func (*APIKeyRateLimiter) StartCleanup ¶ added in v0.3.0
func (l *APIKeyRateLimiter) StartCleanup(ctx context.Context)
StartCleanup periodically sweeps idle per-key buckets until ctx is cancelled.
func (*APIKeyRateLimiter) Sweep ¶ added in v0.3.0
func (l *APIKeyRateLimiter) Sweep(idleTTL time.Duration)
Sweep removes per-key buckets that have been idle beyond idleTTL, bounding memory under a churn of distinct keys (production audit H5).
type APIKeyRateLimiterConfig ¶ added in v0.3.0
type APIKeyRateLimiterConfig struct {
DefaultRPM int // requests per minute per key; <= 0 uses DefaultAPIKeyRPM
Enabled bool // when false, Allow always returns true
}
APIKeyRateLimiterConfig configures a per-API-key rate limiter.
type AutoBanConfig ¶
type AutoBanConfig struct {
Threshold int // requests within Window before a ban triggers
Window time.Duration // rolling window for counting requests
BanDuration time.Duration // how long a ban lasts
}
AutoBanConfig configures rolling-window automatic banning.
type Blocklist ¶
type Blocklist struct {
// contains filtered or unexported fields
}
Blocklist enforces IP allow/block decisions with optional Tor and auto-ban. It is safe for concurrent use.
func NewBlocklist ¶
func NewBlocklist(cfg BlocklistConfig) (*Blocklist, error)
NewBlocklist parses the allow/block lists and, when BlockTor is set, fetches the Tor exit-node list (gracefully degrading to no Tor blocking on failure).
func (*Blocklist) IsAllowed ¶
IsAllowed reports whether ip may proceed and a human-readable reason. The checks run in order: allowlist (if set), manual block, Tor exit, auto-ban.
func (*Blocklist) ManualBlock ¶
ManualBlock blocks ip at runtime with the given reason.
func (*Blocklist) ManualUnblock ¶
ManualUnblock removes a runtime manual block for ip.
func (*Blocklist) RecordRequest ¶
RecordRequest tracks a request from ip for auto-ban accounting; if the count within the configured window exceeds the threshold, ip is auto-banned.
func (*Blocklist) StartTorRefresh ¶
StartTorRefresh refreshes the Tor exit list every 24h until ctx is cancelled. It is a no-op when Tor blocking is disabled.
func (*Blocklist) Stats ¶
func (b *Blocklist) Stats() BlocklistStats
Stats returns a snapshot of current blocklist activity.
type BlocklistConfig ¶
type BlocklistConfig struct {
IPAllowlist []string // CIDRs or IPs; when non-empty, only these are allowed
IPBlocklist []string // CIDRs or IPs to always block
BlockTor bool // fetch and block Tor exit nodes
TorListURL string // override the Tor list URL (default official)
AutoBan AutoBanConfig
}
BlocklistConfig configures a Blocklist.
type BlocklistStats ¶
type BlocklistStats struct {
ManualBlocks int
AutoBans int
TorBlocks int
AllowlistSize int
TotalChecked int64
}
BlocklistStats is a snapshot of blocklist activity.
type BurstProtection ¶ added in v0.3.0
type BurstProtection struct {
// contains filtered or unexported fields
}
BurstProtection auto-bans IPs that exceed a request burst threshold (by default >100 requests within one second bans the IP for five minutes). An optional notifier (e.g. Telegram via the notification router) is alerted on each triggered ban. Safe for concurrent use.
func NewBurstProtection ¶ added in v0.3.0
func NewBurstProtection(cfg BurstProtectionConfig) *BurstProtection
NewBurstProtection builds a BurstProtection from cfg, applying defaults for zero fields.
func (*BurstProtection) Allow ¶ added in v0.3.0
func (b *BurstProtection) Allow(ip string) bool
Allow records a request from ip and reports whether it may proceed. It returns false while ip is banned; crossing the burst threshold triggers the ban, a WARN log, and the notifier.
func (*BurstProtection) Middleware ¶ added in v0.3.0
func (b *BurstProtection) Middleware() func(http.Handler) http.Handler
Middleware rejects requests from banned IPs with 429 and a Retry-After of the remaining ban duration (rounded up to a second).
func (*BurstProtection) SetClock ¶ added in v0.3.0
func (b *BurstProtection) SetClock(now func() time.Time)
SetClock overrides the protection's time source (tests only).
func (*BurstProtection) SetNotify ¶ added in v0.3.0
func (b *BurstProtection) SetNotify(fn func(title, body string))
SetNotify wires the out-of-band alert callback invoked when a ban triggers.
func (*BurstProtection) StartCleanup ¶ added in v0.3.0
func (b *BurstProtection) StartCleanup(ctx context.Context)
StartCleanup periodically sweeps idle burst windows and expired bans until ctx is cancelled.
func (*BurstProtection) Sweep ¶ added in v0.3.0
func (b *BurstProtection) Sweep()
Sweep removes per-IP burst windows and expired bans, bounding memory under a churn of distinct source IPs (production audit H5). Active bans are kept.
type BurstProtectionConfig ¶ added in v0.3.0
type BurstProtectionConfig struct {
Threshold int // requests inside Window that trigger a ban
Window time.Duration // burst measurement window
BanFor time.Duration // how long a triggered IP stays banned
}
BurstProtectionConfig configures BurstProtection. Zero values take the DefaultBurst* constants.
type Edge ¶
type Edge struct {
// contains filtered or unexported fields
}
Edge composes IP blocking and rate limiting into one HTTP middleware. It resolves the real client IP (honouring X-Forwarded-For only from trusted proxies) and exposes it downstream via the X-Vortex-Client-IP header.
func NewEdge ¶
func NewEdge(cfg EdgeConfig) *Edge
NewEdge builds an Edge from cfg. Invalid TrustedProxies entries are ignored (treated as no trusted proxy) so a misconfiguration fails closed — XFF is then never trusted.
func (*Edge) Middleware ¶
Middleware returns the edge security middleware. Pipeline per request:
- resolve the client IP (XFF if from a trusted proxy, else RemoteAddr)
- Blocklist.IsAllowed → 403 JSON if blocked
- Blocklist.RecordRequest (auto-ban accounting)
- RateLimit.Allow → 429 if limited
- next handler, with X-Vortex-Client-IP set to the resolved IP
type EdgeConfig ¶
type EdgeConfig struct {
Blocklist *Blocklist // may be nil to skip block checks
RateLimit *HTTPRateLimiter // may be nil to skip rate limiting
TrustedProxies []string // CIDRs/IPs whose X-Forwarded-For is trusted
}
EdgeConfig configures the edge security middleware.
type EdgeStats ¶
type EdgeStats struct {
Blocklist BlocklistStats
}
EdgeStats combines blocklist stats with edge-level counters.
type GlobalRateLimiter ¶ added in v0.3.0
type GlobalRateLimiter struct {
// contains filtered or unexported fields
}
GlobalRateLimiter is a single token bucket shared by every request the server handles, protecting against distributed floods that stay under any per-IP or per-key budget. Safe for concurrent use.
func NewGlobalRateLimiter ¶ added in v0.3.0
func NewGlobalRateLimiter(rpm int) *GlobalRateLimiter
NewGlobalRateLimiter builds a global limiter allowing rpm requests per minute across all clients; rpm <= 0 uses DefaultGlobalRPM.
func (*GlobalRateLimiter) Allow ¶ added in v0.3.0
func (g *GlobalRateLimiter) Allow() bool
Allow reports whether one more request may proceed, consuming one token.
func (*GlobalRateLimiter) Middleware ¶ added in v0.3.0
func (g *GlobalRateLimiter) Middleware() func(http.Handler) http.Handler
Middleware rejects requests with 429 once the global budget is exhausted.
func (*GlobalRateLimiter) SetClock ¶ added in v0.3.0
func (g *GlobalRateLimiter) SetClock(now func() time.Time)
SetClock overrides the limiter's time source (tests only).
type HTTPRateLimiter ¶
type HTTPRateLimiter struct {
// contains filtered or unexported fields
}
HTTPRateLimiter applies a token bucket per source IP. It is safe for concurrent use.
func NewHTTPRateLimiter ¶
func NewHTTPRateLimiter(cfg HTTPRateLimiterConfig) *HTTPRateLimiter
NewHTTPRateLimiter builds a limiter from cfg. A non-positive Burst defaults to RPM (one minute's worth of tokens).
func (*HTTPRateLimiter) Allow ¶
func (r *HTTPRateLimiter) Allow(ip string) bool
Allow reports whether a request from ip may proceed, consuming one token. When the limiter is disabled it always allows.
func (*HTTPRateLimiter) Middleware ¶
func (r *HTTPRateLimiter) Middleware() func(http.Handler) http.Handler
Middleware returns an HTTP middleware that rejects over-limit requests with a 429 and a JSON body, setting the Retry-After header. It logs a WARN on each rejection. The client IP is read from the X-Vortex-Client-IP header set by the edge (see edge.go); absent that it falls back to RemoteAddr.
func (*HTTPRateLimiter) SetClock ¶
func (r *HTTPRateLimiter) SetClock(now func() time.Time)
SetClock overrides the limiter's time source. It is intended for tests so rate-limit behaviour can be asserted deterministically without real waits.
func (*HTTPRateLimiter) StartCleanup ¶
func (r *HTTPRateLimiter) StartCleanup(ctx context.Context)
StartCleanup periodically removes buckets that have been idle beyond bucketIdleTTL, bounding memory under churning client IPs. It returns when ctx is cancelled.
type HTTPRateLimiterConfig ¶
type HTTPRateLimiterConfig struct {
RPM int // requests per minute per IP
Burst int // bucket capacity (max burst); defaults to RPM when <= 0
Enabled bool // when false, Allow always returns true
}
HTTPRateLimiterConfig configures a per-IP HTTP rate limiter.
type PerRouteRateLimiter ¶
type PerRouteRateLimiter struct {
// contains filtered or unexported fields
}
PerRouteRateLimiter holds an independent HTTPRateLimiter per route name.
func NewPerRouteRateLimiter ¶
func NewPerRouteRateLimiter(routes map[string]HTTPRateLimiterConfig) *PerRouteRateLimiter
NewPerRouteRateLimiter builds a limiter per route from the given configs.
func (*PerRouteRateLimiter) MiddlewareForRoute ¶
MiddlewareForRoute returns the rate-limit middleware for routeName, or a pass-through when the route has no configured limiter.