Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
272 changes: 270 additions & 2 deletions docs/architecture/server-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,69 @@ scp:
# File transfer filtering
filter:
enabled: false # Default: false
default_action: allow # Default action when no rules match: allow, deny, log

rules:
- pattern: "*.exe"
# Match by glob pattern
- name: "block-exe"
pattern: "*.exe"
action: deny
- path_prefix: "/tmp/"

# Match by path prefix (directory tree)
- name: "log-tmp"
path_prefix: "/tmp/"
action: log

# Match by multiple file extensions
- name: "block-executables"
extensions: ["exe", "bat", "sh", "ps1"]
action: deny

# Match by directory component (anywhere in path)
- name: "block-git"
directory: ".git"
action: deny

# Composite rule with AND logic
- name: "protect-env-outside-home"
composite:
type: and
matchers:
- pattern: "*.env"
- not:
path_prefix: "/home"
action: deny

# Composite rule with OR logic
- name: "block-secrets"
composite:
type: or
matchers:
- pattern: "*.key"
- pattern: "*.pem"
- extensions: ["crt", "p12", "pfx"]
action: deny

# Composite rule with NOT logic (whitelist pattern)
- name: "whitelist-data"
composite:
type: not
matcher:
path_prefix: "/data"
action: deny

# Rule with operation restriction
- name: "readonly-logs"
pattern: "*.log"
action: deny
operations: ["upload", "delete"]

# Rule with user restriction
- name: "admin-only-config"
path_prefix: "/etc"
action: deny
users: ["guest", "readonly"]

# Audit logging configuration
audit:
enabled: false # Default: false
Expand Down Expand Up @@ -647,6 +704,217 @@ scp -rp ./data/ user@bssh-server:/storage/backup/

---

## File Transfer Filtering

The bssh-server provides a comprehensive policy-based system for controlling file transfers in SFTP and SCP operations. The filter system allows administrators to allow, deny, or log file operations based on various criteria.

### Filter Architecture

```
Filter Request Flow:
┌─────────────────┐ ┌──────────────────┐ ┌────────────────┐
│ File Operation │ --> │ Normalize Path │ --> │ Match Rules │
│ (SFTP/SCP) │ │ (prevent bypass) │ │ (in order) │
└─────────────────┘ └──────────────────┘ └────────────────┘
v
┌─────────────────┐ ┌──────────────────┐ ┌────────────────┐
│ First Match │ --> │ Apply Action │ --> │ Allow/Deny/Log │
│ Wins │ │ (or default) │ │ │
└─────────────────┘ └──────────────────┘ └────────────────┘
```

### Matcher Types

The filter system supports multiple matcher types that can be combined for flexible rule definitions:

| Matcher | Config Key | Description | Example |
|---------|------------|-------------|---------|
| **Glob** | `pattern` | Shell-style glob patterns | `*.exe`, `secret*` |
| **Prefix** | `path_prefix` | Directory tree matching | `/etc`, `/home/user` |
| **Extension** | `extensions` | Multiple file extensions | `["exe", "bat", "sh"]` |
| **Directory** | `directory` | Component anywhere in path | `.git`, `.ssh` |
| **Composite** | `composite` | AND/OR/NOT logic | See below |

### Glob Pattern Matching

Glob patterns support standard wildcards:
- `*` - matches any sequence of characters
- `?` - matches any single character
- `[abc]` - matches any character in the set
- `[!abc]` - matches any character not in the set

```yaml
rules:
- pattern: "*.key" # All .key files
- pattern: "secret?.txt" # secret1.txt, secretA.txt, etc.
- pattern: "[0-9]*.log" # Log files starting with a digit
```

### Extension Matching

Multi-extension matching is case-insensitive by default:

```yaml
rules:
- name: "block-executables"
extensions: ["exe", "bat", "sh", "ps1", "cmd"]
action: deny

- name: "block-archives"
extensions: ["zip", "tar", "gz", "rar", "7z"]
action: deny
```

### Composite Rules

Composite rules allow combining multiple matchers with logical operators:

**AND Logic** - All matchers must match:
```yaml
- name: "env-outside-home"
composite:
type: and
matchers:
- pattern: "*.env"
- not:
path_prefix: "/home"
action: deny
```

**OR Logic** - Any matcher must match:
```yaml
- name: "sensitive-files"
composite:
type: or
matchers:
- pattern: "*.key"
- pattern: "*.pem"
- pattern: "*.p12"
action: deny
```

**NOT Logic** - Invert the match (whitelist pattern):
```yaml
- name: "whitelist-data-only"
composite:
type: not
matcher:
path_prefix: "/data"
action: deny # Deny everything NOT in /data
```

### Operation and User Restrictions

Rules can be limited to specific operations or users:

```yaml
rules:
# Prevent deletion of log files
- name: "protect-logs"
pattern: "*.log"
action: deny
operations: ["delete"]

# Block uploads of executables for guest users
- name: "guest-no-executables"
extensions: ["exe", "sh", "bat"]
action: deny
operations: ["upload"]
users: ["guest", "anonymous"]
```

**Available Operations:**
- `upload` - File uploads
- `download` - File downloads
- `delete` - File deletion
- `rename` - File rename/move
- `createdir` - Directory creation
- `listdir` - Directory listing
- `stat` - Reading file attributes
- `setstat` - Modifying file attributes
- `symlink` - Creating symbolic links
- `readlink` - Reading symbolic link targets

### Security Features

**Path Traversal Protection:**
All paths are normalized before matching to prevent bypass attempts:
```
/var/../etc/passwd -> /etc/passwd
/home/user/../../etc -> /etc
```

**First Match Wins:**
Rules are evaluated in order. The first matching rule determines the action. If no rules match, the default action (configurable, defaults to `allow`) is used.

### SizeAwareFilter Trait

For size-based filtering (e.g., blocking large uploads), the `SizeAwareFilter` trait provides:

```rust
use bssh::server::filter::{SizeAwareFilter, FilterResult, Operation};
use bssh::server::filter::path::SizeMatcher;

// Create a size matcher for files over 100MB
let large_file_matcher = SizeMatcher::min(100 * 1024 * 1024);

// Check if the given size matches
assert!(large_file_matcher.matches_size(200 * 1024 * 1024)); // 200MB matches
assert!(!large_file_matcher.matches_size(50 * 1024 * 1024)); // 50MB doesn't match
```

**Note:** Size-based filtering in configuration requires implementation integration with the actual file transfer handlers.

### Complete Filter Configuration Example

```yaml
filter:
enabled: true
default_action: allow

rules:
# Block dangerous executables
- name: "block-executables"
extensions: ["exe", "bat", "sh", "ps1", "cmd", "com"]
action: deny

# Block private keys and certificates
- name: "block-secrets"
composite:
type: or
matchers:
- pattern: "*.key"
- pattern: "*.pem"
- pattern: "*.p12"
- pattern: "id_rsa*"
- pattern: "id_ed25519*"
action: deny

# Block hidden directories
- name: "block-hidden"
directory: ".git"
action: deny

- name: "block-ssh-config"
directory: ".ssh"
action: deny

# Log access to configuration files
- name: "log-config-access"
path_prefix: "/etc"
action: log

# Restrict guests to read-only access in /data
- name: "guest-read-only"
path_prefix: "/data"
operations: ["upload", "delete", "rename", "createdir", "setstat"]
users: ["guest"]
action: deny
```

---

## Session Management

The server implements comprehensive session management with per-user limits, idle timeout detection, and session tracking.
Expand Down
86 changes: 85 additions & 1 deletion src/server/config/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ pub struct FilterConfig {
}

/// A single file transfer filter rule.
#[derive(Debug, Clone, Deserialize, Serialize)]
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct FilterRule {
/// Rule name (for logging and debugging).
///
Expand All @@ -309,6 +309,37 @@ pub struct FilterRule {
#[serde(default)]
pub path_prefix: Option<String>,

/// File extensions to match.
///
/// Example: ["exe", "sh", "bat"] blocks executable files
#[serde(default)]
pub extensions: Option<Vec<String>>,

/// Directory component to match.
///
/// Matches if any path component equals this value.
/// Example: ".git" matches /project/.git/config
#[serde(default)]
pub directory: Option<String>,

/// Minimum file size in bytes.
///
/// Files smaller than this size will not match.
#[serde(default)]
pub min_size: Option<u64>,

/// Maximum file size in bytes.
///
/// Files larger than this size will not match.
#[serde(default)]
pub max_size: Option<u64>,

/// Composite rule configuration.
///
/// Allows combining multiple matchers with AND/OR/NOT logic.
#[serde(default)]
pub composite: Option<CompositeRuleConfig>,

/// Action to take when rule matches.
pub action: FilterAction,

Expand All @@ -326,6 +357,59 @@ pub struct FilterRule {
pub users: Option<Vec<String>>,
}

/// Configuration for composite filter rules.
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct CompositeRuleConfig {
/// Type of composite logic: "and", "or", or "not"
#[serde(rename = "type")]
pub logic_type: CompositeLogicType,

/// List of matchers for AND/OR logic.
#[serde(default)]
pub matchers: Vec<MatcherConfig>,

/// Single matcher for NOT logic.
#[serde(default)]
pub matcher: Option<Box<MatcherConfig>>,
}

/// Type of composite logic.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum CompositeLogicType {
/// All matchers must match
And,
/// Any matcher must match
Or,
/// Invert the matcher result
Not,
}

/// Configuration for a single matcher within a composite rule.
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(default)]
pub struct MatcherConfig {
/// Glob pattern
#[serde(default)]
pub pattern: Option<String>,

/// Path prefix
#[serde(default)]
pub path_prefix: Option<String>,

/// File extensions
#[serde(default)]
pub extensions: Option<Vec<String>>,

/// Directory component
#[serde(default)]
pub directory: Option<String>,

/// Nested NOT matcher
#[serde(default)]
pub not: Option<Box<MatcherConfig>>,
}

/// Action to take when a filter rule matches.
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
#[serde(rename_all = "lowercase")]
Expand Down
Loading
Loading