Kubernetes tunnel
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
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.
| Flag | What it does |
|---|---|
--namespace=shop | A single namespace only. Cluster-scoped resources (nodes, the namespace list), -A and other namespaces are denied. The namespace object itself is read-only |
--read-only | Reads only (GET, HEAD, OPTIONS). exec, attach and port-forward are denied; logs and pods/proxy are allowed |
--no-delete | Deleting is denied, other writes are allowed |
--deny-resource=secrets,configmaps | The listed resources are denied, names are case-insensitive |
--deny-subresource=exec,attach | Denied 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:
| Preset | What is allowed |
|---|---|
view | Reads only, no secrets, no exec, attach, portforward or proxy |
observer | Reads of pods and their logs only, no exec, attach, portforward or proxy |
debug | Everything except deleting. secrets are not hidden: exec gets to them anyway |
open | No 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