Skip to content

Kubernetes and SSH Tunneling

The dapcli Kubernetes module provides a secure proxy mechanism for executing kubectl commands and managing cluster resources from an operator’s laptop, which typically lacks direct network access to the cluster’s pod CIDR. This is achieved by tunneling SSH traffic through a management host to an Incus-managed VM (the “runner”) that resides on the cluster network. The module abstracts the complexity of this multi-hop execution chain, handling SSH configuration, argument quoting to prevent shell mangling, and resource lifecycle management for port forwards.

The execution path involves three distinct layers: the local CLI, the remote management host, and the isolated runner VM. The CLI initiates an SSH connection to the management host, which then executes an incus exec command to run a shell inside the designated VM. All kubectl operations are performed within this VM environment.

diagram

Access parameters for the runner environment are defined in the RunnerConfig dataclass, which is frozen to ensure immutability. Configuration is primarily driven by environment variables, which can be initialized via dap config init. The default values assume a standard Ed25519 key and a VM named dap-runner.

  • DAP_RUNNER_SSH_HOST: The SSH target for the management host (default: user@mgmt.example.com).
  • DAP_RUNNER_SSH_KEY: Path to the SSH private key (default: ~/.ssh/id_ed25519).
  • DAP_RUNNER_VM: The name of the Incus VM to target (default: dap-runner).

The RunnerConfig.from_env() class method retrieves these values, expanding the SSH key path to an absolute path via Path.expanduser() 1.

Directly passing argument lists to SSH is problematic because SSH concatenates all arguments following the host specification with spaces. This behavior can mangle kubectl flags (e.g., -n might be interpreted by the remote shell rather than kubectl), leading to silent failures or help output.

To mitigate this, the module uses shlex.quote() to properly escape each argument before joining them into a single string payload. The run_in_runner function constructs the remote command as incus exec <vm_name> -- bash -lc <quoted_command>. The kubectl_in_runner helper wraps this by formatting the kubectl command with pre-quoted arguments.

For services requiring persistent connections, the port_forward context manager opens a kubectl port-forward process inside the runner VM. It yields the local port on the runner (not the operator’s laptop) and ensures the process is killed upon exiting the context 2.

For one-off HTTP requests, runner_curl executes curl inside the runner. It parses the HTTP status code from the output and returns the body separately, allowing callers to handle responses without parsing raw shell output.