tumult-ssh — SSH Remote Execution
Remote command execution and file transfer over SSH for the Tumult chaos engineering platform.
Features
- SSH connection manager with connection pooling
- Remote command execution with stdout/stderr capture and exit code
- File upload via SSH channel (no SFTP subsystem required)
- Key-based authentication (ed25519, RSA, ECDSA)
- SSH agent authentication (ssh-agent / pageant)
- Configurable timeouts for both connection and command execution
Configuration
Activities can target remote hosts via the ExecutionTarget::Ssh variant:
method[1]:
- name: stress-cpu-remote
activity_type: action
provider:
type: process
path: stress-ng
arguments[3]: --cpu, 4, --timeout, 30s
execution_target:
type: ssh
host: db-primary.example.com
port: 22
user: ops
key_path: /home/ops/.ssh/id_ed25519
Authentication
Key-based
let config = SshConfig::with_key(
"db-primary.example.com",
"ops",
PathBuf::from("/home/ops/.ssh/id_ed25519"),
);
Supported key types: Ed25519, RSA (2048+), ECDSA (P-256, P-384).
SSH Agent
let config = SshConfig::with_agent("db-primary.example.com", "ops");
Uses the SSH_AUTH_SOCK environment variable to connect to a running SSH agent.
API
Connect
let session = SshSession::connect(config).await?;
Execute Command
let result = session.execute("uname -a").await?;
println!("stdout: {}", result.stdout);
println!("exit code: {}", result.exit_code);
assert!(result.success());
Upload File
session.upload_file(
Path::new("scripts/stress.sh"),
"/tmp/stress.sh",
).await?;
Close
session.close().await?;
Timeouts
let config = SshConfig::with_key("host", "user", key_path)
.connect_timeout(Duration::from_secs(30)) // Connection timeout
.command_timeout(Duration::from_secs(60)); // Per-command timeout
Error Handling
All SSH operations return Result<_, SshError> with these variants:
| Error | Cause |
|---|---|
ConnectionFailed | TCP connection or SSH handshake failed |
AuthenticationFailed | Key rejected or agent not available |
KeyNotFound | Private key file does not exist |
KeyParseError | Private key file is malformed |
ExecutionFailed | Command could not be started |
ChannelError | SSH channel operation failed |
UploadFailed | File transfer failed |
Timeout | Connection or command timed out |
Security Notes
Host Key Verification
Host key verification is currently accept-all (see ADR-006). This is acceptable for trusted internal networks and ephemeral cloud instances, but NOT for production use over untrusted networks. Known_hosts verification is planned for a future release.
RSA Key Vulnerability (RUSTSEC-2023-0071)
The russh 0.58 dependency tree includes rsa 0.10.0-rc.12, which has a known timing side-channel vulnerability (Marvin Attack, CVSS 5.9 medium). This affects RSA key authentication only.
Mitigation: Use Ed25519 keys (recommended) or ECDSA keys instead of RSA keys. Ed25519 is not affected by this vulnerability and is the preferred key type for modern SSH.
# Generate an Ed25519 key (recommended)
ssh-keygen -t ed25519 -C "tumult-chaos" -f ~/.ssh/tumult_ed25519
# Use it in your experiment
execution_target:
type: ssh
host: target-host
user: ops
key_path: ~/.ssh/tumult_ed25519
No upstream fix is currently available for the RSA crate. This advisory will be resolved when russh updates its dependency.
Implementation Notes
- Uses
russh0.58 — pure Rust, no C dependencies - Async-native with tokio
- File upload uses
cat > path && chmod 755via SSH channel — no SFTP subsystem needed - Authentication is bounded by
connect_timeoutto prevent stalls - Upload operations respect
command_timeout