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
19 changes: 19 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ directories = "6"
dirs = "6.0"
chrono = "0.4"
glob = "0.3"
whoami = "1.5"

[dev-dependencies]
tempfile = "3"
Expand Down
40 changes: 39 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ A high-performance parallel SSH command execution tool for cluster management, b
- **Parallel Execution**: Execute commands across multiple nodes simultaneously
- **Cluster Management**: Define and manage node clusters via configuration files
- **Progress Tracking**: Real-time progress indicators for each node
- **Flexible Authentication**: Support for SSH keys and SSH agent
- **Flexible Authentication**: Support for SSH keys, SSH agent, password authentication, and encrypted key passphrases
- **Host Key Verification**: Secure host key checking with known_hosts support
- **Cross-Platform**: Works on Linux and macOS
- **Output Management**: Save command outputs to files per node with detailed logging
Expand Down Expand Up @@ -35,6 +35,12 @@ bssh -c staging -i ~/.ssh/custom_key "systemctl status nginx"
# Use SSH agent for authentication
bssh --use-agent -c production "systemctl status nginx"

# Use password authentication (will prompt for password)
bssh --password -H "user@host.com" "uptime"

# Use encrypted SSH key (will prompt for passphrase)
bssh -i ~/.ssh/encrypted_key -c production "df -h"

# Limit parallel connections
bssh -c production --parallel 5 "apt update"
```
Expand All @@ -49,6 +55,38 @@ bssh -c production ping
bssh list
```

## Authentication

bssh supports multiple authentication methods:

### SSH Key Authentication
- **Default keys**: Automatically tries `~/.ssh/id_ed25519`, `~/.ssh/id_rsa`, `~/.ssh/id_ecdsa`, `~/.ssh/id_dsa`
- **Custom key**: Use `-i` flag to specify a key file
- **Encrypted keys**: Automatically detects and prompts for passphrase

### SSH Agent
- **Auto-detection**: Automatically uses SSH agent if `SSH_AUTH_SOCK` is set
- **Explicit**: Use `-A` flag to force SSH agent authentication

### Password Authentication
- Use `-P` flag to enable password authentication
- Password is prompted securely without echo

### Examples
```bash
# Use default SSH key (auto-detect)
bssh -H "user@host" "uptime"

# Use specific SSH key (prompts for passphrase if encrypted)
bssh -i ~/.ssh/custom_key -c production "df -h"

# Use SSH agent
bssh -A -c production "systemctl status"

# Use password authentication
bssh -P -H "user@host" "ls -la"
```

## Configuration

### Configuration Priority Order
Expand Down
33 changes: 28 additions & 5 deletions docs/man/bssh.1
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ bssh \- Backend.AI SSH - Parallel command execution across cluster nodes
is a high-performance parallel SSH command execution tool for cluster management, built with Rust.
It enables efficient execution of commands across multiple nodes simultaneously with real-time output streaming.
The tool provides secure file transfer capabilities using SFTP protocol for both uploading and downloading files
to/from multiple remote hosts in parallel. It automatically detects Backend.AI multi-node session environments
and supports various configuration methods.
to/from multiple remote hosts in parallel. It supports multiple authentication methods including SSH keys (with
passphrase support for encrypted keys), SSH agent, and password authentication. It automatically detects Backend.AI
multi-node session environments and supports various configuration methods.

.SH OPTIONS
.TP
Expand All @@ -37,7 +38,8 @@ Default username for SSH connections

.TP
.BR \-i ", " \-\-identity " " \fIIDENTITY\fR
SSH private key file path
SSH private key file path. If the key is encrypted, bssh will
automatically prompt for the passphrase.

.TP
.BR \-A ", " \-\-use\-agent
Expand All @@ -46,6 +48,12 @@ When this option is specified, bssh will attempt to use the SSH agent
for authentication. Falls back to key file authentication if the agent
is not available or authentication fails.

.TP
.BR \-P ", " \-\-password
Use password authentication. When this option is specified, bssh will
prompt for the password securely without echoing it to the terminal.
This is useful for systems that don't have SSH keys configured.

.TP
.BR \-p ", " \-\-parallel " " \fIPARALLEL\fR
Maximum parallel connections (default: 10)
Expand Down Expand Up @@ -205,6 +213,20 @@ Use custom SSH key:
Use SSH agent for authentication:
.B bssh -A -c production "systemctl status"

.TP
Use password authentication:
.B bssh -P -H "user@host.com" "uptime"
.RS
Prompts for password interactively
.RE

.TP
Use encrypted SSH key:
.B bssh -i ~/.ssh/encrypted_key -c production "df -h"
.RS
Automatically detects encrypted key and prompts for passphrase
.RE

.TP
Save output to files:
.B bssh --output-dir ./results -c production "ps aux"
Expand Down Expand Up @@ -299,8 +321,9 @@ User configuration directory location
SSH known hosts file for host key verification

.TP
.I ~/.ssh/id_rsa
Default SSH private key
.I ~/.ssh/id_ed25519, ~/.ssh/id_rsa, ~/.ssh/id_ecdsa, ~/.ssh/id_dsa
Default SSH private keys (checked in order of preference). If a key is
encrypted, bssh will prompt for the passphrase.

.TP
.I $SSH_AUTH_SOCK
Expand Down
13 changes: 12 additions & 1 deletion src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@ pub struct Cli {
#[arg(short = 'u', long, help = "Default username for SSH connections")]
pub user: Option<String>,

#[arg(short = 'i', long, help = "SSH private key file path")]
#[arg(
short = 'i',
long,
help = "SSH private key file path (prompts for passphrase if encrypted)"
)]
pub identity: Option<PathBuf>,

#[arg(
Expand All @@ -57,6 +61,13 @@ pub struct Cli {
)]
pub use_agent: bool,

#[arg(
short = 'P',
long,
help = "Use password authentication (will prompt for password)"
)]
pub password: bool,

#[arg(
short = 'p',
long,
Expand Down
28 changes: 26 additions & 2 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,18 @@ impl Config {
// Get current user as default
let default_user = env::var("USER")
.or_else(|_| env::var("USERNAME"))
.unwrap_or_else(|_| "root".to_string());
.or_else(|_| env::var("LOGNAME"))
.unwrap_or_else(|_| {
// Try to get current user from system
#[cfg(unix)]
{
whoami::username()
}
#[cfg(not(unix))]
{
"user".to_string()
}
});

// Backend.AI multi-node clusters use port 2200 by default
nodes.push(NodeConfig::Simple(format!("{default_user}@{host}:2200")));
Expand Down Expand Up @@ -215,7 +226,20 @@ impl Config {
.or_else(|| cluster.defaults.user.as_ref().map(|u| expand_env_vars(u)))
.or_else(|| self.defaults.user.as_ref().map(|u| expand_env_vars(u)))
.unwrap_or_else(|| {
std::env::var("USER").unwrap_or_else(|_| "root".to_string())
std::env::var("USER")
.or_else(|_| std::env::var("USERNAME"))
.or_else(|_| std::env::var("LOGNAME"))
.unwrap_or_else(|_| {
// Try to get current user from system
#[cfg(unix)]
{
whoami::username()
}
#[cfg(not(unix))]
{
"user".to_string()
}
})
});

let port = port
Expand Down
Loading