SSH Anywhere

A high-performance SSH library with unified API for direct and jump host connections.
✨ Features
- 🔀 Unified API: Single
SSHClient
class for both direct and jump host connections
- ⚡ Control Master Support: Automatic SSH multiplexing for improved performance
- 🔗 Jump Host Chaining: Support for multiple jump hosts in sequence
- 🔐 Authentication Methods: Both password and key-based authentication
- 💻 Interactive Sessions: Full PTY support for interactive SSH sessions
- 📋 Command Execution: Clean command output with automatic pagination handling
- 🧹 Resource Management: Automatic cleanup of SSH control sockets
- 🏗️ Sequential Commands: Execute multiple commands while preserving session state
🚀 Quick Start
Installation
From PyPI (Recommended)
pip install ssh-anywhere
From Source
git clone https://github.com/wbx13/ssh.git
cd ssh
pip install -e .
For Development
git clone https://github.com/wbx13/ssh.git
cd ssh
poetry install
Basic Usage
Direct Connection
from ssh import SSHClient
client = SSHClient(
hostname="example.com",
username="user",
private_key_path="~/.ssh/id_rsa"
)
result = client.exec_cmd("hostname")
print(result.stdout)
client.interact()
Jump Host Connection
from ssh import SSHClient
jump_host = SSHClient(
hostname="jump.example.com",
username="jump_user",
private_key_path="~/.ssh/id_rsa"
)
target = SSHClient(
hostname="10.0.0.100",
username="target_user",
password="password",
jump_host=jump_host
)
result = target.exec_cmd("get system status")
print(result.stdout)
Multi-hop Chaining
jump1 = SSHClient(hostname="jump1.example.com", username="user")
jump2 = SSHClient(hostname="jump2.example.com", username="user", jump_host=jump1)
target = SSHClient(hostname="target.example.com", username="user", jump_host=jump2)
result = target.exec_cmd("hostname")
Sequential Commands with State Preservation
For configuration workflows that require maintaining session state:
from ssh import SSHClient
client = SSHClient(
hostname="firewall.example.com",
username="admin",
password="password"
)
commands = [
'config system interface',
'show',
'edit port1',
'set description "Updated via SSH"',
'show',
'end'
]
results = client.exec_sequential_commands(commands, timeout=60)
for i, (cmd, result) in enumerate(zip(commands, results)):
print(f"Command {i+1}: {cmd}")
print(f"Success: {result.success}")
print(f"Output: {result.stdout[:100]}...")
📚 API Reference
SSHClient
The main class for SSH connections.
Constructor Parameters
hostname | str | Required | Target hostname or IP address |
username | str | Current user | SSH username |
port | int | 22 | SSH port |
password | str | None | Password for authentication |
private_key_path | str | None | Path to private key file |
jump_host | SSHClient | None | Another SSHClient instance to use as jump host |
ssh_options | dict | None | Additional SSH options |
establish_master | bool | True | Whether to establish control master on init |
Methods
exec_cmd(command, timeout=30) | Execute a command and return CommandResult |
exec_sequential_commands(commands, timeout=60, command_delay=0.5) | Execute multiple commands sequentially while maintaining session state |
interact(escape_char='~') | Start an interactive SSH session |
CommandResult
Result object returned by exec_cmd()
.
Properties
returncode | int | Exit code of the command |
stdout | str | Standard output as string |
stderr | str | Standard error as string |
success | bool | Boolean indicating if command succeeded (returncode == 0) |
Utility Functions
cleanup_ssh_sockets() | Clean up all SSH control sockets |
🎯 Examples
Run the Demo Script
ssh-demo
python examples/unified_demo.py
Environment Configuration
Create a .env
file for the demo:
JUMP_HOST=jump.example.com
JUMP_USERNAME=jump_user
JUMP_KEY_PATH=~/.ssh/jump_key
TARGET_HOST=target.example.com
TARGET_USERNAME=target_user
TARGET_PASSWORD=target_password
🛠️ Development
Setup Development Environment
git clone https://github.com/wbx13/ssh.git
cd ssh
poetry install
poetry run pre-commit install
poetry run pytest
poetry run black src/ tests/ examples/
poetry run isort src/ tests/ examples/
poetry run flake8 src/ tests/ examples/
Running Tests
poetry run pytest
poetry run pytest --cov=src --cov-report=html
poetry run pytest tests/test_client.py -v
📋 Requirements
System Requirements
- Python 3.8+
- SSH client (
ssh
command) - Usually pre-installed on Unix systems
- expect command - For password authentication through jump hosts
- Ubuntu/Debian:
sudo apt install expect
- macOS:
brew install expect
(or use built-in version)
- RHEL/CentOS:
sudo yum install expect
Python Dependencies
All Python dependencies are managed through Poetry and specified in pyproject.toml
.
🤝 Contributing
We welcome contributions! Please see our Contributing Guide for details.
Quick Contribution Checklist
🔒 Security
Please see our Security Policy for information on reporting security vulnerabilities.
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- Built on top of OpenSSH for reliable SSH connectivity
- Inspired by the need for a unified SSH client interface
- Thanks to all contributors and users of the library
📈 Changelog
See CHANGELOG.md for a detailed list of changes and version history.