fix: replace broken DashMap rate limiting with tower-governor middleware
All checks were successful
CI Pipeline / Rust Format Check (push) Successful in 4s
CI Pipeline / Clippy Lints (push) Successful in 1m1s
CI Pipeline / Rust Unit Tests (push) Successful in 1m21s
CI Pipeline / Security Audit (push) Successful in 4s
CI Pipeline / Frontend Lint & Type Check (push) Successful in 16s
CI Pipeline / Build .deb & Release (push) Has been skipped
All checks were successful
CI Pipeline / Rust Format Check (push) Successful in 4s
CI Pipeline / Clippy Lints (push) Successful in 1m1s
CI Pipeline / Rust Unit Tests (push) Successful in 1m21s
CI Pipeline / Security Audit (push) Successful in 4s
CI Pipeline / Frontend Lint & Type Check (push) Successful in 16s
CI Pipeline / Build .deb & Release (push) Has been skipped
- Replace custom DashMap<IpAddr, Instant> rate limiting in enrollment.rs that fell back to 0.0.0.0 when X-Forwarded-For was missing, causing ALL enrollment traffic to share a single global rate limit bucket - Use tower_governor with SmartIpKeyExtractor for proper per-IP rate limiting that respects X-Forwarded-For headers (critical behind HAProxy) - Add three configurable rate limit tiers via config.toml: * Enrollment: 5 req/min per IP, burst 3 (strict) * Auth: 20 req/min per IP, burst 10 (moderate) * API: 120 req/min per IP, burst 30 (normal) - Remove enrollment_rate_limits from AppState and cleanup task - Remove manual rate limit code from enrollment.rs (headers param, IP extraction) - Add into_make_service_with_connect_info for ConnectInfo fallback - Add RateLimitConfig to AppConfig with sensible defaults Fixes: #1
This commit is contained in:
58
crates/pm-core/src/config.rs
Executable file → Normal file
58
crates/pm-core/src/config.rs
Executable file → Normal file
@ -1,6 +1,61 @@
|
||||
use config::{Config, ConfigError, Environment, File};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Rate limiting configuration per route group.
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct RateLimitConfig {
|
||||
/// Enrollment endpoint: requests per minute per IP (default: 5)
|
||||
#[serde(default = "default_enrollment_rpm")]
|
||||
pub enrollment_rpm: u32,
|
||||
/// Enrollment burst allowance (default: 3)
|
||||
#[serde(default = "default_enrollment_burst")]
|
||||
pub enrollment_burst: u32,
|
||||
/// Public auth endpoints: requests per minute per IP (default: 20)
|
||||
#[serde(default = "default_auth_rpm")]
|
||||
pub auth_rpm: u32,
|
||||
/// Auth burst allowance (default: 10)
|
||||
#[serde(default = "default_auth_burst")]
|
||||
pub auth_burst: u32,
|
||||
/// Authenticated API: requests per minute per IP (default: 120)
|
||||
#[serde(default = "default_api_rpm")]
|
||||
pub api_rpm: u32,
|
||||
/// API burst allowance (default: 30)
|
||||
#[serde(default = "default_api_burst")]
|
||||
pub api_burst: u32,
|
||||
}
|
||||
|
||||
fn default_enrollment_rpm() -> u32 {
|
||||
5
|
||||
}
|
||||
fn default_enrollment_burst() -> u32 {
|
||||
3
|
||||
}
|
||||
fn default_auth_rpm() -> u32 {
|
||||
20
|
||||
}
|
||||
fn default_auth_burst() -> u32 {
|
||||
10
|
||||
}
|
||||
fn default_api_rpm() -> u32 {
|
||||
120
|
||||
}
|
||||
fn default_api_burst() -> u32 {
|
||||
30
|
||||
}
|
||||
|
||||
impl Default for RateLimitConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enrollment_rpm: default_enrollment_rpm(),
|
||||
enrollment_burst: default_enrollment_burst(),
|
||||
auth_rpm: default_auth_rpm(),
|
||||
auth_burst: default_auth_burst(),
|
||||
api_rpm: default_api_rpm(),
|
||||
api_burst: default_api_burst(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Top-level application configuration.
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct AppConfig {
|
||||
@ -9,6 +64,8 @@ pub struct AppConfig {
|
||||
pub worker: WorkerConfig,
|
||||
pub logging: LoggingConfig,
|
||||
pub security: SecurityConfig,
|
||||
#[serde(default)]
|
||||
pub rate_limit: RateLimitConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
@ -151,6 +208,7 @@ impl Default for AppConfig {
|
||||
web_tls_key_path: "/etc/patch-manager/tls/web.key".to_string(),
|
||||
sso_callback_url: default_sso_callback_url(),
|
||||
},
|
||||
rate_limit: RateLimitConfig::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user