Skip to main content

Kubernetes tunnel

info

Available only with a subscription.

Overview​

A Kubernetes tunnel gives a colleague or a contractor temporary access to your cluster with plain kubectl: no VPN, no exposing the API server, no sharing your credentials.

The client reads your local kubeconfig, starts a reverse proxy to the API server and an HTTP tunnel to it. The guest gets a one-time link to a ready kubeconfig. It contains the tunnel address with a valid TLS certificate and a guest token. The proxy checks the token and replaces it with your real credentials, so they never leave your machine.

Quick start​

tuna kubernetes --context=staging --service-account=shop/debug --ttl=4h

The client opens a terminal UI: the header shows the service account, namespace, restrictions and expiry, below is the feed of guest requests. Instructions for the guest:

curl -sfO https://<tunnel address>/tuna/<secret>/kubeconfig.yaml
KUBECONFIG=./kubeconfig.yaml kubectl get pods

get, list, watch, logs, exec (including stdin), port-forward, pods/proxy and writes such as scale, create, delete work through the tunnel. Guest requests are shown in the inspector as regular HTTP requests.

The command has a short alias tuna k8s.

Examples​

note

All current flags, hints and examples are available in the help:

tuna kubernetes --help

Almost every flag has a matching environment variable.

Kubeconfig and context​

The client uses a single kubeconfig file: from the --kubeconfig flag, otherwise from $KUBECONFIG, otherwise ~/.kube/config. A :-separated list of files in $KUBECONFIG is not supported. The default context is current-context:

tuna kubernetes --kubeconfig=./staging.yaml --context=staging

Client certificates, token, tokenFile and exec plugins that return a token are supported. Exec plugins that return a certificate are not supported. With auth-provider the client exits with an error.

Service account​

Without --service-account the guest acts with your cluster permissions, and the client warns about it. Create a service account with minimal RBAC permissions for the guest and pass it in the flag:

tuna kubernetes --service-account=shop/debug

The format is [namespace/]name. Without a namespace the context namespace is used, or default if there is none. The client issues the service account token itself via the TokenRequest API and renews it every hour.

Access restrictions​

The restrictions below work on top of RBAC and only narrow permissions, never extend them.

FlagWhat it does
--namespace=shopA single namespace only. Cluster-scoped resources (nodes, the namespace list), -A and other namespaces are denied. The namespace object itself is read-only
--read-onlyReads only (GET, HEAD, OPTIONS). exec, attach and port-forward are denied; logs and pods/proxy are allowed
--no-deleteDeleting is denied, other writes are allowed
--deny-resource=secrets,configmapsThe listed resources are denied, names are case-insensitive
--deny-subresource=exec,attachDenied subresources: exec, attach, portforward, log, proxy

With --namespace and --read-only, kubectl auth whoami and kubectl auth can-i do not work: they are POST requests to cluster-scoped resources.

The proxy strips Impersonate-* headers, so kubectl --as does not work through the tunnel.

Presets​

--preset enables a ready set of restrictions:

PresetWhat is allowed
viewReads only, no secrets, no exec, attach, portforward or proxy
observerReads of pods and their logs only, no exec, attach, portforward or proxy
debugEverything except deleting. secrets are not hidden: exec gets to them anyway
openNo extra restrictions
tuna kubernetes --preset=debug --namespace=shop

A preset and flags add up and never weaken each other: --preset=debug --read-only gives reads only.

The observer preset allows only pods, so kubectl logs deploy/api fails; point at a pod instead: kubectl logs pod/api-7c9f8d6b5-x2k4q.

Lifetime and download limit​

tuna kubernetes --ttl=4h --download-limit=1

--ttl sets how long the access stays valid, 0 (the default) means no limit. After it expires kubectl gets this access has expired, ask for a new link.

--download-limit limits kubeconfig downloads, 1 by default, 0 removes the limit. Beyond the limit the link responds with 410, and you see a warning about the download attempt in the log. If the guest gets 410 on the very first download, someone else took the kubeconfig first: stop the tunnel and issue a new link.

Permanent address​

When the tunnel reconnects with a new address, the client issues a new token and a new link, and the lifetime and the download limit start over. To keep the address, use a reserved subdomain or your own domain:

tuna kubernetes --subdomain=k8s-staging
tuna kubernetes --domain=k8s.example.com

Guest tokens live only in the process memory: after the client restarts, old links and kubeconfigs stop working.

Specifying a token​

You can specify a particular token using the --token flag or the TUNA_TOKEN environment variable. Overriding follows the configuration ordering policy.

tuna kubernetes --token=tt_***

Specifying a connection region​

You can specify a particular region using the --location/-l flag or the TUNA_LOCATION environment variable. Overriding follows the configuration ordering policy.

tuna kubernetes --location=nl

Running as a service​

The tunnel can run as a service or with multiple tunnel startup:

tuna service install --name=k8s-staging -- tuna kubernetes --context=staging --service-account=shop/debug --subdomain=k8s-staging