From ad4c84322816ba6cf5f9ec31db96b99392e33018 Mon Sep 17 00:00:00 2001 From: Matteo Bunino <48362942+matbun@users.noreply.github.com> Date: Fri, 16 Oct 2026 20:34:40 +0200 Subject: [PATCH 1/5] docs: the reverse tunnel of the ssh shadow A section in the SSH tunnel guide (how it works, what the site has to allow, the annotations, SOCKS for undeclared endpoints, who else on the node can use the forwards, limits, troubleshooting), the Reverse options in the options table, and the interlink.eu/reverse-* annotations in the pod annotations reference. The note saying the ssh shadow gives the pod no way back into the cluster is updated. Part of #548 Co-Authored-By: Claude Fable 5.1 Signed-off-by: Matteo Bunino <48362942+matbun@users.noreply.github.com> --- docs/docs/guides/09-pod-annotations.mdx | 96 +++++++++++++ .../guides/14-ssh-tunnel-configuration.mdx | 128 +++++++++++++++++- 2 files changed, 220 insertions(+), 4 deletions(-) diff --git a/docs/docs/guides/09-pod-annotations.mdx b/docs/docs/guides/09-pod-annotations.mdx index 33fa91cd..9bbcb776 100644 --- a/docs/docs/guides/09-pod-annotations.mdx +++ b/docs/docs/guides/09-pod-annotations.mdx @@ -16,6 +16,7 @@ InterLink supports several categories of annotations: - **[Mesh Networking](#mesh-networking)**: Control bidirectional mesh networking for offloaded pods - **[Wstunnel Integration](#wstunnel-integration)**: Control websocket tunneling for exposed ports - **[SSH Shadow](#ssh-shadow)**: Unix socket ports and namespace placement for shadow pods +- **[SSH Reverse Tunnel](#ssh-reverse-tunnel)**: Let an offloaded pod reach endpoints inside the cluster over the SSH shadow - **[Job Management](#job-management)**: Handle remote job execution and tracking - **[System Annotations](#system-annotations)**: Internal annotations used by interLink components @@ -308,6 +309,101 @@ metadata: --- +## SSH Reverse Tunnel + +With the [SSH shadow](./14-ssh-tunnel-configuration.mdx) and +`Network.SSH.Reverse.Enabled: true`, these annotations let an offloaded pod open +connections to endpoints inside the cluster. How it works, what the site has to allow +and the limits are in +[Pod to cluster: the reverse tunnel](./14-ssh-tunnel-configuration.mdx#pod-to-cluster-the-reverse-tunnel). + +### `interlink.eu/reverse-forwards` + +Lists the cluster endpoints the pod may connect to. + +**Usage:** +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: trainer + annotations: + interlink.eu/reverse-forwards: "minio.user.svc.cluster.local:9000 6443:kubernetes.default.svc.cluster.local:443" +spec: + containers: + - name: trainer + image: docker://python:3.12 +``` + +**Format:** +- **Endpoint**: `host:port` - the job connects to the same port +- **Remapped**: `listen-port:host:port` - the job connects to `listen-port`; needed when `port` is below 1024 +- **Several**: space-separated + +**Behavior:** +- The virtual kubelet adds the names to the container's `/etc/hosts` and waits for the tunnel before the workload starts +- A Service FQDN also resolves as `name.namespace.svc` and `name.namespace`, and as `name` in the pod's own namespace +- An entry that does not parse, or a listen port below 1024, is refused when the pod is created +- Needs `Network.SSH.Reverse.Enabled: true`; otherwise the pod is refused rather than run without its tunnel + +**Default:** Not set (no connections back into the cluster) + +--- + +### `interlink.eu/reverse-socks-port` + +Adds a SOCKS5 proxy for endpoints not listed in `interlink.eu/reverse-forwards`. + +**Usage:** +```yaml +metadata: + annotations: + interlink.eu/reverse-socks-port: "1080" +``` + +**Behavior:** +- Any cluster address, resolved inside the cluster at connect time, for programs told to use the proxy (`ALL_PROXY=socks5h://:1080`) +- A plain loopback listener: every user of the compute node can use it +- Must be above 1023 and not clash with a forward's listen port + +**Default:** Not set (no proxy) + +--- + +### `interlink.eu/reverse-bind` + +The `127.x.y.z` address the forwards listen on inside the job. + +**Behavior:** +- Derived from the pod UID when unset, so two pods on one node never share it +- Must be in `127.0.0.0/8` and not `127.0.0.1` + +**Default:** Derived from the pod UID + +--- + +### `interlink.eu/reverse-node-exec` + +How the shadow runs a command on the compute node from the login node, for this pod. + +**Format:** `ssh` (`ssh `) or `srun` (`srun --jobid= --overlap`) + +**Default:** `Network.SSH.Reverse.NodeExec` + +--- + +### `interlink.eu/reverse-owner-only` + +Whether the forwards can be used by the job's user only. + +**Behavior:** +- `true`: each forward ends in a unix socket only that user can open, with a relay in front that checks the connecting user; needs `python3` on the compute node +- `false`: the ports are bound directly, open to every user of the compute node + +**Default:** `true` + +--- + ## Job Management ### `JobID` diff --git a/docs/docs/guides/14-ssh-tunnel-configuration.mdx b/docs/docs/guides/14-ssh-tunnel-configuration.mdx index ef19c0bd..0dbe3339 100644 --- a/docs/docs/guides/14-ssh-tunnel-configuration.mdx +++ b/docs/docs/guides/14-ssh-tunnel-configuration.mdx @@ -25,10 +25,11 @@ configuration, no pre-exec injection. :::info The SSH shadow replaces **wstunnel**, not [full mesh](./13-mesh-network-configuration.mdx). -It exposes the offloaded pod's ports to the cluster; it does not give the pod access -back into the cluster, so an offloaded workload still cannot reach in-cluster object -storage or message buses. Combining the two is rejected at startup and tracked in -[#548](https://github.com/interlink-hq/interLink/issues/548). +It exposes the offloaded pod's ports to the cluster. A workload that needs the other +direction, in-cluster object storage or a message bus for example, gets it over the same +login node with the [reverse tunnel](#pod-to-cluster-the-reverse-tunnel), without +WireGuard and without a network namespace. Combining the SSH shadow with full mesh is +rejected at startup. ::: --- @@ -128,6 +129,7 @@ warning in the virtual kubelet log. | --- | --- | --- | --- | | `wstunnel` (default) | cluster → pod | `EnableTunnel` + exposed ports | wstunnel client, dials out | | `ssh` | cluster → pod | `EnableTunnel` + exposed ports | nothing | +| `ssh` reverse | pod → cluster | `SSH.Reverse.Enabled` + `interlink.eu/reverse-forwards` | nothing: the batch script waits for the tunnel | | full mesh | bidirectional | `FullMesh: true`, every pod | `mesh.sh` (slirp4netns + WireGuard) | --- @@ -220,6 +222,10 @@ in the chart repository for a complete deployment. | `ReplicateCredentials` | `true` | Copy the credential into each shadow's namespace | | `NodeWaitTimeout` | `2h` | How long the shadow waits for the compute node | | `ExtraOptions` | `[]` | Extra ssh options, each passed as `-o