-
Notifications
You must be signed in to change notification settings - Fork 1
Closed
Labels
priority:mediumMedium priority issueMedium priority issuestatus:doneCompletedCompletedtype:enhancementNew feature or requestNew feature or requesttype:securitySecurity vulnerability or fixSecurity vulnerability or fix
Description
Summary
Implement IP-based access control to allow or deny connections from specific IP addresses or CIDR ranges.
Parent Epic
- Implement bssh-server with SFTP/SCP support #123 - bssh-server 추가 구현
- Depends on: Implement authentication rate limiting (fail2ban-like) #140 (rate limiting)
Implementation Details
1. IP Access Control
// src/server/security/access.rs
use ipnetwork::IpNetwork;
use std::net::IpAddr;
/// IP-based access control
pub struct IpAccessControl {
/// Allowed IP ranges (whitelist mode)
allowed: Vec<IpNetwork>,
/// Blocked IP ranges (blacklist)
blocked: Vec<IpNetwork>,
/// Default policy when no rules match
default_policy: AccessPolicy,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum AccessPolicy {
Allow,
Deny,
}
impl IpAccessControl {
pub fn new() -> Self {
Self {
allowed: Vec::new(),
blocked: Vec::new(),
default_policy: AccessPolicy::Allow,
}
}
pub fn from_config(config: &SecurityConfig) -> Result<Self> {
let mut ctrl = Self::new();
for cidr in &config.allowed_ips {
let network: IpNetwork = cidr.parse()
.context(format!("Invalid allowed_ips CIDR: {}", cidr))?;
ctrl.allowed.push(network);
}
for cidr in &config.blocked_ips {
let network: IpNetwork = cidr.parse()
.context(format!("Invalid blocked_ips CIDR: {}", cidr))?;
ctrl.blocked.push(network);
}
// If allowed list is specified, default to deny
if !ctrl.allowed.is_empty() {
ctrl.default_policy = AccessPolicy::Deny;
}
Ok(ctrl)
}
/// Check if IP is allowed to connect
pub fn check(&self, ip: &IpAddr) -> AccessPolicy {
// Check blocked list first (blacklist takes priority)
for network in &self.blocked {
if network.contains(*ip) {
tracing::debug!("IP {} blocked by rule {}", ip, network);
return AccessPolicy::Deny;
}
}
// Check allowed list (whitelist)
if !self.allowed.is_empty() {
for network in &self.allowed {
if network.contains(*ip) {
return AccessPolicy::Allow;
}
}
// Not in whitelist
tracing::debug!("IP {} not in allowed list", ip);
return AccessPolicy::Deny;
}
self.default_policy
}
/// Add allowed range
pub fn allow(&mut self, network: IpNetwork) {
self.allowed.push(network);
}
/// Add blocked range
pub fn block(&mut self, network: IpNetwork) {
self.blocked.push(network);
}
}2. Integrate at Connection Level
// Update src/server/mod.rs
impl russh::server::Server for BsshServer {
fn new_client(&mut self, peer_addr: Option<SocketAddr>) -> Option<Self::Handler> {
// Check IP access control before creating handler
if let Some(addr) = peer_addr {
let ip = addr.ip();
// Check IP access control
if self.config.security.ip_access.check(&ip) == AccessPolicy::Deny {
tracing::info!("Connection rejected from {} (IP access control)", ip);
return None;
}
// Check rate limit ban
if self.rate_limiter.is_banned_sync(&ip) {
tracing::info!("Connection rejected from {} (banned)", ip);
return None;
}
}
Some(SshHandler::new(peer_addr, ...))
}
}3. Dynamic Updates
impl IpAccessControl {
/// Add IP to block list at runtime
pub fn block_ip(&mut self, ip: IpAddr) {
let network = IpNetwork::from(ip);
if !self.blocked.contains(&network) {
self.blocked.push(network);
tracing::info!("Blocked IP: {}", ip);
}
}
/// Remove IP from block list
pub fn unblock_ip(&mut self, ip: IpAddr) {
let network = IpNetwork::from(ip);
self.blocked.retain(|n| n != &network);
tracing::info!("Unblocked IP: {}", ip);
}
/// Reload from config
pub fn reload(&mut self, config: &SecurityConfig) -> Result<()> {
*self = Self::from_config(config)?;
Ok(())
}
}Configuration
security:
# Whitelist mode: only allow these IPs
allowed_ips:
- 10.0.0.0/8
- 192.168.0.0/16
- 172.16.0.0/12
# Blacklist: always deny these IPs
blocked_ips:
- 192.168.100.0/24
- 10.10.10.10/32Files to Create/Modify
| File | Action |
|---|---|
src/server/security/access.rs |
Create - IP access control |
src/server/security/mod.rs |
Modify - Add access module |
src/server/mod.rs |
Modify - Integrate at connection level |
Testing Requirements
- Unit test: CIDR matching
- Unit test: Whitelist mode (default deny)
- Unit test: Blacklist takes priority
- Unit test: Single IP blocking
- Integration test: Connection rejection
Acceptance Criteria
- IpAccessControl implementation
- CIDR range support
- Whitelist mode (allowed_ips)
- Blacklist mode (blocked_ips)
- Blacklist takes priority over whitelist
- Connection-level rejection
- Runtime updates support
- Tests passing
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
priority:mediumMedium priority issueMedium priority issuestatus:doneCompletedCompletedtype:enhancementNew feature or requestNew feature or requesttype:securitySecurity vulnerability or fixSecurity vulnerability or fix