refactor(git): remove SSH rate limiting

SSH is deployed inside Kubernetes cluster where rate limiting
at the application layer is unnecessary. Remove all SSH rate
limiter code:
- SshRateLimiter from SSHandle and SSHServer structs
- is_user_allowed checks in auth_publickey, auth_publickey_offered
- is_repo_access_allowed in exec_request
- is_ip_allowed in server::new_client
- rate_limiter module and start_cleanup
This commit is contained in:
ZhenYi 2026-04-16 22:40:59 +08:00
parent 9368df54da
commit 0a998affbb
3 changed files with 2 additions and 70 deletions

View File

@ -2,7 +2,6 @@ use crate::ssh::ReceiveSyncService;
use crate::ssh::RepoReceiveSyncTask;
use crate::ssh::SshTokenService;
use crate::ssh::authz::SshAuthService;
use crate::ssh::rate_limit::SshRateLimiter;
use db::cache::AppCache;
use db::database::AppDatabase;
use models::repos::{repo, repo_branch_protect};
@ -20,7 +19,6 @@ use std::net::SocketAddr;
use std::path::PathBuf;
use std::process::Stdio;
use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration;
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWriteExt};
use tokio::process::ChildStdin;
@ -80,7 +78,6 @@ pub struct SSHandle {
pub sync: ReceiveSyncService,
pub upload_pack_eof_sent: HashSet<ChannelId>,
pub logger: Logger,
pub rate_limiter: Arc<SshRateLimiter>,
pub token_service: SshTokenService,
pub client_addr: Option<SocketAddr>,
}
@ -91,7 +88,6 @@ impl SSHandle {
cache: AppCache,
sync: ReceiveSyncService,
logger: Logger,
rate_limiter: Arc<SshRateLimiter>,
token_service: SshTokenService,
client_addr: Option<SocketAddr>,
) -> Self {
@ -115,7 +111,6 @@ impl SSHandle {
sync,
upload_pack_eof_sent: HashSet::new(),
logger,
rate_limiter,
token_service,
client_addr,
}
@ -201,17 +196,6 @@ impl russh::server::Handler for SSHandle {
}
};
let user_id = user_model.uid.to_string();
if !self.rate_limiter.is_user_allowed(&user_id).await {
warn!(
self.logger,
"SSH token auth rate limit exceeded: {}, client: {}",
user_model.username,
client_info
);
return Err(russh::Error::NotAuthenticated);
}
info!(
self.logger,
"SSH token authentication successful: user={}, client={}",
@ -278,16 +262,6 @@ impl russh::server::Handler for SSHandle {
}
};
let user_id = user_model.uid.to_string();
if !self.rate_limiter.is_user_allowed(&user_id).await {
let msg = format!(
"User rate limit exceeded: {}, client: {}",
user_model.username, client_info
);
warn!(self.logger, "{}", msg);
return Err(russh::Error::NotAuthenticated);
}
info!(
self.logger,
"SSH authentication successful: user={}, client={}", user_model.username, client_info
@ -345,16 +319,6 @@ impl russh::server::Handler for SSHandle {
}
};
let user_id = user_model.uid.to_string();
if !self.rate_limiter.is_user_allowed(&user_id).await {
let msg = format!(
"User rate limit exceeded: {}, client: {}",
user_model.username, client_info
);
warn!(self.logger, "{}", msg);
return Err(russh::Error::NotAuthenticated);
}
info!(
self.logger,
"SSH authentication successful: user={}, client={}", user_model.username, client_info
@ -371,10 +335,7 @@ impl russh::server::Handler for SSHandle {
channel: ChannelId,
_: &mut Session,
) -> Result<(), Self::Error> {
info!(self.logger, "channel_close";
"channel" => ?channel,
"client" => ?self.client_addr
);
info!(self.logger, "{}", format!("channel_close channel={:?} client={:?}", channel, self.client_addr));
self.cleanup_channel(channel);
Ok(())
}
@ -682,19 +643,6 @@ impl russh::server::Handler for SSHandle {
return Err(russh::Error::Disconnect);
}
let user_id = operator.uid.to_string();
let repo_path = format!("{}/{}", owner, &repo.repo_name);
if !self
.rate_limiter
.is_repo_access_allowed(&user_id, &repo_path)
.await
{
let msg = format!("Rate limit exceeded for repository access: {}", repo_path);
warn!(self.logger, "{}", format!("Repo access rate limit exceeded user={} repo={}", operator.username, repo.repo_name));
session.disconnect(Disconnect::ByApplication, &msg, "").ok();
return Err(russh::Error::Disconnect);
}
info!(self.logger, "{}", format!("Access granted user={} repo={} is_write={}", operator.username, repo.repo_name, is_write));
let repo_path = PathBuf::from(&repo.storage_path);

View File

@ -19,7 +19,6 @@ use std::time::Duration;
pub mod authz;
pub mod handle;
pub mod rate_limit;
pub mod server;
#[derive(Clone)]
@ -148,7 +147,6 @@ impl SSHHandle {
// Start the rate limiter cleanup background task so the HashMap
// doesn't grow unbounded over time.
let _cleanup = server.rate_limiter.clone().start_cleanup();
let ssh_port = self.app.ssh_port()?;
let bind_addr = format!("0.0.0.0:{}", ssh_port);
let public_host = self.app.ssh_domain()?;

View File

@ -1,7 +1,6 @@
use crate::ssh::ReceiveSyncService;
use crate::ssh::SshTokenService;
use crate::ssh::handle::SSHandle;
use crate::ssh::rate_limit::SshRateLimiter;
use db::cache::AppCache;
use db::database::AppDatabase;
use deadpool_redis::cluster::Pool as RedisPool;
@ -9,14 +8,12 @@ use russh::server::Handler;
use slog::{Logger, info, warn};
use std::io;
use std::net::SocketAddr;
use std::sync::Arc;
pub struct SSHServer {
pub db: AppDatabase,
pub cache: AppCache,
pub redis_pool: RedisPool,
pub logger: Logger,
pub rate_limiter: Arc<SshRateLimiter>,
pub token_service: SshTokenService,
}
@ -33,7 +30,6 @@ impl SSHServer {
cache,
redis_pool,
logger,
rate_limiter: Arc::new(SshRateLimiter::new()),
token_service,
}
}
@ -43,21 +39,12 @@ impl russh::server::Server for SSHServer {
fn new_client(&mut self, addr: Option<SocketAddr>) -> Self::Handler {
if let Some(addr) = addr {
let ip = addr.ip().to_string();
info!(
self.logger,
"New SSH connection from {}:{}",
ip,
addr.ip(),
addr.port()
);
let rate_limiter = self.rate_limiter.clone();
let logger = self.logger.clone();
tokio::spawn(async move {
if !rate_limiter.is_ip_allowed(&ip).await {
warn!(logger, "{}", format!("IP rate limit exceeded ip={}", ip));
}
});
} else {
info!(self.logger, "New SSH connection from unknown address");
}
@ -67,7 +54,6 @@ impl russh::server::Server for SSHServer {
self.cache.clone(),
sync_service,
self.logger.clone(),
self.rate_limiter.clone(),
self.token_service.clone(),
addr,
)