keter-rate-limiting-plugin 0.2.0.0 → 0.2.0.1
raw patch · 3 files changed
+226/−3 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- CHANGELOG.md +3/−0
- README.md +222/−2
- keter-rate-limiting-plugin.cabal +1/−1
CHANGELOG.md view
@@ -24,3 +24,6 @@ * Second version. Changed Keter.RateLimiter.WAI module to remove multiple times computed data while working on the advice of @jappeace for keter integration and to prevent potential memory leak when keter reloads configuration. +## 0.2.0.1 -- 2025-09-28++* Second version revised A. Updated documentation in README.md to include basic information on keter integration (expected in the keter-2.3.0).
README.md view
@@ -194,8 +194,228 @@ ## Example Usage -### Using the Convenient API+## For the Keter Users (is expected to be introduced in keter-2.3.0, see the README there+and / or Changelog file) +### Important notes++Configure middleware in app bundles (config/keter.yaml), +not in the global Keter daemon config. The global keter-config.yaml +remains for listeners, TLS, ip-from-header, healthcheck-path, etc. +Requests to healthcheck-path are never rate-limited.++### Quick Start++Attach a rate-limiter to any stanza via a middleware list.++Example bundle config (config/keter.yaml):++```yaml+stanzas:+ - type: webapp+ exec: ./my-app+ hosts: ["www.example.com"]+ middleware:+ - rate-limiter:+ zone_by: default+ throttles:+ - name: "ip-basic"+ limit: 100+ period: 60+ algorithm: FixedWindow+ identifier_by: ip++ - type: reverse-proxy+ hosts: ["api.example.com"]+ to: "http://127.0.0.1:9000"+ middleware:+ - rate-limiter:+ zone_by: { header: "X-Tenant-ID" }+ throttles:+ - name: "tenant-api"+ limit: 1000+ period: 3600+ algorithm: SlidingWindow+ identifier_by: { header: "X-Api-Key" }++ - type: static-files+ hosts: ["static.example.com"]+ root: ./static+ middleware:+ - rate-limiter:+ zone_by: ip+ throttles:+ - name: "static-ip"+ limit: 300+ period: 60+ algorithm: LeakyBucket+ identifier_by: ip+```++Tip: You can stack multiple middleware blocks if you need +different protections. They run in order.++### Field Reference++* `rate-limiter`: top-level middleware key.+* `zone_by`:+ 1. `"default"`: counters are isolated per vhost (Host header). Good per-domain isolation.+ 2. `"ip"`: counters are isolated per client IP zone. Good for IP fairness.+ 3. `{ "header": "X-Header" }`: per-tenant/customer isolation via a header value.+* `throttles`: list of rules. Each rule:+ 1. `name`: a label for logs/metrics.+ 2. `limit`: integer capacity or max requests.+ 3. `period`: seconds (window or refill/leak interval depending on algorithm).+ 4. `algorithm`: one of `FixedWindow | SlidingWindow | TokenBucket | LeakyBucket | TinyLRU`.+ 5. `identifier_by`:+ * `"ip"`: identify by client IP (honors global ip-from-header).+ * `"ip+path"`: combine IP and path for path-specific throttles (e.g., /login).+ * `"ip+ua"`: combine IP and User-Agent.+ * `{ "header": "X-User" }`: identify by a header value.+ * `{ "cookie": "session" }`: identify by a cookie value.+ * `{ "header+ip": "X-Key" }`: combine header and IP.+ 6. `token_bucket_ttl`: optional seconds; TokenBucket only (evicts idle buckets).++### Choosing Algorithms++Rule of thumb for common scenarios:++* **FixedWindow**+ 1. When: Simple quotas (e.g., 100 req/min per IP).+ 2. Pros: Simple, low overhead.+ 3. Cons: Window boundary bursts possible.+ 4. Use for: Public pages, basic protections.++* **SlidingWindow**+ 1. When: Smoother enforcement over time; avoid boundary spikes.+ 2. Pros: More accurate rolling rate.+ 3. Cons: More state churn than FixedWindow.+ 4. Use for: API endpoints where fairness matters.++* **TokenBucket**+ 1. When: Allow short bursts but control average rate.+ 2. Pros: Classic API limiter; bursty but bounded.+ 3. Cons: Requires sensible period; consider TTL for idle buckets.+ 4. Use for: Developer APIs, webhook receivers.+ 5. Tip: Set token_bucket_ttl (e.g., 1800s) to evict idle buckets.++* **LeakyBucket**+ 1. When: Smooth out bursts to a steady outflow.+ 2. Pros: Predictable, backpressure-like effect.+ 3. Cons: Tuning capacity vs leak rate.+ 4. Use for: Form submissions, login attempts.++* **TinyLRU**+ 1. When: Lightweight micro-throttling with tiny memory footprint.+ 2. Pros: Very small, simple.+ 3. Cons: Coarser control than others.+ 4. Use for: Edge micro-protection, complementary limits.++### Practical Patterns++* Path-specific throttles (e.g., login):++```yaml+middleware:+ - rate-limiter:+ zone_by: default+ throttles:+ - name: "login"+ limit: 5+ period: 60+ algorithm: SlidingWindow+ identifier_by: ip+path+```++* API key quotas per tenant:++```yaml+middleware:+ - rate-limiter:+ zone_by: { header: "X-Tenant-ID" }+ throttles:+ - name: "tenant-quota"+ limit: 1000+ period: 3600+ algorithm: TokenBucket+ identifier_by: { header: "X-Api-Key" }+ token_bucket_ttl: 1800+```++* Mixed protections on the same host:++```yaml+middleware:+ - rate-limiter:+ zone_by: default+ throttles:+ - { name: "global-ip", limit: 600, period: 600, algorithm: FixedWindow, identifier_by: ip }+ - rate-limiter:+ zone_by: default+ throttles:+ - { name: "login", limit: 5, period: 60, algorithm: SlidingWindow, identifier_by: ip+path }+```++* Static assets fairness:++```yaml+- type: static-files+ hosts: ["cdn.example.com"]+ root: ./public+ middleware:+ - rate-limiter:+ zone_by: ip+ throttles:+ - { name: "cdn-ip", limit: 300, period: 60, algorithm: LeakyBucket, identifier_by: ip }+```++### Global keter daemon settings impacting behavior (keter-config.yaml):++* `ip-from-header`: influences throttles with `identifier_by: ip`.+* `healthcheck-path`: this path is always allowed and never rate-limited.+++### Operational Tips++* Start with SlidingWindow or TokenBucket for APIs; FixedWindow +for simple pages; add a strict path-specific rule for sensitive +endpoints (/login, /password-reset).+* Tune limit/period to real traffic; prefer longer periods with +proportionally larger limits for smoother behavior.+* If behind a load balancer/proxy, set ip-from-header: true +in keter-config.yaml to honor X-Forwarded-For.+* Keep healthcheck-path simple (e.g., /keter-health); it's always +bypassed by the limiter.+* For multi-tenant apps, use zone_by: { header: "X-Tenant-ID" } +so each tenant's counters are isolated; pair with header/cookie +identifiers that match your auth.+* Use token_bucket_ttl to bound memory for TokenBucket.+* Stacking throttles is common; the most restrictive one effectively +governs.+* Consider integrating limiter notifications with your logging/metrics.++### FAQ++* **Should I configure middleware in the global Keter config?**++No. Middleware is per-app in bundles (config/keter.yaml). The global file +configures listeners, TLS, ip-from-header, and healthcheck-path.++* **Does it work with HTTPS and multiple listeners?**++Yes. The middleware is applied uniformly; rate limiting is agnostic +to scheme.++* **How do vhosts interact with rate limits?**++With zone_by: default, counters are isolated per Host. Different hosts +pointing to the same backend port don't share counters.++If you'd like help choosing safe defaults for your workloads, open +an issue with a brief description of your traffic patterns and endpoints.++## Using the Convenient API+ The `CacheWithZone` module provides helpers that automatically compose cache keys from the algorithm, zone, and user key, simplifying common use cases while leveraging efficient HashMap-based zone lookups. ```haskell@@ -213,7 +433,7 @@ isAllowed <- allowFixedWindowRequest cache "zoneX" "userX" 100 3600 -- 100 requests per hour ``` -### Using the Customizable API+## Using the Customizable API For more complex scenarios, you can manually construct cache keys and interact directly with the `Cache` module. This gives you full control over the key structure while still benefiting from HashMap-optimized storage.
keter-rate-limiting-plugin.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: keter-rate-limiting-plugin-version: 0.2.0.0+version: 0.2.0.1 synopsis: Simple Keter rate limiting plugin. description: A modern, high-performance, and highly customisable rate limiting plugin for keter.