Skip to content

Commit 1ccdea7

Browse files
authored
feat: add password authentication and SSH key passphrase support (#6)
* feat: add password authentication and SSH key passphrase support - Add --password flag for password-based authentication - Automatically detect and prompt for passphrases on encrypted SSH keys - Support passphrase entry for both explicit and default key paths - Check multiple default key types (ed25519, rsa, ecdsa, dsa) - Update all commands (exec, upload, download, ping) to support new auth methods - Add secure password/passphrase prompting using rpassword crate * update: add password auth and passphrase support to documentation - Update man page with password flag and passphrase information - Add authentication section to README with examples - Improve help text for identity flag to mention passphrase support - Keep version number unchanged at 0.3.0 * fix: use current user instead of root as default username - Replace hardcoded 'root' fallback with current user detection - Try USER, USERNAME, LOGNAME environment variables first - Use whoami crate to get system username as last resort - Add test to verify current user is used correctly - Ensures non-root users don't accidentally connect as root
1 parent d2c8341 commit 1ccdea7

10 files changed

Lines changed: 316 additions & 42 deletions

File tree

Cargo.lock

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ directories = "6"
2929
dirs = "6.0"
3030
chrono = "0.4"
3131
glob = "0.3"
32+
whoami = "1.5"
3233

3334
[dev-dependencies]
3435
tempfile = "3"

README.md

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ A high-performance parallel SSH command execution tool for cluster management, b
77
- **Parallel Execution**: Execute commands across multiple nodes simultaneously
88
- **Cluster Management**: Define and manage node clusters via configuration files
99
- **Progress Tracking**: Real-time progress indicators for each node
10-
- **Flexible Authentication**: Support for SSH keys and SSH agent
10+
- **Flexible Authentication**: Support for SSH keys, SSH agent, password authentication, and encrypted key passphrases
1111
- **Host Key Verification**: Secure host key checking with known_hosts support
1212
- **Cross-Platform**: Works on Linux and macOS
1313
- **Output Management**: Save command outputs to files per node with detailed logging
@@ -35,6 +35,12 @@ bssh -c staging -i ~/.ssh/custom_key "systemctl status nginx"
3535
# Use SSH agent for authentication
3636
bssh --use-agent -c production "systemctl status nginx"
3737

38+
# Use password authentication (will prompt for password)
39+
bssh --password -H "user@host.com" "uptime"
40+
41+
# Use encrypted SSH key (will prompt for passphrase)
42+
bssh -i ~/.ssh/encrypted_key -c production "df -h"
43+
3844
# Limit parallel connections
3945
bssh -c production --parallel 5 "apt update"
4046
```
@@ -49,6 +55,38 @@ bssh -c production ping
4955
bssh list
5056
```
5157

58+
## Authentication
59+
60+
bssh supports multiple authentication methods:
61+
62+
### SSH Key Authentication
63+
- **Default keys**: Automatically tries `~/.ssh/id_ed25519`, `~/.ssh/id_rsa`, `~/.ssh/id_ecdsa`, `~/.ssh/id_dsa`
64+
- **Custom key**: Use `-i` flag to specify a key file
65+
- **Encrypted keys**: Automatically detects and prompts for passphrase
66+
67+
### SSH Agent
68+
- **Auto-detection**: Automatically uses SSH agent if `SSH_AUTH_SOCK` is set
69+
- **Explicit**: Use `-A` flag to force SSH agent authentication
70+
71+
### Password Authentication
72+
- Use `-P` flag to enable password authentication
73+
- Password is prompted securely without echo
74+
75+
### Examples
76+
```bash
77+
# Use default SSH key (auto-detect)
78+
bssh -H "user@host" "uptime"
79+
80+
# Use specific SSH key (prompts for passphrase if encrypted)
81+
bssh -i ~/.ssh/custom_key -c production "df -h"
82+
83+
# Use SSH agent
84+
bssh -A -c production "systemctl status"
85+
86+
# Use password authentication
87+
bssh -P -H "user@host" "ls -la"
88+
```
89+
5290
## Configuration
5391

5492
### Configuration Priority Order

docs/man/bssh.1

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ bssh \- Backend.AI SSH - Parallel command execution across cluster nodes
1414
is a high-performance parallel SSH command execution tool for cluster management, built with Rust.
1515
It enables efficient execution of commands across multiple nodes simultaneously with real-time output streaming.
1616
The tool provides secure file transfer capabilities using SFTP protocol for both uploading and downloading files
17-
to/from multiple remote hosts in parallel. It automatically detects Backend.AI multi-node session environments
18-
and supports various configuration methods.
17+
to/from multiple remote hosts in parallel. It supports multiple authentication methods including SSH keys (with
18+
passphrase support for encrypted keys), SSH agent, and password authentication. It automatically detects Backend.AI
19+
multi-node session environments and supports various configuration methods.
1920

2021
.SH OPTIONS
2122
.TP
@@ -37,7 +38,8 @@ Default username for SSH connections
3738

3839
.TP
3940
.BR \-i ", " \-\-identity " " \fIIDENTITY\fR
40-
SSH private key file path
41+
SSH private key file path. If the key is encrypted, bssh will
42+
automatically prompt for the passphrase.
4143

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

51+
.TP
52+
.BR \-P ", " \-\-password
53+
Use password authentication. When this option is specified, bssh will
54+
prompt for the password securely without echoing it to the terminal.
55+
This is useful for systems that don't have SSH keys configured.
56+
4957
.TP
5058
.BR \-p ", " \-\-parallel " " \fIPARALLEL\fR
5159
Maximum parallel connections (default: 10)
@@ -205,6 +213,20 @@ Use custom SSH key:
205213
Use SSH agent for authentication:
206214
.B bssh -A -c production "systemctl status"
207215

216+
.TP
217+
Use password authentication:
218+
.B bssh -P -H "user@host.com" "uptime"
219+
.RS
220+
Prompts for password interactively
221+
.RE
222+
223+
.TP
224+
Use encrypted SSH key:
225+
.B bssh -i ~/.ssh/encrypted_key -c production "df -h"
226+
.RS
227+
Automatically detects encrypted key and prompts for passphrase
228+
.RE
229+
208230
.TP
209231
Save output to files:
210232
.B bssh --output-dir ./results -c production "ps aux"
@@ -299,8 +321,9 @@ User configuration directory location
299321
SSH known hosts file for host key verification
300322

301323
.TP
302-
.I ~/.ssh/id_rsa
303-
Default SSH private key
324+
.I ~/.ssh/id_ed25519, ~/.ssh/id_rsa, ~/.ssh/id_ecdsa, ~/.ssh/id_dsa
325+
Default SSH private keys (checked in order of preference). If a key is
326+
encrypted, bssh will prompt for the passphrase.
304327

305328
.TP
306329
.I $SSH_AUTH_SOCK

src/cli.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@ pub struct Cli {
4747
#[arg(short = 'u', long, help = "Default username for SSH connections")]
4848
pub user: Option<String>,
4949

50-
#[arg(short = 'i', long, help = "SSH private key file path")]
50+
#[arg(
51+
short = 'i',
52+
long,
53+
help = "SSH private key file path (prompts for passphrase if encrypted)"
54+
)]
5155
pub identity: Option<PathBuf>,
5256

5357
#[arg(
@@ -57,6 +61,13 @@ pub struct Cli {
5761
)]
5862
pub use_agent: bool,
5963

64+
#[arg(
65+
short = 'P',
66+
long,
67+
help = "Use password authentication (will prompt for password)"
68+
)]
69+
pub password: bool,
70+
6071
#[arg(
6172
short = 'p',
6273
long,

src/config.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,18 @@ impl Config {
103103
// Get current user as default
104104
let default_user = env::var("USER")
105105
.or_else(|_| env::var("USERNAME"))
106-
.unwrap_or_else(|_| "root".to_string());
106+
.or_else(|_| env::var("LOGNAME"))
107+
.unwrap_or_else(|_| {
108+
// Try to get current user from system
109+
#[cfg(unix)]
110+
{
111+
whoami::username()
112+
}
113+
#[cfg(not(unix))]
114+
{
115+
"user".to_string()
116+
}
117+
});
107118

108119
// Backend.AI multi-node clusters use port 2200 by default
109120
nodes.push(NodeConfig::Simple(format!("{default_user}@{host}:2200")));
@@ -215,7 +226,20 @@ impl Config {
215226
.or_else(|| cluster.defaults.user.as_ref().map(|u| expand_env_vars(u)))
216227
.or_else(|| self.defaults.user.as_ref().map(|u| expand_env_vars(u)))
217228
.unwrap_or_else(|| {
218-
std::env::var("USER").unwrap_or_else(|_| "root".to_string())
229+
std::env::var("USER")
230+
.or_else(|_| std::env::var("USERNAME"))
231+
.or_else(|_| std::env::var("LOGNAME"))
232+
.unwrap_or_else(|_| {
233+
// Try to get current user from system
234+
#[cfg(unix)]
235+
{
236+
whoami::username()
237+
}
238+
#[cfg(not(unix))]
239+
{
240+
"user".to_string()
241+
}
242+
})
219243
});
220244

221245
let port = port

0 commit comments

Comments
 (0)