SSH Client¶
The SSH client is the primary interface for connecting to SSH servers and executing remote operations. SpindleX provides both a synchronous SSHClient and an asynchronous AsyncSSHClient.
Basic Usage¶
Creating and Configuring a Client¶
from spindlex import SSHClient
from spindlex.hostkeys.policy import RejectPolicy
# Create client
client = SSHClient()
# Configure host key policy. RejectPolicy is the secure default -
# shown explicitly here to make the security posture obvious.
client.set_missing_host_key_policy(RejectPolicy())
# Load ~/.ssh/known_hosts so trusted servers can be verified.
client.get_host_keys().load()
Connection Methods¶
Password Authentication¶
Public Key Authentication¶
Command Execution¶
Simple Commands¶
Commands with Input¶
Host Key Management¶
Host Key Policies¶
from spindlex.hostkeys.policy import (
AutoAddPolicy, RejectPolicy, WarningPolicy
)
# Reject all unknown host keys (the secure default - recommended).
client.set_missing_host_key_policy(RejectPolicy())
# Log warning but accept unknown host keys. Use this only when you
# understand that an attacker can still MITM the first connection.
client.set_missing_host_key_policy(WarningPolicy())
# WARNING: AutoAddPolicy trusts every first-seen host key and therefore
# disables MITM protection. Only use it in short-lived disposable test
# environments - never in production.
client.set_missing_host_key_policy(AutoAddPolicy())
Port Forwarding¶
SpindleX supports both local and remote port forwarding (SSH tunneling).
Local Port Forwarding¶
Local port forwarding allows you to forward a port on your local machine to a port on a remote server.
with SSHClient() as client:
client.connect('jump-host.example.com', username='user')
# Forward local port 8080 to remote-server.internal:80
tunnel_id = client.create_local_port_forward(
local_port=8080,
remote_host='remote-server.internal',
remote_port=80
)
print(f"Tunnel {tunnel_id} established. Connect to localhost:8080")
# Keep the connection open while you use the tunnel
import time
while True:
time.sleep(1)
from spindlex import AsyncSSHClient
async def main():
async with AsyncSSHClient() as client:
await client.connect('jump-host.example.com', username='user')
# Forward local port 8080 to remote-server.internal:80
tunnel_id = await client.create_local_port_forward(
local_port=8080,
remote_host='remote-server.internal',
remote_port=80
)
print(f"Tunnel {tunnel_id} established.")
# Keep the connection open while you use the tunnel
while True:
await asyncio.sleep(1)
Remote Port Forwarding¶
Remote port forwarding allows you to forward a port on the remote server to a port on your local machine.
```python async def main(): async with AsyncSSHClient() as client: await client.connect('server.example.com', username='user')
# Forward remote port 9090 to localhost:3000
tunnel_id = await client.create_remote_port_forward(
remote_port=9090,
local_host='127.0.0.1',
local_port=3000
)
print(f"Remote tunnel {tunnel_id} established.")
Managing Tunnels¶
Once a tunnel is created, you can manage it using the tunnel_id returned by the creation methods.
Closing a Specific Tunnel¶
Listing Active Tunnels¶
Error Handling¶
Common Exceptions¶
from spindlex.exceptions import (
SSHException,
AuthenticationException,
BadHostKeyException,
TransportException
)
try:
client.connect('example.com', username='user', password='pass')
except AuthenticationException as e:
print(f"Authentication failed: {e}")
except BadHostKeyException as e:
print(f"Host key verification failed: {e}")
except TransportException as e:
print(f"Transport error: {e}")
except SSHException as e:
print(f"General SSH error: {e}")
Best Practices¶
- Always close connections: Use context managers (
withorasync with). - Use key-based authentication: More secure than passwords.
- Implement proper host key verification: Don't use
AutoAddPolicyin production. - Handle timeouts appropriately: Set reasonable timeout values.
- Monitor connection health: Check
transport.activeperiodically.