Writing a kubectl ssh plugin

28 Feb 2023 12:54 kubernetes

In this post, I showed how to access the Erlang console via SSH using kubectl port-forward.

kubectl --namespace erlclu port-forward deployment/erlclu 10022:22 &
ssh -p 10022 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null localhost

This works for any pod running an SSH daemon, incidentally.

But it’s a bunch of typing (or copy-pasting). It would be nice if it was a single command. In fact, it would be awesome if it was a kubectl plugin, so that we could run it as kubectl ssh POD. Here’s how.

Hello kubectl

To implement a kubectl plugin – for example kubectl hello, you just put kubectl-hello somewhere in $PATH. It can be written in anything. Here’s kubectl-hello:

#!/usr/bin/env bash
echo "Hello kubectl!"
$ kubectl hello
Hello kubectl!

kubectl ssh

Create the kubectl-ssh script as follows:

#!/usr/bin/env bash

exec 3< <(kubectl port-forward "$@" 0:22)

# When the script exits, kill the port-forward process
pid=$!
trap "kill $pid" EXIT

# Find out which port number was used
read <&3 -r line

re='^Forwarding from .*:([0-9]+) -> 22$'
if [[ $line =~ $re ]]; then
    port="${BASH_REMATCH[1]}"

    # Use ssh to connect to the local port; disable host key checking
    ssh -p "$port" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null localhost
else
    exit 1
fi

Mark it as executable and put it somewhere in $PATH.

Of interest:

  • It passes "$@", so that any other arguments are passed to kubectl port-forward as-is.
  • You can pass anything that kubectl port-forward will accept, not just pods, so it’ll work as kubectl ssh deployment/whatever, etc.
  • It uses 0 as the local port; this causes kubectl port-forward to pick an arbitrary local port.
  • We use redirection to fd 3 (and the following read from fd 3) to capture the chosen local port.
  • Because ssh thinks we’re connecting to localhost, it’ll complain that the host key keeps changing, so we disable that with the -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null options. This makes it less secure against MITM attacks, however.

Tab completion

Since v1.26.0 (so you might need to upgrade), kubectl supports tab completion for plugins, and we can take advantage of that. Create a kubectl_complete-ssh script as follows (and chmod +x and put it in $PATH):

#!/bin/sh

exec kubectl __complete port-forward "$@"

We take advantage of the fact that our tab completion is identical to that of kubectl port-forward, and that kubectl has a hidden __complete command.

If you’re on WSL, you need to be aware of kubectl#1336.