tunnel-manager 0.0.5__tar.gz → 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of tunnel-manager might be problematic. Click here for more details.

Files changed (24) hide show
  1. tunnel_manager-1.0.0/PKG-INFO +391 -0
  2. tunnel_manager-1.0.0/README.md +373 -0
  3. {tunnel_manager-0.0.5 → tunnel_manager-1.0.0}/pyproject.toml +2 -1
  4. tunnel_manager-1.0.0/tests/test_tunnel.py +78 -0
  5. tunnel_manager-1.0.0/tunnel_manager/__init__.py +31 -0
  6. tunnel_manager-1.0.0/tunnel_manager/tunnel_manager.py +891 -0
  7. tunnel_manager-1.0.0/tunnel_manager/tunnel_manager_mcp.py +1644 -0
  8. tunnel_manager-1.0.0/tunnel_manager.egg-info/PKG-INFO +391 -0
  9. {tunnel_manager-0.0.5 → tunnel_manager-1.0.0}/tunnel_manager.egg-info/SOURCES.txt +1 -0
  10. {tunnel_manager-0.0.5 → tunnel_manager-1.0.0}/tunnel_manager.egg-info/entry_points.txt +1 -0
  11. {tunnel_manager-0.0.5 → tunnel_manager-1.0.0}/tunnel_manager.egg-info/top_level.txt +1 -0
  12. tunnel_manager-0.0.5/PKG-INFO +0 -190
  13. tunnel_manager-0.0.5/README.md +0 -172
  14. tunnel_manager-0.0.5/tunnel_manager/__init__.py +0 -16
  15. tunnel_manager-0.0.5/tunnel_manager/tunnel_manager.py +0 -190
  16. tunnel_manager-0.0.5/tunnel_manager/tunnel_manager_mcp.py +0 -317
  17. tunnel_manager-0.0.5/tunnel_manager.egg-info/PKG-INFO +0 -190
  18. {tunnel_manager-0.0.5 → tunnel_manager-1.0.0}/LICENSE +0 -0
  19. {tunnel_manager-0.0.5 → tunnel_manager-1.0.0}/MANIFEST.in +0 -0
  20. {tunnel_manager-0.0.5 → tunnel_manager-1.0.0}/requirements.txt +0 -0
  21. {tunnel_manager-0.0.5 → tunnel_manager-1.0.0}/setup.cfg +0 -0
  22. {tunnel_manager-0.0.5 → tunnel_manager-1.0.0}/tunnel_manager/__main__.py +0 -0
  23. {tunnel_manager-0.0.5 → tunnel_manager-1.0.0}/tunnel_manager.egg-info/dependency_links.txt +0 -0
  24. {tunnel_manager-0.0.5 → tunnel_manager-1.0.0}/tunnel_manager.egg-info/requires.txt +0 -0
@@ -0,0 +1,391 @@
1
+ Metadata-Version: 2.4
2
+ Name: tunnel-manager
3
+ Version: 1.0.0
4
+ Summary: Create SSH Tunnels to your remote hosts and host as an MCP Server for Agentic AI!
5
+ Author-email: Audel Rouhi <knucklessg1@gmail.com>
6
+ License: MIT
7
+ Classifier: Development Status :: 5 - Production/Stable
8
+ Classifier: License :: Public Domain
9
+ Classifier: Environment :: Console
10
+ Classifier: Operating System :: POSIX :: Linux
11
+ Classifier: Programming Language :: Python :: 3
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: fastmcp>=2.11.3
16
+ Requires-Dist: paramiko>=4.0.0
17
+ Dynamic: license-file
18
+
19
+ # Tunnel Manager
20
+
21
+ ![PyPI - Version](https://img.shields.io/pypi/v/tunnel-manager)
22
+ ![PyPI - Downloads](https://img.shields.io/pypi/dd/tunnel-manager)
23
+ ![GitHub Repo stars](https://img.shields.io/github/stars/Knuckles-Team/tunnel-manager)
24
+ ![GitHub forks](https://img.shields.io/github/forks/Knuckles-Team/tunnel-manager)
25
+ ![GitHub contributors](https://img.shields.io/github/contributors/Knuckles-Team/tunnel-manager)
26
+ ![PyPI - License](https://img.shields.io/pypi/l/tunnel-manager)
27
+ ![GitHub](https://img.shields.io/github/license/Knuckles-Team/tunnel-manager)
28
+
29
+ ![GitHub last commit (by committer)](https://img.shields.io/github/last-commit/Knuckles-Team/tunnel-manager)
30
+ ![GitHub pull requests](https://img.shields.io/github/issues-pr/Knuckles-Team/tunnel-manager)
31
+ ![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed/Knuckles-Team/tunnel-manager)
32
+ ![GitHub issues](https://img.shields.io/github/issues/Knuckles-Team/tunnel-manager)
33
+
34
+ ![GitHub top language](https://img.shields.io/github/languages/top/Knuckles-Team/tunnel-manager)
35
+ ![GitHub language count](https://img.shields.io/github/languages/count/Knuckles-Team/tunnel-manager)
36
+ ![GitHub repo size](https://img.shields.io/github/repo-size/Knuckles-Team/tunnel-manager)
37
+ ![GitHub repo file count (file type)](https://img.shields.io/github/directory-file-count/Knuckles-Team/tunnel-manager)
38
+ ![PyPI - Wheel](https://img.shields.io/pypi/wheel/tunnel-manager)
39
+ ![PyPI - Implementation](https://img.shields.io/pypi/implementation/tunnel-manager)
40
+
41
+ *Version: 1.0.0*
42
+
43
+ This project provides a Python-based `Tunnel` class for secure SSH connections and file transfers, integrated with a FastMCP server (`tunnel_manager_mcp.py`) to expose these capabilities as tools for AI-driven workflows. The implementation supports both standard SSH (e.g., for local networks) and Teleport's secure access platform, leveraging the `paramiko` library for SSH operations.
44
+
45
+ ## Features
46
+
47
+ ### Tunnel Class
48
+ - **Purpose**: Facilitates secure SSH connections, file transfers, and key management for single or multiple hosts.
49
+ - **Key Functionality**:
50
+ - **Run Remote Commands**: Execute shell commands on a remote host and retrieve output.
51
+ - **File Upload/Download**: Transfer files to/from a single host or all hosts in an inventory group using SFTP.
52
+ - **Passwordless SSH Setup**: Configure key-based authentication for secure, passwordless access.
53
+ - **SSH Config Management**: Copy local SSH config files to remote hosts.
54
+ - **Key Rotation**: Generate and deploy new SSH key pairs, updating `authorized_keys`.
55
+ - **Inventory Support**: Operate on multiple hosts defined in an Ansible-style YAML inventory, with group targeting (e.g., `all`, `homelab`, `poweredge`).
56
+ - **Teleport Support**: Seamlessly integrates with Teleport's certificate-based authentication and proxying.
57
+ - **Configuration Flexibility**: Loads SSH settings from `~/.ssh/config` by default, with optional overrides for username, password, identity files, certificates, and proxy commands.
58
+ - **Logging**: Optional file-based logging for debugging and auditing.
59
+ - **Parallel Execution**: Support for parallel operations across multiple hosts with configurable thread limits.
60
+
61
+ ### FastMCP Server
62
+ - **Purpose**: Exposes `Tunnel` class functionality as a FastMCP server, enabling AI tools to perform remote operations programmatically.
63
+ - **Tools Provided**:
64
+ - `run_remote_command`: Runs a shell command on a single remote host.
65
+ - `upload_file`: Uploads a file to a single remote host via SFTP.
66
+ - `download_file`: Downloads a file from a single remote host via SFTP.
67
+ - `check_ssh_server`: Checks if the SSH server is running and configured for key-based authentication.
68
+ - `test_key_auth`: Tests key-based authentication for a host.
69
+ - `setup_passwordless_ssh`: Sets up passwordless SSH for a single host.
70
+ - `copy_ssh_config`: Copies an SSH config file to a single remote host.
71
+ - `rotate_ssh_key`: Rotates SSH keys for a single host.
72
+ - `remove_host_key`: Removes a host’s key from the local `known_hosts` file.
73
+ - `setup_all_passwordless_ssh`: Sets up passwordless SSH for all hosts in an inventory group.
74
+ - `run_command_on_all`: Runs a command on all hosts in an inventory group.
75
+ - `copy_ssh_config_on_all`: Copies an SSH config file to all hosts in an inventory group.
76
+ - `rotate_ssh_key_on_all`: Rotates SSH keys for all hosts in an inventory group.
77
+ - **Transport Options**: Supports `stdio` (for local scripting) and `http` (for networked access) transport modes.
78
+ - **Progress Reporting**: Integrates with FastMCP's `Context` for progress updates during operations.
79
+ - **Logging**: Comprehensive logging to a file (`tunnel_mcp.log` by default) or a user-specified file.
80
+
81
+ <details>
82
+ <summary><b>Usage:</b></summary>
83
+
84
+ ## Tunnel Class
85
+ The `Tunnel` class can be used standalone for SSH operations. Example:
86
+
87
+ ```python
88
+ from tunnel_manager.tunnel_manager import Tunnel
89
+
90
+ # Initialize with a remote host (assumes ~/.ssh/config or explicit params)
91
+ tunnel = Tunnel(
92
+ remote_host="192.168.1.10",
93
+ username="admin",
94
+ password="mypassword",
95
+ identity_file="/path/to/id_rsa",
96
+ certificate_file="/path/to/cert", # Optional for Teleport
97
+ proxy_command="tsh proxy ssh %h", # Optional for Teleport
98
+ ssh_config_file="~/.ssh/config",
99
+ log_file="tunnel.log"
100
+ )
101
+
102
+ # Connect and run a command
103
+ tunnel.connect()
104
+ out, err = tunnel.run_command("ls -la /tmp")
105
+ print(f"Output: {out}\nError: {err}")
106
+
107
+ # Upload a file
108
+ tunnel.send_file("/local/file.txt", "/remote/file.txt")
109
+
110
+ # Download a file
111
+ tunnel.receive_file("/remote/file.txt", "/local/downloaded.txt")
112
+
113
+ # Setup passwordless SSH
114
+ tunnel.setup_passwordless_ssh(local_key_path="~/.ssh/id_rsa")
115
+
116
+ # Copy SSH config
117
+ tunnel.copy_ssh_config("/local/ssh_config", "~/.ssh/config")
118
+
119
+ # Rotate SSH key
120
+ tunnel.rotate_ssh_key("/path/to/new_key")
121
+
122
+ # Close the connection
123
+ tunnel.close()
124
+ ```
125
+
126
+ ## Tunnel Manager CLI Usage
127
+ The `tunnel_manager.py` script provides a CLI for managing SSH operations across hosts defined in an Ansible-style YAML inventory file. Below are examples for each command, targeting different inventory groups (`all`, `homelab`, `poweredge`).
128
+
129
+ **Inventory File Example (`inventory.yml`)**:
130
+ ```yaml
131
+ all:
132
+ hosts:
133
+ r510:
134
+ ansible_host: 192.168.1.10
135
+ ansible_user: admin
136
+ ansible_ssh_pass: mypassword
137
+ r710:
138
+ ansible_host: 192.168.1.11
139
+ ansible_user: admin
140
+ ansible_ssh_pass: mypassword
141
+ gr1080:
142
+ ansible_host: 192.168.1.14
143
+ ansible_user: admin
144
+ ansible_ssh_pass: mypassword
145
+ homelab:
146
+ hosts:
147
+ r510:
148
+ ansible_host: 192.168.1.10
149
+ ansible_user: admin
150
+ ansible_ssh_pass: mypassword
151
+ r710:
152
+ ansible_host: 192.168.1.11
153
+ ansible_user: admin
154
+ ansible_ssh_pass: mypassword
155
+ gr1080:
156
+ ansible_host: 192.168.1.14
157
+ ansible_user: admin
158
+ ansible_ssh_pass: mypassword
159
+ poweredge:
160
+ hosts:
161
+ r510:
162
+ ansible_host: 192.168.1.10
163
+ ansible_user: admin
164
+ ansible_ssh_pass: mypassword
165
+ r710:
166
+ ansible_host: 192.168.1.11
167
+ ansible_user: admin
168
+ ansible_ssh_pass: mypassword
169
+ ```
170
+
171
+ Replace IPs, usernames, and passwords with your actual values.
172
+
173
+ ### CLI Commands
174
+
175
+ #### 1. Setup Passwordless SSH
176
+ Set up passwordless SSH for hosts in the inventory, distributing a shared key.
177
+ - **Target `all` group (sequential)**:
178
+ ```bash
179
+ tunnel-manager setup-all --inventory inventory.yml --shared-key-path ~/.ssh/id_shared --log-file setup.log
180
+ ```
181
+ - **Target `homelab` group (parallel, 3 threads)**:
182
+ ```bash
183
+ tunnel-manager setup-all --inventory inventory.yml --shared-key-path ~/.ssh/id_shared --group homelab --parallel --max-threads 3 --log-file setup_homelab.log
184
+ ```
185
+ - **Target `poweredge` group (sequential)**:
186
+ ```bash
187
+ tunnel-manager setup-all --inventory inventory.yml --shared-key-path ~/.ssh/id_shared --group poweredge --log-file setup_poweredge.log
188
+ ```
189
+
190
+ #### 2. Run a Command
191
+ Execute a shell command on all hosts in the specified group.
192
+ - **Run `uptime` on `all` group (sequential)**:
193
+ ```bash
194
+ tunnel-manager run-command --inventory inventory.yml --remote-command "uptime" --log-file uptime.log
195
+ ```
196
+ - **Run `df -h` on `homelab` group (parallel, 5 threads)**:
197
+ ```bash
198
+ tunnel-manager run-command --inventory inventory.yml --remote-command "df -h" --group homelab --parallel --max-threads 5 --log-file df_homelab.log
199
+ ```
200
+ - **Run `whoami` on `poweredge` group (sequential)**:
201
+ ```bash
202
+ tunnel-manager run-command --inventory inventory.yml --remote-command "whoami" --group poweredge --log-file whoami_poweredge.log
203
+ ```
204
+
205
+ #### 3. Copy SSH Config
206
+ Copy a local SSH config file to the remote hosts’ `~/.ssh/config`.
207
+ - **Copy to `all` group (sequential)**:
208
+ ```bash
209
+ tunnel-manager copy-config --inventory inventory.yml --local-config-path ~/.ssh/config --log-file copy_config.log
210
+ ```
211
+ - **Copy to `homelab` group (parallel, 4 threads)**:
212
+ ```bash
213
+ tunnel-manager copy-config --inventory inventory.yml --local-config-path ~/.ssh/config --group homelab --parallel --max-threads 4 --log-file copy_homelab.log
214
+ ```
215
+ - **Copy to `poweredge` group with custom remote path**:
216
+ ```bash
217
+ tunnel-manager copy-config --inventory inventory.yml --local-config-path ~/.ssh/config --remote-config-path ~/.ssh/custom_config --group poweredge --log-file copy_poweredge.log
218
+ ```
219
+
220
+ #### 4. Rotate SSH Keys
221
+ Rotate SSH keys for hosts, generating new keys with a prefix.
222
+ - **Rotate keys for `all` group (sequential)**:
223
+ ```bash
224
+ tunnel-manager rotate-key --inventory inventory.yml --key-prefix ~/.ssh/id_ --log-file rotate.log
225
+ ```
226
+ - **Rotate keys for `homelab` group (parallel, 3 threads)**:
227
+ ```bash
228
+ tunnel-manager rotate-key --inventory inventory.yml --key-prefix ~/.ssh/id_ --group homelab --parallel --max-threads 3 --log-file rotate_homelab.log
229
+ ```
230
+ - **Rotate keys for `poweredge` group (sequential)**:
231
+ ```bash
232
+ tunnel-manager rotate-key --inventory inventory.yml --key-prefix ~/.ssh/id_ --group poweredge --log-file rotate_poweredge.log
233
+ ```
234
+
235
+ #### 5. Upload a File
236
+ Upload a local file to all hosts in the specified group.
237
+ - **Upload to `all` group (sequential)**:
238
+ ```bash
239
+ tunnel-manager send-file --inventory inventory.yml --local-path ./myfile.txt --remote-path /home/user/myfile.txt --log-file upload.log
240
+ ```
241
+ - **Upload to `homelab` group (parallel, 3 threads)**:
242
+ ```bash
243
+ tunnel-manager send-file --inventory inventory.yml --local-path ./myfile.txt --remote-path /home/user/myfile.txt --group homelab --parallel --max-threads 3 --log-file upload_homelab.log
244
+ ```
245
+ - **Upload to `poweredge` group (sequential)**:
246
+ ```bash
247
+ tunnel-manager send-file --inventory inventory.yml --local-path ./myfile.txt --remote-path /home/user/myfile.txt --group poweredge --log-file upload_poweredge.log
248
+ ```
249
+
250
+ #### 6. Download a File
251
+ Download a file from all hosts in the specified group, saving to host-specific subdirectories (e.g., `downloads/R510/myfile.txt`).
252
+ - **Download from `all` group (sequential)**:
253
+ ```bash
254
+ tunnel-manager receive-file --inventory inventory.yml --remote-path /home/user/myfile.txt --local-path-prefix ./downloads --log-file download.log
255
+ ```
256
+ - **Download from `homelab` group (parallel, 3 threads)**:
257
+ ```bash
258
+ tunnel-manager receive-file --inventory inventory.yml --remote-path /home/user/myfile.txt --local-path-prefix ./downloads --group homelab --parallel --max-threads 3 --log-file download_homelab.log
259
+ ```
260
+ - **Download from `poweredge` group (sequential)**:
261
+ ```bash
262
+ tunnel-manager receive-file --inventory inventory.yml --remote-path /home/user/myfile.txt --local-path-prefix ./downloads --group poweredge --log-file download_poweredge.log
263
+ ```
264
+
265
+ ### CLI Command Table
266
+ | Short Flag | Long Flag | Description | Required | Default Value |
267
+ |------------|----------------------|----------------------------------------------------------|----------|---------------|
268
+ | -h | --help | Show usage for the script | No | None |
269
+ | | --log-file | Log to specified file (default: console output) | No | Console |
270
+ | | setup-all | Setup passwordless SSH for all hosts in inventory | Yes* | None |
271
+ | | --inventory | YAML inventory path | Yes | None |
272
+ | | --shared-key-path | Path to shared private key | No | ~/.ssh/id_shared |
273
+ | | --group | Inventory group to target | No | all |
274
+ | | --parallel | Run operation in parallel | No | False |
275
+ | | --max-threads | Max threads for parallel execution | No | 5 |
276
+ | | run-command | Run a shell command on all hosts in inventory | Yes* | None |
277
+ | | --remote-command | Shell command to run | Yes | None |
278
+ | | copy-config | Copy SSH config to all hosts in inventory | Yes* | None |
279
+ | | --local-config-path | Local SSH config path | Yes | None |
280
+ | | --remote-config-path | Remote path for SSH config | No | ~/.ssh/config |
281
+ | | rotate-key | Rotate SSH keys for all hosts in inventory | Yes* | None |
282
+ | | --key-prefix | Prefix for new key paths (appends hostname) | No | ~/.ssh/id_ |
283
+ | | send-file | Upload a file to all hosts in inventory | Yes* | None |
284
+ | | --local-path | Local file path to upload | Yes | None |
285
+ | | --remote-path | Remote destination path | Yes | None |
286
+ | | receive-file | Download a file from all hosts in inventory | Yes* | None |
287
+ | | --remote-path | Remote file path to download | Yes | None |
288
+ | | --local-path-prefix | Local directory path prefix to save files | Yes | None |
289
+
290
+ ### Notes
291
+ One of the commands (`setup-all`, `run-command`, `copy-config`, `rotate-key`, `send-file`, `receive-file`) must be specified as the first argument to `tunnel_manager.py`. Each command has required arguments that must be specified with flags:
292
+ - `setup-all`: Requires `--inventory`.
293
+ - `run-command`: Requires `--inventory` and `--remote-command`.
294
+ - `copy-config`: Requires `--inventory` and `--local-config-path`.
295
+ - `rotate-key`: Requires `--inventory`.
296
+ - `send-file`: Requires `--inventory`, `--local-path`, and `--remote-path`.
297
+ - `receive-file`: Requires `--inventory`, `--remote-path`, and `--local-path-prefix`.
298
+
299
+ ### Additional Notes
300
+ - Ensure `ansible_host` values in `inventory.yml` are resolvable IPs or hostnames.
301
+ - Update `ansible_ssh_private_key_file` in the inventory after running `rotate-key`.
302
+ - Use `--log-file` for file-based logging or omit for console output.
303
+ - The `--parallel` option speeds up operations but may overload resources; adjust `--max-threads` as needed.
304
+ - The `receive-file` command saves files to `local_path_prefix/<hostname>/<filename>` to preserve original filenames and avoid conflicts.
305
+
306
+ ## FastMCP Server
307
+ The FastMCP server exposes the `Tunnel` functionality as AI-accessible tools. Start the server with:
308
+
309
+ ```bash
310
+ python tunnel_manager_mcp.py --transport stdio
311
+ ```
312
+
313
+ Or for HTTP transport:
314
+ ```bash
315
+ python tunnel_manager_mcp.py --transport http --host 127.0.0.1 --port 8080
316
+ ```
317
+
318
+ </details>
319
+
320
+ <details>
321
+ <summary><b>Installation Instructions:</b></summary>
322
+
323
+ ## Use with AI
324
+
325
+ Configure `mcp.json`
326
+ ```json
327
+ {
328
+ "mcpServers": {
329
+ "tunnel_manager": {
330
+ "command": "uv",
331
+ "args": [
332
+ "run",
333
+ "--with",
334
+ "tunnel-manager",
335
+ "tunnel_manager_mcp"
336
+ ],
337
+ "env": {
338
+ "TUNNEL_REMOTE_HOST": "user@192.168.1.12", // Optional
339
+ "TUNNEL_USERNAME": "admin", // Optional
340
+ "TUNNEL_PASSWORD": "", // Optional
341
+ "TUNNEL_REMOTE_PORT": "22", // Optional
342
+ "TUNNEL_IDENTITY_FILE": "", // Optional
343
+ "TUNNEL_CERTIFICATE": "", // Optional
344
+ "TUNNEL_PROXY_COMMAND": "", // Optional
345
+ "TUNNEL_LOG_FILE": "~/tunnel_log.txt" // Optional
346
+ },
347
+ "timeout": 200000
348
+ }
349
+ }
350
+ }
351
+ ```
352
+
353
+ ### Deploy MCP Server as a Container
354
+ ```bash
355
+ docker pull knucklessg1/tunnel-manager:latest
356
+ ```
357
+
358
+ Modify the `compose.yml`
359
+ ```yaml
360
+ services:
361
+ tunnel-manager:
362
+ image: knucklessg1/tunnel-manager:latest
363
+ environment:
364
+ - HOST=0.0.0.0
365
+ - PORT=8021
366
+ ports:
367
+ - 8021:8021
368
+ ```
369
+
370
+ ### Install Python Package
371
+ ```bash
372
+ python -m pip install tunnel-manager
373
+ ```
374
+
375
+ or
376
+
377
+ ```bash
378
+ uv pip install --upgrade tunnel-manager
379
+ ```
380
+
381
+ </details>
382
+
383
+ <details>
384
+ <summary><b>Repository Owners:</b></summary>
385
+
386
+
387
+ <img width="100%" height="180em" src="https://github-readme-stats.vercel.app/api?username=Knucklessg1&show_icons=true&hide_border=true&&count_private=true&include_all_commits=true" />
388
+
389
+ ![GitHub followers](https://img.shields.io/github/followers/Knucklessg1)
390
+ ![GitHub User's stars](https://img.shields.io/github/stars/Knucklessg1)
391
+ </details>