tunnel-manager 1.0.3__tar.gz → 1.0.5__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.
- {tunnel_manager-1.0.3/tunnel_manager.egg-info → tunnel_manager-1.0.5}/PKG-INFO +295 -197
- {tunnel_manager-1.0.3 → tunnel_manager-1.0.5}/README.md +293 -195
- {tunnel_manager-1.0.3 → tunnel_manager-1.0.5}/pyproject.toml +2 -2
- {tunnel_manager-1.0.3 → tunnel_manager-1.0.5}/requirements.txt +1 -1
- {tunnel_manager-1.0.3 → tunnel_manager-1.0.5}/tunnel_manager/tunnel_manager_mcp.py +213 -2
- {tunnel_manager-1.0.3 → tunnel_manager-1.0.5/tunnel_manager.egg-info}/PKG-INFO +295 -197
- {tunnel_manager-1.0.3 → tunnel_manager-1.0.5}/tunnel_manager.egg-info/requires.txt +1 -1
- {tunnel_manager-1.0.3 → tunnel_manager-1.0.5}/LICENSE +0 -0
- {tunnel_manager-1.0.3 → tunnel_manager-1.0.5}/MANIFEST.in +0 -0
- {tunnel_manager-1.0.3 → tunnel_manager-1.0.5}/setup.cfg +0 -0
- {tunnel_manager-1.0.3 → tunnel_manager-1.0.5}/tests/test_tunnel.py +0 -0
- {tunnel_manager-1.0.3 → tunnel_manager-1.0.5}/tunnel_manager/__init__.py +0 -0
- {tunnel_manager-1.0.3 → tunnel_manager-1.0.5}/tunnel_manager/__main__.py +0 -0
- {tunnel_manager-1.0.3 → tunnel_manager-1.0.5}/tunnel_manager/tunnel_manager.py +0 -0
- {tunnel_manager-1.0.3 → tunnel_manager-1.0.5}/tunnel_manager.egg-info/SOURCES.txt +0 -0
- {tunnel_manager-1.0.3 → tunnel_manager-1.0.5}/tunnel_manager.egg-info/dependency_links.txt +0 -0
- {tunnel_manager-1.0.3 → tunnel_manager-1.0.5}/tunnel_manager.egg-info/entry_points.txt +0 -0
- {tunnel_manager-1.0.3 → tunnel_manager-1.0.5}/tunnel_manager.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tunnel-manager
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.5
|
|
4
4
|
Summary: Create SSH Tunnels to your remote hosts and host as an MCP Server for Agentic AI!
|
|
5
5
|
Author-email: Audel Rouhi <knucklessg1@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -12,7 +12,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
12
12
|
Requires-Python: >=3.10
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE
|
|
15
|
-
Requires-Dist: fastmcp>=2.
|
|
15
|
+
Requires-Dist: fastmcp>=2.12.4
|
|
16
16
|
Requires-Dist: paramiko>=4.0.0
|
|
17
17
|
Dynamic: license-file
|
|
18
18
|
|
|
@@ -38,7 +38,7 @@ Dynamic: license-file
|
|
|
38
38
|

|
|
39
39
|

|
|
40
40
|
|
|
41
|
-
*Version: 1.0.
|
|
41
|
+
*Version: 1.0.5*
|
|
42
42
|
|
|
43
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
44
|
|
|
@@ -84,135 +84,49 @@ This project provides a Python-based `Tunnel` class for secure SSH connections a
|
|
|
84
84
|
<details>
|
|
85
85
|
<summary><b>Usage:</b></summary>
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
# Download a file
|
|
114
|
-
tunnel.receive_file("/remote/file.txt", "/local/downloaded.txt")
|
|
115
|
-
|
|
116
|
-
# Setup passwordless SSH with RSA
|
|
117
|
-
tunnel.setup_passwordless_ssh(local_key_path="~/.ssh/id_rsa", key_type="rsa")
|
|
118
|
-
|
|
119
|
-
# Copy SSH config
|
|
120
|
-
tunnel.copy_ssh_config("/local/ssh_config", "~/.ssh/config")
|
|
121
|
-
|
|
122
|
-
# Rotate SSH key with RSA
|
|
123
|
-
tunnel.rotate_ssh_key("/path/to/new_rsa_key", key_type="rsa")
|
|
124
|
-
|
|
125
|
-
# Close the connection
|
|
126
|
-
tunnel.close()
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
### Using Ed25519 Keys
|
|
130
|
-
```python
|
|
131
|
-
from tunnel_manager.tunnel_manager import Tunnel
|
|
132
|
-
|
|
133
|
-
# Initialize with a remote host (assumes ~/.ssh/config or explicit params)
|
|
134
|
-
tunnel = Tunnel(
|
|
135
|
-
remote_host="192.168.1.10",
|
|
136
|
-
username="admin",
|
|
137
|
-
password="mypassword",
|
|
138
|
-
identity_file="/path/to/id_ed25519",
|
|
139
|
-
certificate_file="/path/to/cert", # Optional for Teleport
|
|
140
|
-
proxy_command="tsh proxy ssh %h", # Optional for Teleport
|
|
141
|
-
ssh_config_file="~/.ssh/config",
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
# Connect and run a command
|
|
145
|
-
tunnel.connect()
|
|
146
|
-
out, err = tunnel.run_command("ls -la /tmp")
|
|
147
|
-
print(f"Output: {out}\nError: {err}")
|
|
148
|
-
|
|
149
|
-
# Upload a file
|
|
150
|
-
tunnel.send_file("/local/file.txt", "/remote/file.txt")
|
|
151
|
-
|
|
152
|
-
# Download a file
|
|
153
|
-
tunnel.receive_file("/remote/file.txt", "/local/downloaded.txt")
|
|
154
|
-
|
|
155
|
-
# Setup passwordless SSH with Ed25519
|
|
156
|
-
tunnel.setup_passwordless_ssh(local_key_path="~/.ssh/id_ed25519", key_type="ed25519")
|
|
157
|
-
|
|
158
|
-
# Copy SSH config
|
|
159
|
-
tunnel.copy_ssh_config("/local/ssh_config", "~/.ssh/config")
|
|
160
|
-
|
|
161
|
-
# Rotate SSH key with Ed25519
|
|
162
|
-
tunnel.rotate_ssh_key("/path/to/new_ed25519_key", key_type="ed25519")
|
|
163
|
-
|
|
164
|
-
# Close the connection
|
|
165
|
-
tunnel.close()
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
## Tunnel Manager CLI Usage
|
|
169
|
-
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`). The CLI now supports both RSA and Ed25519 keys via the `--key-type` flag for relevant commands (default: `ed25519`).
|
|
170
|
-
|
|
171
|
-
**Inventory File Example (`inventory.yml`)**:
|
|
172
|
-
```yaml
|
|
173
|
-
all:
|
|
174
|
-
hosts:
|
|
175
|
-
r510:
|
|
176
|
-
ansible_host: 192.168.1.10
|
|
177
|
-
ansible_user: admin
|
|
178
|
-
ansible_ssh_private_key_file: "~/.ssh/id_ed25519"
|
|
179
|
-
r710:
|
|
180
|
-
ansible_host: 192.168.1.11
|
|
181
|
-
ansible_user: admin
|
|
182
|
-
ansible_ssh_pass: mypassword
|
|
183
|
-
gr1080:
|
|
184
|
-
ansible_host: 192.168.1.14
|
|
185
|
-
ansible_user: admin
|
|
186
|
-
ansible_ssh_private_key_file: "~/.ssh/id_rsa"
|
|
187
|
-
homelab:
|
|
188
|
-
hosts:
|
|
189
|
-
r510:
|
|
190
|
-
ansible_host: 192.168.1.10
|
|
191
|
-
ansible_user: admin
|
|
192
|
-
ansible_ssh_private_key_file: "~/.ssh/id_ed25519"
|
|
193
|
-
r710:
|
|
194
|
-
ansible_host: 192.168.1.11
|
|
195
|
-
ansible_user: admin
|
|
196
|
-
ansible_ssh_pass: mypassword
|
|
197
|
-
gr1080:
|
|
198
|
-
ansible_host: 192.168.1.14
|
|
199
|
-
ansible_user: admin
|
|
200
|
-
ansible_ssh_private_key_file: "~/.ssh/id_rsa"
|
|
201
|
-
poweredge:
|
|
202
|
-
hosts:
|
|
203
|
-
r510:
|
|
204
|
-
ansible_host: 192.168.1.10
|
|
205
|
-
ansible_user: admin
|
|
206
|
-
ansible_ssh_private_key_file: "~/.ssh/id_ed25519"
|
|
207
|
-
r710:
|
|
208
|
-
ansible_host: 192.168.1.11
|
|
209
|
-
ansible_user: admin
|
|
210
|
-
ansible_ssh_pass: mypassword
|
|
211
|
-
```
|
|
87
|
+
### CLI
|
|
88
|
+
| Short Flag | Long Flag | Description | Required | Default Value |
|
|
89
|
+
|------------|----------------------|----------------------------------------------------------|----------|---------------|
|
|
90
|
+
| -h | --help | Show usage for the script | No | None |
|
|
91
|
+
| | --log-file | Log to specified file (default: console output) | No | Console |
|
|
92
|
+
| | setup-all | Setup passwordless SSH for all hosts in inventory | Yes* | None |
|
|
93
|
+
| | --inventory | YAML inventory path | Yes | None |
|
|
94
|
+
| | --shared-key-path | Path to shared private key | No | ~/.ssh/id_shared |
|
|
95
|
+
| | --key-type | Key type (rsa or ed25519) | No | ed25519 |
|
|
96
|
+
| | --group | Inventory group to target | No | all |
|
|
97
|
+
| | --parallel | Run operation in parallel | No | False |
|
|
98
|
+
| | --max-threads | Max threads for parallel execution | No | 5 |
|
|
99
|
+
| | run-command | Run a shell command on all hosts in inventory | Yes* | None |
|
|
100
|
+
| | --remote-command | Shell command to run | Yes | None |
|
|
101
|
+
| | copy-config | Copy SSH config to all hosts in inventory | Yes* | None |
|
|
102
|
+
| | --local-config-path | Local SSH config path | Yes | None |
|
|
103
|
+
| | --remote-config-path | Remote path for SSH config | No | ~/.ssh/config |
|
|
104
|
+
| | rotate-key | Rotate SSH keys for all hosts in inventory | Yes* | None |
|
|
105
|
+
| | --key-prefix | Prefix for new key paths (appends hostname) | No | ~/.ssh/id_ |
|
|
106
|
+
| | --key-type | Key type (rsa or ed25519) | No | ed25519 |
|
|
107
|
+
| | send-file | Upload a file to all hosts in inventory | Yes* | None |
|
|
108
|
+
| | --local-path | Local file path to upload | Yes | None |
|
|
109
|
+
| | --remote-path | Remote destination path | Yes | None |
|
|
110
|
+
| | receive-file | Download a file from all hosts in inventory | Yes* | None |
|
|
111
|
+
| | --remote-path | Remote file path to download | Yes | None |
|
|
112
|
+
| | --local-path-prefix | Local directory path prefix to save files | Yes | None |
|
|
212
113
|
|
|
213
|
-
|
|
114
|
+
### Notes
|
|
115
|
+
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:
|
|
116
|
+
- `setup-all`: Requires `--inventory`.
|
|
117
|
+
- `run-command`: Requires `--inventory` and `--remote-command`.
|
|
118
|
+
- `copy-config`: Requires `--inventory` and `--local-config-path`.
|
|
119
|
+
- `rotate-key`: Requires `--inventory`.
|
|
120
|
+
- `send-file`: Requires `--inventory`, `--local-path`, and `--remote-path`.
|
|
121
|
+
- `receive-file`: Requires `--inventory`, `--remote-path`, and `--local-path-prefix`.
|
|
214
122
|
|
|
215
|
-
###
|
|
123
|
+
### Additional Notes
|
|
124
|
+
- Ensure `ansible_host` values in `inventory.yml` are resolvable IPs or hostnames.
|
|
125
|
+
- Update `ansible_ssh_private_key_file` in the inventory after running `rotate-key`.
|
|
126
|
+
- Use `--log-file` for file-based logging or omit for console output.
|
|
127
|
+
- The `--parallel` option speeds up operations but may overload resources; adjust `--max-threads` as needed.
|
|
128
|
+
- The `receive-file` command saves files to `local_path_prefix/<hostname>/<filename>` to preserve original filenames and avoid conflicts.
|
|
129
|
+
- Ed25519 keys are recommended for better security and performance over RSA, but RSA is supported for compatibility with older systems.
|
|
216
130
|
|
|
217
131
|
#### 1. Setup Passwordless SSH
|
|
218
132
|
Set up passwordless SSH for hosts in the inventory, distributing a shared key. Use `--key-type` to specify RSA or Ed25519 (default: ed25519).
|
|
@@ -304,70 +218,267 @@ Download a file from all hosts in the specified group, saving to host-specific s
|
|
|
304
218
|
tunnel-manager --log-file download_poweredge.log receive-file --inventory inventory.yml --remote-path /home/user/myfile.txt --local-path-prefix ./downloads --group poweredge
|
|
305
219
|
```
|
|
306
220
|
|
|
307
|
-
###
|
|
308
|
-
| Short Flag | Long Flag | Description | Required | Default Value |
|
|
309
|
-
|------------|----------------------|----------------------------------------------------------|----------|---------------|
|
|
310
|
-
| -h | --help | Show usage for the script | No | None |
|
|
311
|
-
| | --log-file | Log to specified file (default: console output) | No | Console |
|
|
312
|
-
| | setup-all | Setup passwordless SSH for all hosts in inventory | Yes* | None |
|
|
313
|
-
| | --inventory | YAML inventory path | Yes | None |
|
|
314
|
-
| | --shared-key-path | Path to shared private key | No | ~/.ssh/id_shared |
|
|
315
|
-
| | --key-type | Key type (rsa or ed25519) | No | ed25519 |
|
|
316
|
-
| | --group | Inventory group to target | No | all |
|
|
317
|
-
| | --parallel | Run operation in parallel | No | False |
|
|
318
|
-
| | --max-threads | Max threads for parallel execution | No | 5 |
|
|
319
|
-
| | run-command | Run a shell command on all hosts in inventory | Yes* | None |
|
|
320
|
-
| | --remote-command | Shell command to run | Yes | None |
|
|
321
|
-
| | copy-config | Copy SSH config to all hosts in inventory | Yes* | None |
|
|
322
|
-
| | --local-config-path | Local SSH config path | Yes | None |
|
|
323
|
-
| | --remote-config-path | Remote path for SSH config | No | ~/.ssh/config |
|
|
324
|
-
| | rotate-key | Rotate SSH keys for all hosts in inventory | Yes* | None |
|
|
325
|
-
| | --key-prefix | Prefix for new key paths (appends hostname) | No | ~/.ssh/id_ |
|
|
326
|
-
| | --key-type | Key type (rsa or ed25519) | No | ed25519 |
|
|
327
|
-
| | send-file | Upload a file to all hosts in inventory | Yes* | None |
|
|
328
|
-
| | --local-path | Local file path to upload | Yes | None |
|
|
329
|
-
| | --remote-path | Remote destination path | Yes | None |
|
|
330
|
-
| | receive-file | Download a file from all hosts in inventory | Yes* | None |
|
|
331
|
-
| | --remote-path | Remote file path to download | Yes | None |
|
|
332
|
-
| | --local-path-prefix | Local directory path prefix to save files | Yes | None |
|
|
221
|
+
### Tunnel Manager Inventory
|
|
333
222
|
|
|
334
|
-
|
|
335
|
-
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:
|
|
336
|
-
- `setup-all`: Requires `--inventory`.
|
|
337
|
-
- `run-command`: Requires `--inventory` and `--remote-command`.
|
|
338
|
-
- `copy-config`: Requires `--inventory` and `--local-config-path`.
|
|
339
|
-
- `rotate-key`: Requires `--inventory`.
|
|
340
|
-
- `send-file`: Requires `--inventory`, `--local-path`, and `--remote-path`.
|
|
341
|
-
- `receive-file`: Requires `--inventory`, `--remote-path`, and `--local-path-prefix`.
|
|
223
|
+
**Inventory File Example (`inventory.yml`)**:
|
|
342
224
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
225
|
+
```yaml
|
|
226
|
+
all:
|
|
227
|
+
hosts:
|
|
228
|
+
r510:
|
|
229
|
+
ansible_host: 192.168.1.10
|
|
230
|
+
ansible_user: admin
|
|
231
|
+
ansible_ssh_private_key_file: "~/.ssh/id_ed25519"
|
|
232
|
+
r710:
|
|
233
|
+
ansible_host: 192.168.1.11
|
|
234
|
+
ansible_user: admin
|
|
235
|
+
ansible_ssh_pass: mypassword
|
|
236
|
+
gr1080:
|
|
237
|
+
ansible_host: 192.168.1.14
|
|
238
|
+
ansible_user: admin
|
|
239
|
+
ansible_ssh_private_key_file: "~/.ssh/id_rsa"
|
|
240
|
+
homelab:
|
|
241
|
+
hosts:
|
|
242
|
+
r510:
|
|
243
|
+
ansible_host: 192.168.1.10
|
|
244
|
+
ansible_user: admin
|
|
245
|
+
ansible_ssh_private_key_file: "~/.ssh/id_ed25519"
|
|
246
|
+
r710:
|
|
247
|
+
ansible_host: 192.168.1.11
|
|
248
|
+
ansible_user: admin
|
|
249
|
+
ansible_ssh_pass: mypassword
|
|
250
|
+
gr1080:
|
|
251
|
+
ansible_host: 192.168.1.14
|
|
252
|
+
ansible_user: admin
|
|
253
|
+
ansible_ssh_private_key_file: "~/.ssh/id_rsa"
|
|
254
|
+
poweredge:
|
|
255
|
+
hosts:
|
|
256
|
+
r510:
|
|
257
|
+
ansible_host: 192.168.1.10
|
|
258
|
+
ansible_user: admin
|
|
259
|
+
ansible_ssh_private_key_file: "~/.ssh/id_ed25519"
|
|
260
|
+
r710:
|
|
261
|
+
ansible_host: 192.168.1.11
|
|
262
|
+
ansible_user: admin
|
|
263
|
+
ansible_ssh_pass: mypassword
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Replace IPs, usernames, and passwords with your actual values.
|
|
350
267
|
|
|
351
|
-
## FastMCP Server
|
|
352
|
-
The FastMCP server exposes the `Tunnel` functionality as AI-accessible tools. Start the server with:
|
|
353
268
|
|
|
269
|
+
### MCP CLI
|
|
270
|
+
|
|
271
|
+
| Short Flag | Long Flag | Description |
|
|
272
|
+
|------------|------------------------------------|-----------------------------------------------------------------------------|
|
|
273
|
+
| -h | --help | Display help information |
|
|
274
|
+
| -t | --transport | Transport method: 'stdio', 'http', or 'sse' [legacy] (default: stdio) |
|
|
275
|
+
| -s | --host | Host address for HTTP transport (default: 0.0.0.0) |
|
|
276
|
+
| -p | --port | Port number for HTTP transport (default: 8000) |
|
|
277
|
+
| | --auth-type | Authentication type: 'none', 'static', 'jwt', 'oauth-proxy', 'oidc-proxy', 'remote-oauth' (default: none) |
|
|
278
|
+
| | --token-jwks-uri | JWKS URI for JWT verification |
|
|
279
|
+
| | --token-issuer | Issuer for JWT verification |
|
|
280
|
+
| | --token-audience | Audience for JWT verification |
|
|
281
|
+
| | --oauth-upstream-auth-endpoint | Upstream authorization endpoint for OAuth Proxy |
|
|
282
|
+
| | --oauth-upstream-token-endpoint | Upstream token endpoint for OAuth Proxy |
|
|
283
|
+
| | --oauth-upstream-client-id | Upstream client ID for OAuth Proxy |
|
|
284
|
+
| | --oauth-upstream-client-secret | Upstream client secret for OAuth Proxy |
|
|
285
|
+
| | --oauth-base-url | Base URL for OAuth Proxy |
|
|
286
|
+
| | --oidc-config-url | OIDC configuration URL |
|
|
287
|
+
| | --oidc-client-id | OIDC client ID |
|
|
288
|
+
| | --oidc-client-secret | OIDC client secret |
|
|
289
|
+
| | --oidc-base-url | Base URL for OIDC Proxy |
|
|
290
|
+
| | --remote-auth-servers | Comma-separated list of authorization servers for Remote OAuth |
|
|
291
|
+
| | --remote-base-url | Base URL for Remote OAuth |
|
|
292
|
+
| | --allowed-client-redirect-uris | Comma-separated list of allowed client redirect URIs |
|
|
293
|
+
| | --eunomia-type | Eunomia authorization type: 'none', 'embedded', 'remote' (default: none) |
|
|
294
|
+
| | --eunomia-policy-file | Policy file for embedded Eunomia (default: mcp_policies.json) |
|
|
295
|
+
| | --eunomia-remote-url | URL for remote Eunomia server |
|
|
296
|
+
|
|
297
|
+
### Using as an MCP Server
|
|
298
|
+
|
|
299
|
+
The MCP Server can be run in two modes: `stdio` (for local testing) or `http` (for networked access). To start the server, use the following commands:
|
|
300
|
+
|
|
301
|
+
#### Run in stdio mode (default):
|
|
354
302
|
```bash
|
|
355
|
-
|
|
303
|
+
tunnel-manager-mcp --transport "stdio"
|
|
356
304
|
```
|
|
357
305
|
|
|
358
|
-
|
|
306
|
+
#### Run in HTTP mode:
|
|
359
307
|
```bash
|
|
360
|
-
|
|
308
|
+
tunnel-manager-mcp --transport "http" --host "0.0.0.0" --port "8000"
|
|
361
309
|
```
|
|
362
310
|
|
|
363
|
-
|
|
311
|
+
### Tunnel Class
|
|
312
|
+
The `Tunnel` class can be used standalone for SSH operations. Examples:
|
|
364
313
|
|
|
365
|
-
|
|
366
|
-
|
|
314
|
+
#### Using RSA Keys
|
|
315
|
+
```python
|
|
316
|
+
from tunnel_manager.tunnel_manager import Tunnel
|
|
367
317
|
|
|
368
|
-
|
|
318
|
+
# Initialize with a remote host (assumes ~/.ssh/config or explicit params)
|
|
319
|
+
tunnel = Tunnel(
|
|
320
|
+
remote_host="192.168.1.10",
|
|
321
|
+
username="admin",
|
|
322
|
+
password="mypassword",
|
|
323
|
+
identity_file="/path/to/id_rsa",
|
|
324
|
+
certificate_file="/path/to/cert", # Optional for Teleport
|
|
325
|
+
proxy_command="tsh proxy ssh %h", # Optional for Teleport
|
|
326
|
+
ssh_config_file="~/.ssh/config",
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
# Connect and run a command
|
|
330
|
+
tunnel.connect()
|
|
331
|
+
out, err = tunnel.run_command("ls -la /tmp")
|
|
332
|
+
print(f"Output: {out}\nError: {err}")
|
|
333
|
+
|
|
334
|
+
# Upload a file
|
|
335
|
+
tunnel.send_file("/local/file.txt", "/remote/file.txt")
|
|
336
|
+
|
|
337
|
+
# Download a file
|
|
338
|
+
tunnel.receive_file("/remote/file.txt", "/local/downloaded.txt")
|
|
339
|
+
|
|
340
|
+
# Setup passwordless SSH with RSA
|
|
341
|
+
tunnel.setup_passwordless_ssh(local_key_path="~/.ssh/id_rsa", key_type="rsa")
|
|
342
|
+
|
|
343
|
+
# Copy SSH config
|
|
344
|
+
tunnel.copy_ssh_config("/local/ssh_config", "~/.ssh/config")
|
|
345
|
+
|
|
346
|
+
# Rotate SSH key with RSA
|
|
347
|
+
tunnel.rotate_ssh_key("/path/to/new_rsa_key", key_type="rsa")
|
|
348
|
+
|
|
349
|
+
# Close the connection
|
|
350
|
+
tunnel.close()
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
#### Using Ed25519 Keys
|
|
354
|
+
```python
|
|
355
|
+
from tunnel_manager.tunnel_manager import Tunnel
|
|
356
|
+
|
|
357
|
+
# Initialize with a remote host (assumes ~/.ssh/config or explicit params)
|
|
358
|
+
tunnel = Tunnel(
|
|
359
|
+
remote_host="192.168.1.10",
|
|
360
|
+
username="admin",
|
|
361
|
+
password="mypassword",
|
|
362
|
+
identity_file="/path/to/id_ed25519",
|
|
363
|
+
certificate_file="/path/to/cert", # Optional for Teleport
|
|
364
|
+
proxy_command="tsh proxy ssh %h", # Optional for Teleport
|
|
365
|
+
ssh_config_file="~/.ssh/config",
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
# Connect and run a command
|
|
369
|
+
tunnel.connect()
|
|
370
|
+
out, err = tunnel.run_command("ls -la /tmp")
|
|
371
|
+
print(f"Output: {out}\nError: {err}")
|
|
372
|
+
|
|
373
|
+
# Upload a file
|
|
374
|
+
tunnel.send_file("/local/file.txt", "/remote/file.txt")
|
|
375
|
+
|
|
376
|
+
# Download a file
|
|
377
|
+
tunnel.receive_file("/remote/file.txt", "/local/downloaded.txt")
|
|
378
|
+
|
|
379
|
+
# Setup passwordless SSH with Ed25519
|
|
380
|
+
tunnel.setup_passwordless_ssh(local_key_path="~/.ssh/id_ed25519", key_type="ed25519")
|
|
381
|
+
|
|
382
|
+
# Copy SSH config
|
|
383
|
+
tunnel.copy_ssh_config("/local/ssh_config", "~/.ssh/config")
|
|
384
|
+
|
|
385
|
+
# Rotate SSH key with Ed25519
|
|
386
|
+
tunnel.rotate_ssh_key("/path/to/new_ed25519_key", key_type="ed25519")
|
|
387
|
+
|
|
388
|
+
# Close the connection
|
|
389
|
+
tunnel.close()
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Deploy MCP Server as a Service
|
|
393
|
+
|
|
394
|
+
The MCP server can be deployed using Docker, with configurable authentication, middleware, and Eunomia authorization.
|
|
395
|
+
|
|
396
|
+
#### Using Docker Run
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
docker pull knucklessg1/tunnel-manager:latest
|
|
400
|
+
|
|
401
|
+
docker run -d \
|
|
402
|
+
--name tunnel-manager-mcp \
|
|
403
|
+
-p 8004:8004 \
|
|
404
|
+
-e HOST=0.0.0.0 \
|
|
405
|
+
-e PORT=8004 \
|
|
406
|
+
-e TRANSPORT=http \
|
|
407
|
+
-e AUTH_TYPE=none \
|
|
408
|
+
-e EUNOMIA_TYPE=none \
|
|
409
|
+
knucklessg1/tunnel-manager:latest
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
For advanced authentication (e.g., JWT, OAuth Proxy, OIDC Proxy, Remote OAuth) or Eunomia, add the relevant environment variables:
|
|
413
|
+
|
|
414
|
+
```bash
|
|
415
|
+
docker run -d \
|
|
416
|
+
--name tunnel-manager-mcp \
|
|
417
|
+
-p 8004:8004 \
|
|
418
|
+
-e HOST=0.0.0.0 \
|
|
419
|
+
-e PORT=8004 \
|
|
420
|
+
-e TRANSPORT=http \
|
|
421
|
+
-e AUTH_TYPE=oidc-proxy \
|
|
422
|
+
-e OIDC_CONFIG_URL=https://provider.com/.well-known/openid-configuration \
|
|
423
|
+
-e OIDC_CLIENT_ID=your-client-id \
|
|
424
|
+
-e OIDC_CLIENT_SECRET=your-client-secret \
|
|
425
|
+
-e OIDC_BASE_URL=https://your-server.com \
|
|
426
|
+
-e ALLOWED_CLIENT_REDIRECT_URIS=http://localhost:*,https://*.example.com/* \
|
|
427
|
+
-e EUNOMIA_TYPE=embedded \
|
|
428
|
+
-e EUNOMIA_POLICY_FILE=/app/mcp_policies.json \
|
|
429
|
+
knucklessg1/tunnel-manager:latest
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
#### Using Docker Compose
|
|
433
|
+
|
|
434
|
+
Create a `docker-compose.yml` file:
|
|
435
|
+
|
|
436
|
+
```yaml
|
|
437
|
+
services:
|
|
438
|
+
tunnel-manager-mcp:
|
|
439
|
+
image: knucklessg1/tunnel-manager:latest
|
|
440
|
+
environment:
|
|
441
|
+
- HOST=0.0.0.0
|
|
442
|
+
- PORT=8004
|
|
443
|
+
- TRANSPORT=http
|
|
444
|
+
- AUTH_TYPE=none
|
|
445
|
+
- EUNOMIA_TYPE=none
|
|
446
|
+
ports:
|
|
447
|
+
- 8004:8004
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
For advanced setups with authentication and Eunomia:
|
|
451
|
+
|
|
452
|
+
```yaml
|
|
453
|
+
services:
|
|
454
|
+
tunnel-manager-mcp:
|
|
455
|
+
image: knucklessg1/tunnel-manager:latest
|
|
456
|
+
environment:
|
|
457
|
+
- HOST=0.0.0.0
|
|
458
|
+
- PORT=8004
|
|
459
|
+
- TRANSPORT=http
|
|
460
|
+
- AUTH_TYPE=oidc-proxy
|
|
461
|
+
- OIDC_CONFIG_URL=https://provider.com/.well-known/openid-configuration
|
|
462
|
+
- OIDC_CLIENT_ID=your-client-id
|
|
463
|
+
- OIDC_CLIENT_SECRET=your-client-secret
|
|
464
|
+
- OIDC_BASE_URL=https://your-server.com
|
|
465
|
+
- ALLOWED_CLIENT_REDIRECT_URIS=http://localhost:*,https://*.example.com/*
|
|
466
|
+
- EUNOMIA_TYPE=embedded
|
|
467
|
+
- EUNOMIA_POLICY_FILE=/app/mcp_policies.json
|
|
468
|
+
ports:
|
|
469
|
+
- 8004:8004
|
|
470
|
+
volumes:
|
|
471
|
+
- ./mcp_policies.json:/app/mcp_policies.json
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
Run the service:
|
|
475
|
+
|
|
476
|
+
```bash
|
|
477
|
+
docker-compose up -d
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
#### Configure `mcp.json` for AI Integration
|
|
369
481
|
|
|
370
|
-
Configure `mcp.json`
|
|
371
482
|
```json
|
|
372
483
|
{
|
|
373
484
|
"mcpServers": {
|
|
@@ -398,23 +509,10 @@ Configure `mcp.json`
|
|
|
398
509
|
}
|
|
399
510
|
}
|
|
400
511
|
```
|
|
512
|
+
</details>
|
|
401
513
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
docker pull knucklessg1/tunnel-manager:latest
|
|
405
|
-
```
|
|
406
|
-
|
|
407
|
-
Modify the `compose.yml`
|
|
408
|
-
```yaml
|
|
409
|
-
services:
|
|
410
|
-
tunnel-manager:
|
|
411
|
-
image: knucklessg1/tunnel-manager:latest
|
|
412
|
-
environment:
|
|
413
|
-
- HOST=0.0.0.0
|
|
414
|
-
- PORT=8021
|
|
415
|
-
ports:
|
|
416
|
-
- 8021:8021
|
|
417
|
-
```
|
|
514
|
+
<details>
|
|
515
|
+
<summary><b>Installation Instructions:</b></summary>
|
|
418
516
|
|
|
419
517
|
### Install Python Package
|
|
420
518
|
```bash
|