bssh (Backend.AI SSH / Broadcast SSH) is a high-performance parallel SSH command execution tool with SSH-compatible interface. This document provides a high-level architecture overview. For detailed component documentation, see docs/architecture/.
- Parallel command execution across multiple nodes
- SSH-compatible command-line interface (drop-in replacement)
- SSH port forwarding (-L, -R, -D/SOCKS proxy)
- SSH jump host support (-J)
- SSH configuration file parsing (-F)
- Interactive PTY sessions with single/multiplex modes
- SFTP file transfers (upload/download)
- Backend.AI cluster auto-detection
- pdsh compatibility mode
┌─────────────────────────────────────────────────────────┐
│ CLI Interface │
│ (main.rs) │
│ (-L, -R, -D, -J, -F, -t/T, SSH-compatible) │
└────────────────────────────┬────────────────────────────┘
│
┌─────────────┬──────────────┼──────────────┬─────────────┐
▼ ▼ ▼ ▼ ▼
┌──────────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌──────────┐
│ Commands │ │ Config │ │ Utils │ │Forwarding │ │ Jump │
│ Module │ │ Manager │ │ Module │ │ Manager │ │ Host │
│ (commands/*) │ │(config.rs)│ │ (utils/*) │ │(forward/*)│ │ (jump/*) │
└──────┬───────┘ └─────┬─────┘ └───────────┘ └───┬───────┘ └───┬──────┘
│ │ │ │
│ ▼ │ │
│ ┌──────────────┐ │ │
│ │ SSH Config │ │ │
│ │ Parser │ │ │
│ │(ssh_config/*)│ │ │
│ └──────────────┘ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────────┐
│ Executor │◄────────────────────────┤ Node │ │ Port Forwarders │
│ (Parallel) │ │ Parser │ │ (L/R/D modes) │
│(executor.rs) │ │ (node.rs) │ │ + Tunnels │
└──────┬───────┘ └──────────────┘ └────────┬─────────┘
│ │
├──────────┬────────────┬───────────────────────────────────┘
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ SSH │ │ SSH │ │ SSH │
│ Client │ │ Client │ │ Client │
│ (russh) │ │ (russh) │ │ (russh) │
└──────────┘ └──────────┘ └──────────┘
Documentation: docs/architecture/cli-interface.md
The CLI system provides an SSH-compatible command-line interface with multiple operation modes:
- Native bssh mode: Cluster-based parallel execution
- SSH compatibility mode: Drop-in SSH replacement for single-host operations
- pdsh compatibility mode: Compatible with pdsh command-line syntax
Key features:
- clap v4 with derive macros for type-safe argument parsing
- Backend.AI cluster auto-detection
- Hostlist expression support (pdsh-compatible)
- Mode detection based on binary name, environment, or flags
Documentation: docs/architecture/configuration.md
Hierarchical configuration system with multiple sources:
- Backend.AI environment variables (auto-detection)
- Current directory (
./config.yaml) - XDG config directory (
~/.config/bssh/config.yaml) - CLI specified path (via
--configflag)
Features:
- YAML format for human readability
- Environment variable expansion (
${VAR}syntax) - SSH configuration file integration
- Platform-specific paths via XDG Base Directory specification
Documentation: docs/architecture/executor.md
Tokio-based async executor for concurrent command execution:
- Semaphore-based concurrency limiting
- Two-stage signal handling (default) or batch mode
- Fail-fast mode for early termination on errors
- Real-time progress visualization
- Stream mode for live output
Documentation: docs/architecture/ssh-client.md
Built on russh and russh-sftp with custom tokio_client wrapper:
- Connection management with russh
- Multiple authentication methods (agent, key file, password)
- Host key verification (known_hosts support)
- Command execution with streaming output
- SFTP file transfers (upload/download)
- Connection timeout handling
- Configurable SSH keepalive (ServerAliveInterval, ServerAliveCountMax)
Documentation: docs/architecture/tui.md
Interactive terminal interface for real-time command monitoring:
- Multiple views (JobList, JobDetail, Logs, System)
- Keyboard navigation and command palette
- Progress parsing from command output
- Real-time log streaming
- Clean shutdown handling
Documentation: docs/architecture/interactive-mode.md
PTY-based interactive SSH sessions:
- Single-host mode: Direct PTY connection to one host
- Multiplex mode: Broadcast input to multiple hosts
- Terminal escape sequence handling
- Raw mode terminal management
- Signal propagation (Ctrl+C, window resize)
Documentation: docs/architecture/ssh-config-parser.md
OpenSSH-compatible configuration file parser:
- Include directive support with recursion limits
- Match directive (Host, LocalUser)
- All standard SSH options
- Configuration caching for performance
- Override chain resolution
Documentation: docs/architecture/ssh-jump-hosts.md
ProxyJump (-J) support for bastion hosts:
- Multiple jump host chains
- IPv6 and custom port support
- Authentication through jump hosts
- Integration with all bssh operations
- Automatic tunnel management
Documentation: docs/architecture/ssh-port-forwarding.md
Full port forwarding support:
- Local forwarding (-L): Forward local port to remote
- Remote forwarding (-R): Forward remote port to local
- Dynamic forwarding (-D): SOCKS proxy mode
- Multiple forwarding rules
- Automatic port allocation
Documentation: docs/architecture/exit-code-strategy.md
MPI-compatible exit code handling:
- MainRank (default): Returns main rank's exit code
- RequireAllSuccess: Returns 0 only if all nodes succeed
- MainRankWithFailureCheck: Hybrid mode for detailed diagnostics
- Automatic main rank detection (Backend.AI integration)
- Preserves actual exit codes (SIGSEGV=139, OOM=137, etc.)
Common utilities for code reuse between bssh client and server implementations:
- Validation: Input validation for usernames, hostnames, paths with security checks
- Rate Limiting: Generic token bucket rate limiter for connection/auth throttling
- Authentication Types: Common auth result types and user info structures
- Error Types: Shared error types for validation, auth, connection, and rate limiting
The security and jump::rate_limiter modules re-export from shared for backward compatibility.
Security features for the SSH server (src/server/security/):
-
AuthRateLimiter: Fail2ban-like authentication rate limiting
- Tracks failed authentication attempts per IP address
- Automatic banning after exceeding configurable threshold
- Time-windowed failure counting (failures outside window not counted)
- Configurable ban duration with automatic expiration
- IP whitelist for exempting trusted addresses from banning
- Memory-safe with configurable maximum tracked IPs
- Automatic cleanup of expired records via background task
- Thread-safe async implementation with
Arc<RwLock<>>
-
IpAccessControl: IP-based connection filtering
- Whitelist mode: Only allow connections from specified CIDR ranges
- Blacklist mode: Block connections from specified CIDR ranges
- Blacklist takes priority over whitelist (blocked IPs are always denied)
- Support for both IPv4 and IPv6 addresses and CIDR notation
- Dynamic updates: Add/remove rules at runtime via
SharedIpAccessControl - Early rejection at connection level before handler creation
- Thread-safe with fail-closed behavior on lock contention
- Configuration via
allowed_ipsandblocked_ipsin server config
Policy-based filtering infrastructure for SFTP and SCP file transfer operations (src/server/filter/):
Structure:
mod.rs-TransferFiltertrait,Operationenum,FilterResultenum,NoOpFilterpolicy.rs-FilterPolicyengine,FilterRule,Matchertrait,SharedFilterPolicypath.rs- Path-based matchers:PrefixMatcher,ExactMatcher,ComponentMatcher,ExtensionMatcherpattern.rs- Pattern-based matchers:GlobMatcher,RegexMatcher,CombinedMatcher,NotMatcher
Key Components:
-
Operation: Enum representing file operations
Upload,Download,Delete,RenameCreateDir,ListDir,Stat,SetStatSymlink,ReadLink
-
FilterResult: Actions to take on matched operations
Allow- Permit the operation (default)Deny- Block the operationLog- Allow but log for auditing
-
TransferFilter Trait: Interface for custom filter implementations
check(path, operation, user)- Check single path operationscheck_with_dest(src, dest, operation, user)- Check two-path operations (rename, symlink)is_enabled()- Check if filtering is active
-
FilterPolicy: First-match-wins rule evaluation engine
- Ordered rule evaluation
- Configurable default action
- Enable/disable filtering
- Create from YAML configuration via
from_config()
-
FilterRule: Combines matcher, action, and optional constraints
- Path pattern matcher
- Per-operation restrictions
- Per-user restrictions
- Named rules for debugging
Built-in Matchers:
| Matcher | Purpose | Example |
|---|---|---|
GlobMatcher |
Wildcard patterns | *.key, *.pem |
RegexMatcher |
Full regex support | (?i)\.exe$ |
PrefixMatcher |
Directory tree matching | /etc/ |
ExactMatcher |
Specific file matching | /etc/shadow |
ComponentMatcher |
Path component matching | .git, .ssh |
ExtensionMatcher |
File extension matching | exe, key |
CombinedMatcher |
OR-combine matchers | Multiple patterns |
NotMatcher |
Invert matcher results | Exclude patterns |
Security Features:
normalize_path()function for path traversal prevention- ReDoS protection via regex size limits
- Case-insensitive extension matching
Usage Example:
use bssh::server::filter::{FilterPolicy, FilterResult, Operation};
use bssh::server::filter::pattern::GlobMatcher;
use bssh::server::filter::policy::FilterRule;
use std::path::Path;
// Create policy that blocks *.key files
let policy = FilterPolicy::new()
.with_default(FilterResult::Allow)
.add_rule(FilterRule::new(
Box::new(GlobMatcher::new("*.key").unwrap()),
FilterResult::Deny,
));
// Check if operation is allowed
let result = policy.check(
Path::new("/etc/secret.key"),
Operation::Download,
"alice"
);
assert_eq!(result, FilterResult::Deny);Configuration (YAML):
filter:
enabled: true
default_action: allow
rules:
- name: block-sensitive-keys
pattern: "*.{key,pem}"
action: deny
operations:
- download
- upload
- name: block-hidden-dirs
path_prefix: "/home"
pattern: ".*"
action: deny
users:
- guestComprehensive audit logging infrastructure for the SSH server (src/server/audit/):
Structure:
mod.rs-AuditManagerfor collecting and distributing audit eventsevent.rs-AuditEventtype definitions and builder patternexporter.rs-AuditExportertrait andNullExporterimplementationfile.rs-FileExporterfor JSON Lines output with rotation support
Key Components:
-
AuditEvent: Represents discrete auditable actions with fields for:
- Unique event ID (UUID v4)
- Timestamp (UTC)
- Event type, session ID, username, client IP
- File paths, bytes transferred, operation result
- Protocol and additional details
-
EventType: Categorizes security and operational events:
- Authentication:
AuthSuccess,AuthFailure,AuthRateLimited - Sessions:
SessionStart,SessionEnd - Commands:
CommandExecuted,CommandBlocked - File operations:
FileOpenRead,FileOpenWrite,FileRead,FileWrite,FileClose,FileUploaded,FileDownloaded,FileDeleted,FileRenamed - Directory operations:
DirectoryCreated,DirectoryDeleted,DirectoryListed - Filters:
TransferDenied,TransferAllowed - Security:
IpBlocked,IpUnblocked,SuspiciousActivity
- Authentication:
-
EventResult: Operation outcomes (
Success,Failure,Denied,Error) -
AuditExporter Trait: Interface for audit event destinations
export()- Export single eventexport_batch()- Export multiple events (optimizable)flush()- Ensure pending events are writtenclose()- Clean up resources
-
NullExporter: No-op exporter for testing and disabled audit logging
-
FileExporter: File-based exporter writing events in JSON Lines format
- Append mode to preserve existing data
- Optional log rotation based on file size (
RotateConfig) - Optional gzip compression for rotated files
- Thread-safe using async Mutex
- Async I/O using tokio
- Automatic parent directory creation
- Restrictive file permissions (0o600 on Unix)
-
AuditManager: Central manager with async processing
- Background worker for non-blocking event processing
- Configurable buffering (buffer size, batch size)
- Periodic flush intervals
- Multiple exporter support
- Graceful shutdown with event flush
Configuration:
let config = AuditConfig::new()
.with_enabled(true)
.with_buffer_size(1000)
.with_batch_size(100)
.with_flush_interval(5);File Exporter Usage:
use bssh::server::audit::file::{FileExporter, RotateConfig};
use std::path::Path;
// Simple file exporter
let exporter = FileExporter::new(Path::new("/var/log/audit.log"))?;
// With rotation (50 MB, 10 backups, gzip compression)
let rotate_config = RotateConfig::new()
.with_max_size(50 * 1024 * 1024)
.with_max_backups(10)
.with_compress(true);
let exporter = FileExporter::new(Path::new("/var/log/audit.log"))?
.with_rotation(rotate_config);Output Format (JSON Lines - one JSON object per line):
{"id":"uuid","timestamp":"2024-01-15T10:30:00Z","event_type":"file_uploaded","session_id":"sess-001","user":"admin","client_ip":"192.168.1.100","path":"/data/report.pdf","bytes":1048576,"result":"success","protocol":"sftp"}-
OtelExporter: OpenTelemetry exporter for distributed tracing and observability
- OTLP/gRPC protocol support using tonic
- Event to LogRecord mapping with proper attribute conversion
- Severity level mapping based on event types and results
- Resource attributes including service.name and service.version
- Graceful shutdown and flush methods
- TLS support for secure audit data transmission
-
LogstashExporter: Logstash exporter for ELK stack integration
- TCP connection with JSON Lines protocol (newline-delimited JSON)
- Optional TLS encryption for secure transmission
- Automatic reconnection on connection failure
- Batch support for efficient event transmission
- Connection timeout handling (default: 10 seconds)
- Configurable host and port
OtelExporter Usage:
use bssh::server::audit::otel::OtelExporter;
use bssh::server::audit::exporter::AuditExporter;
use bssh::server::audit::event::{AuditEvent, EventType};
// Create exporter with OTLP endpoint
let exporter = OtelExporter::new("http://localhost:4317")?;
// Export an audit event
let event = AuditEvent::new(
EventType::AuthSuccess,
"alice".to_string(),
"session-123".to_string(),
);
exporter.export(event).await?;
// Graceful shutdown
exporter.close().await?;LogstashExporter Usage:
use bssh::server::audit::logstash::LogstashExporter;
use bssh::server::audit::exporter::AuditExporter;
use bssh::server::audit::event::{AuditEvent, EventType};
// Create exporter (unencrypted by default)
let exporter = LogstashExporter::new("logstash.example.com", 5044)?
.with_tls(true); // Enable TLS for production
// Export an audit event
let event = AuditEvent::new(
EventType::AuthSuccess,
"alice".to_string(),
"session-123".to_string(),
);
exporter.export(event).await?;
// Graceful shutdown
exporter.close().await?;Binary: bssh-server
The bssh-server binary provides a command-line interface for managing and operating the SSH server:
Subcommands:
- run - Start the SSH server (default when no subcommand specified)
- gen-config - Generate a configuration file template with secure defaults
- hash-password - Hash passwords for configuration using Argon2id (recommended)
- check-config - Validate configuration files and display settings
- gen-host-key - Generate SSH host keys (Ed25519 or RSA)
- version - Show version and build information
Global Options:
-c, --config <FILE>- Configuration file path-b, --bind-address <ADDR>- Override bind address-p, --port <PORT>- Override listen port-k, --host-key <FILE>- Host key file(s) (can be repeated)-v, --verbose- Verbosity level (repeatable: -v, -vv, -vvv)-D, --foreground- Run in foreground (don't daemonize)--pid-file <FILE>- PID file path
Usage Examples:
# Generate configuration template
bssh-server gen-config -o /etc/bssh/server.yaml
# Generate Ed25519 host key (recommended)
bssh-server gen-host-key -t ed25519 -o /etc/bssh/ssh_host_ed25519_key
# Generate RSA host key (for compatibility)
bssh-server gen-host-key -t rsa -o /etc/bssh/ssh_host_rsa_key --bits 4096
# Hash a password for configuration
bssh-server hash-password
# Validate configuration
bssh-server check-config -c /etc/bssh/server.yaml
# Start server with configuration file
bssh-server -c /etc/bssh/server.yaml
# Start server with CLI overrides
bssh-server -c /etc/bssh/server.yaml -p 2222 -b 0.0.0.0 -k /path/to/keyDocumentation: docs/architecture/server-configuration.md
SSH server implementation using the russh library for accepting incoming connections:
Structure (src/server/):
mod.rs-BsshServerstruct andrussh::server::Servertrait implementationconfig/mod.rs- Module exports and backward compatibility layerconfig/types.rs- Comprehensive configuration types with serdeconfig/loader.rs- Config loader with validation and environment overrideshandler.rs-SshHandlerimplementingrussh::server::Handlertraitsession.rs- Session state management (SessionManager,SessionInfo,ChannelState)exec.rs- Command execution for SSH exec requestssftp.rs- SFTP subsystem handler with path traversal preventionscp.rs- SCP protocol handler with sink/source modesauth/- Authentication provider infrastructureaudit/- Audit logging infrastructure (event types, exporters, manager)
Key Components:
-
BsshServer: Main server struct managing the SSH server lifecycle
- Accepts connections on configured address
- Loads host keys from OpenSSH format files
- Configures russh with authentication settings
- Creates shared rate limiter for authentication attempts
-
Server Configuration System: Dual configuration system for flexibility
- Builder API (
ServerConfig): Programmatic configuration for embedded use - File-Based (
ServerFileConfig): YAML configuration with environment overrides - Configuration precedence: CLI > Environment > File > Defaults
- Configuration validation at startup (host keys, CIDR ranges, paths)
- Support for BSSH_* environment variable overrides
- Builder API (
-
ServerConfig: Configuration options with builder pattern
- Host key paths and listen address
- Connection limits and timeouts
- Authentication method toggles (password, publickey, keyboard-interactive)
- Public key authentication configuration (authorized_keys location)
- Command execution configuration (shell, timeout, allowed/blocked commands)
-
ServerFileConfig: Comprehensive YAML file configuration
- Server settings (bind address, port, host keys, keepalive)
- Authentication (public key, password with inline or file-based users)
- Shell configuration (default shell, environment, command timeout)
- SFTP/SCP enablement with optional chroot
- File transfer filtering rules
- Audit logging (file, OpenTelemetry, Logstash exporters)
- Security settings (auth attempts, bans, session limits, IP allowlist/blocklist)
-
SshHandler: Per-connection handler for SSH protocol events
- Public key authentication via AuthProvider trait
- Rate limiting for authentication attempts (token bucket)
- Auth rate limiting with ban support (fail2ban-like)
- Channel operations (open, close, EOF, data)
- PTY, exec, shell, and subsystem request handling
- Command execution with stdout/stderr streaming
-
PTY Module (
src/server/pty.rs): Pseudo-terminal management for interactive sessions- PTY master/slave pair creation using POSIX APIs via nix crate
- Window size management with TIOCSWINSZ ioctl
- Async I/O for PTY master file descriptor using tokio's AsyncFd
- Configuration management (terminal type, dimensions, pixel sizes)
- Implements
AsyncReadandAsyncWritefor PTY I/O
-
Shell Session Module (
src/server/shell.rs): Interactive shell session handler- Shell process spawning with login shell configuration (-l flag)
- Terminal environment setup (TERM, HOME, USER, SHELL, PATH)
- Bidirectional I/O forwarding between SSH channel and PTY master
- Window resize event handling forwarded to PTY
- Proper session cleanup on disconnect (SIGHUP to shell, process termination)
- Controlling terminal setup via TIOCSCTTY ioctl
-
CommandExecutor: Executes commands requested by SSH clients
- Shell-based command execution with
-cflag - Environment variable configuration (HOME, USER, SHELL, PATH)
- Stdout/stderr streaming to SSH channel
- Command timeout with graceful process termination
- Command allow/block list validation for security
- Exit code propagation to client
- Shell-based command execution with
-
SessionManager: Tracks active sessions with configurable capacity
- Session creation and cleanup
- Idle session management
- Authentication state tracking
-
SftpHandler: SFTP subsystem handler (
src/server/sftp.rs)- Implements
russh_sftp::server::Handlertrait for file transfer operations - Path traversal prevention with chroot-like isolation
- File operations: open, read, write, close
- Directory operations: opendir, readdir, mkdir, rmdir
- Attribute operations: stat, lstat, fstat, setstat, fsetstat
- Path operations: realpath, rename, remove, readlink, symlink
- Symlink validation ensures targets remain within root directory
- Handle limit enforcement to prevent resource exhaustion
- Read size capping to prevent memory exhaustion
- Implements
-
ScpHandler: SCP protocol handler (
src/server/scp.rs)- Implements SCP server protocol for file transfers via the
scpcommand - Sink mode (
-tflag): receives files from client (upload) - Source mode (
-fflag): sends files to client (download) - Recursive transfer support (
-rflag) for directories - Time preservation (
-pflag) for file modification times - Security features:
- Path traversal prevention with normalized path resolution
- Symlink escape prevention via canonicalization
- Filename validation (rejects
/,..,.) - File size limit (10 GB maximum)
- Mode permission masking (strips setuid/setgid/sticky bits)
- Line length limits to prevent DoS via buffer exhaustion
- Automatic SCP command detection in exec_request handler
- Configurable via
scp_enabledsetting
- Implements SCP server protocol for file transfers via the
The authentication subsystem (src/server/auth/) provides extensible authentication for the SSH server:
Structure:
mod.rs- Module exports and re-exportsprovider.rs-AuthProvidertrait definitionpublickey.rs-PublicKeyVerifierimplementationpassword.rs-PasswordVerifierimplementation with Argon2id hashingcomposite.rs-CompositeAuthProvidercombining multiple auth methods
AuthProvider Trait:
The AuthProvider trait defines the interface for all authentication backends:
#[async_trait]
pub trait AuthProvider: Send + Sync {
async fn verify_publickey(&self, username: &str, key: &PublicKey) -> Result<AuthResult>;
async fn verify_password(&self, username: &str, password: &str) -> Result<AuthResult>;
async fn get_user_info(&self, username: &str) -> Result<Option<UserInfo>>;
async fn user_exists(&self, username: &str) -> Result<bool>;
}PublicKeyVerifier:
Implements public key authentication by parsing OpenSSH authorized_keys files:
-
Key file location modes:
- Directory mode:
{dir}/{username}/authorized_keys - Pattern mode:
/home/{user}/.ssh/authorized_keys
- Directory mode:
-
Supported key types:
- ssh-ed25519, ssh-ed448
- ssh-rsa, ssh-dss
- ecdsa-sha2-nistp256/384/521
- Security keys (sk-ssh-ed25519, sk-ecdsa-sha2-nistp256)
-
Key options parsing:
command="..."- Force specific commandfrom="..."- Restrict source addressesno-pty,no-port-forwarding,no-agent-forwarding,no-X11-forwardingenvironment="..."- Set environment variables
PasswordVerifier:
Implements password authentication with secure password hashing:
-
Argon2id hashing: Uses the OWASP-recommended password hashing algorithm
- Memory cost: 19 MiB
- Time cost: 2 iterations
- Parallelism: 1
-
User configuration:
- External YAML file with user definitions
- Inline users in server configuration
- User attributes: name, password_hash, shell, home, env
-
Security features:
- Timing attack mitigation with constant-time verification
- Minimum verification time (100ms) regardless of user existence
- Dummy hash verification for non-existent users
- Secure memory cleanup using
zeroizecrate - User enumeration protection
-
Hash compatibility:
- Argon2id (recommended, generated by
hash-passwordcommand) - bcrypt (supported for backward compatibility)
- Argon2id (recommended, generated by
CompositeAuthProvider:
Combines multiple authentication methods into a single provider:
- Delegates to
PublicKeyVerifierfor public key auth - Delegates to
PasswordVerifierfor password auth - Prioritizes password verifier for user info (more detailed)
- Supports hot-reloading of password users via
reload_password_users()
Security Features:
- Username validation: Prevents path traversal attacks (e.g.,
../etc/passwd) - File permission checks (Unix): Rejects world/group-writable files and symlinks
- Symlink protection: Uses
symlink_metadata()to detect and reject symlinks - Parent directory validation: Checks parent directory permissions
- Rate limiting: Token bucket rate limiter for authentication attempts
- Timing attack mitigation: Constant-time behavior in password verification and
user_exists()check - Secure memory handling: Password strings cleared from memory after use via
zeroize - Comprehensive logging: All authentication attempts are logged
User Input → CLI Parser → Mode Detection → Node Resolution
↓
Configuration Loading
↓
SSH Config Parsing
↓
Jump Host Chain Creation
↓
Parallel Executor Setup
↓
┌────────────────────┴─────────────────┐
▼ ▼
Connection Pool Task Spawning
↓ ↓
Per-Node Execution Semaphore Control
↓ ↓
Command/Transfer Result Collection
↓ ↓
Output Streaming Exit Code Strategy
└────────────────────┬─────────────────┘
▼
User Output
- Connection errors: Retry with exponential backoff
- Authentication failures: Immediate failure with clear diagnostics
- Command execution errors: Captured with exit codes
- Timeout handling: Configurable per-connection and per-command
- Signal handling: Clean shutdown on Ctrl+C with two-stage confirmation
- SSH agent authentication (auto-detection)
- Private key files with passphrase support
- Password authentication (discouraged in production)
- Public key authentication preferred
- known_hosts file verification
- Three modes: Yes (strict), No (insecure), AcceptNew (recommended)
- Per-host configuration support
- Host key fingerprint display
- No credential logging
- Secure memory handling for passphrases
- Encrypted SSH transport (via russh)
- Connection timeout enforcement
- Jump host support for bastion architectures
- Port forwarding for secure tunneling
- SSH config directive support for security policies
- tokio - Async runtime
- russh / russh-sftp - SSH protocol implementation
- clap - CLI argument parsing
- serde / serde_yaml - Configuration serialization
- tracing / tracing-subscriber - Structured logging
- anyhow / thiserror - Error handling
See LICENSE file for licensing information.
- Parallelism: Adjust
--parallelflag (default: 10) - Connection timeout: Use
--connect-timeout(default: 30s) - Command timeout: Use
--timeout(default: 5min) - Keepalive: Configurable via
--server-alive-interval(default: 60s) and--server-alive-count-max(default: 3)- Interval of 0 disables keepalive
- Connection is considered dead after
interval * (count_max + 1)seconds without response - Equivalent to OpenSSH
ServerAliveIntervalandServerAliveCountMaxoptions
See docs/architecture/configuration.md for complete YAML schema and examples.
- 0: Success (all nodes, or main rank succeeded)
- 1: General failure
- 130: Terminated by SIGINT (Ctrl+C)
- Other: Preserved from main rank (SIGSEGV=139, OOM=137, etc.)
See docs/architecture/exit-code-strategy.md for detailed strategy documentation.
For detailed component documentation, see: