From bb79647fb581587d5a037f7bfc3462ba7317e2ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Thu, 23 Apr 2026 22:05:22 +0200 Subject: [PATCH 1/2] set more permissive default rate limits --- example-config.toml | 4 ++-- src/config.rs | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/example-config.toml b/example-config.toml index 2da968e..38beb76 100644 --- a/example-config.toml +++ b/example-config.toml @@ -7,6 +7,6 @@ http_port = 8080 grpc_port = 50051 log_level = "info" -rate_limit_per_second = 10 -rate_limit_burst = 100 +rate_limit_per_second = 100 +rate_limit_burst = 1000 acme_staging = false diff --git a/src/config.rs b/src/config.rs index 792df84..83b51cb 100644 --- a/src/config.rs +++ b/src/config.rs @@ -29,11 +29,11 @@ fn default_adoption_timeout() -> u64 { } fn default_rate_limit_per_second() -> u64 { - 10 + 100 } fn default_rate_limit_burst() -> u32 { - 100 + 1000 } #[derive(Parser, Debug, Deserialize, Clone)] @@ -58,11 +58,15 @@ pub struct EnvConfig { #[serde(default = "default_log_level")] pub log_level: LevelFilter, - #[arg(long, env = "DEFGUARD_PROXY_RATELIMIT_PERSECOND", default_value_t = 10)] + #[arg( + long, + env = "DEFGUARD_PROXY_RATELIMIT_PERSECOND", + default_value_t = 100 + )] #[serde(default = "default_rate_limit_per_second")] pub rate_limit_per_second: u64, - #[arg(long, env = "DEFGUARD_PROXY_RATELIMIT_BURST", default_value_t = 100)] + #[arg(long, env = "DEFGUARD_PROXY_RATELIMIT_BURST", default_value_t = 1000)] #[serde(default = "default_rate_limit_burst")] pub rate_limit_burst: u32, From 1d1e4c8379b8cc9d0eb8767c803e1b36fdfbfddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20W=C3=B3jcik?= Date: Thu, 23 Apr 2026 22:13:32 +0200 Subject: [PATCH 2/2] only rate-limit API routes --- src/http.rs | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/http.rs b/src/http.rs index 624db3e..2319702 100644 --- a/src/http.rs +++ b/src/http.rs @@ -499,24 +499,30 @@ pub async fn run_server( None }; + // Collect all API routes into a separate router to scope the rate-limiter middleware + let mut api_router = Router::new().nest( + "/api/v1", + Router::new() + .nest("/enrollment", enrollment::router()) + .nest("/password-reset", password_reset::router()) + .nest("/client-mfa", desktop_client_mfa::router()) + .nest("/openid", openid_login::router()) + .route("/poll", post(polling::info)) + .route("/health", get(healthcheck)) + .route("/health-grpc", get(healthcheckgrpc)) + .route("/info", get(app_info)), + ); + if let Some(conf) = governor_conf { + api_router = api_router.layer(GovernorLayer::new(conf)); + } + // Build axum app let mut app = Router::new() .route("/", get(index)) .route("/{*path}", get(index)) .route("/fonts/{*path}", get(web_asset)) .route("/assets/{*path}", get(web_asset)) - .nest( - "/api/v1", - Router::new() - .nest("/enrollment", enrollment::router()) - .nest("/password-reset", password_reset::router()) - .nest("/client-mfa", desktop_client_mfa::router()) - .nest("/openid", openid_login::router()) - .route("/poll", post(polling::info)) - .route("/health", get(healthcheck)) - .route("/health-grpc", get(healthcheckgrpc)) - .route("/info", get(app_info)), - ) + .merge(api_router) .fallback_service(get(handle_404)) .layer(middleware::from_fn_with_state( shared_state.clone(), @@ -546,9 +552,7 @@ pub async fn run_server( }) .on_response(trace::DefaultOnResponse::new().level(Level::DEBUG)), ); - if let Some(conf) = governor_conf { - app = app.layer(GovernorLayer::new(conf)); - } + // Global request body size limit; all proxy endpoints have small payloads. app = app.layer(DefaultBodyLimit::max(REQUEST_BODY_LIMIT)); // Security headers and version are the outermost layers so that ALL short-circuit