mirror of
https://github.com/whit3rabbit/anyllm-proxy.git
synced 2026-09-22 00:00:50 +00:00
security: configurable rate limit fail policy via RATE_LIMIT_FAIL_POLICY
Add "deny" as alias for "closed" policy. Change fail-closed retry-after from 1s to 60s to give Redis time to recover. Add from_env default test. Document env var in CLAUDE.md. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
3b43c8cae2
commit
591fdee72b
@@ -91,6 +91,7 @@ OPENAI_API_KEY=sk-... cargo run -p anyllm_proxy
|
||||
- `IP_ALLOWLIST`: Comma-separated CIDR ranges for IP allowlisting (e.g., `192.168.1.0/24,10.0.0.0/8`). Bare IPs also accepted. When set, only matching IPs can access the proxy.
|
||||
- `TRUST_PROXY_HEADERS`: Set to `true` or `1` to use `X-Forwarded-For` header for client IP when behind a reverse proxy. Only effective when `IP_ALLOWLIST` is set.
|
||||
- `WEBHOOK_URLS`: Comma-separated webhook URLs for request completion notifications. Fire-and-forget HTTP POST with `RequestLogEntry` JSON payload.
|
||||
- `RATE_LIMIT_FAIL_POLICY`: Behavior when Redis rate limiter is unavailable: `open` (default, allow requests) or `closed`/`deny` (reject with 503 and retry-after 60s).
|
||||
|
||||
### LiteLLM env var aliases
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ pub enum RateLimitFailPolicy {
|
||||
impl RateLimitFailPolicy {
|
||||
pub fn from_env_str(s: &str) -> Self {
|
||||
match s.to_lowercase().as_str() {
|
||||
"closed" => Self::Closed,
|
||||
"closed" | "deny" => Self::Closed,
|
||||
_ => Self::Open,
|
||||
}
|
||||
}
|
||||
@@ -97,7 +97,7 @@ impl RedisRateLimiter {
|
||||
}
|
||||
RateLimitFailPolicy::Closed => {
|
||||
tracing::error!(error = %e, "Redis RPM check failed, rejecting request (fail-closed)");
|
||||
Err(1)
|
||||
Err(60)
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -164,7 +164,7 @@ impl RedisRateLimiter {
|
||||
}
|
||||
RateLimitFailPolicy::Closed => {
|
||||
tracing::error!(error = %e, "Redis TPM check failed, rejecting request (fail-closed)");
|
||||
Err(1)
|
||||
Err(60)
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -265,9 +265,25 @@ mod tests {
|
||||
RateLimitFailPolicy::from_env_str("CLOSED"),
|
||||
RateLimitFailPolicy::Closed
|
||||
));
|
||||
assert!(matches!(
|
||||
RateLimitFailPolicy::from_env_str("deny"),
|
||||
RateLimitFailPolicy::Closed
|
||||
));
|
||||
assert!(matches!(
|
||||
RateLimitFailPolicy::from_env_str("DENY"),
|
||||
RateLimitFailPolicy::Closed
|
||||
));
|
||||
assert!(matches!(
|
||||
RateLimitFailPolicy::from_env_str("unknown"),
|
||||
RateLimitFailPolicy::Open
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fail_policy_defaults_to_open() {
|
||||
// When RATE_LIMIT_FAIL_POLICY is unset, from_env should return Open.
|
||||
std::env::remove_var("RATE_LIMIT_FAIL_POLICY");
|
||||
let policy = RateLimitFailPolicy::from_env();
|
||||
assert_eq!(policy, RateLimitFailPolicy::Open);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user