The Kubernetes API call is coming from inside the cluster!

Sometimes its useful to access the Kubernetes API from inside of a Pod. Kubernetes attempts to make this easier by mounting a serviceaccount secret to each pod.

To explore this I have created a Kubernetes cluster using minikube and started an interactive alpine Linux pod:

$ minikube start
$ kubectl run -i --tty alpine --image=alpine --restart=Never -- sh
/ #

You will find several files in the path /var/run/secrets/ that can be used to authenticate to the Kubernetes API (an auth token, a ca certificate and a namespace):

/ # ls /var/run/secrets/
ca.crt namespace token
/ # cat /var/run/secrets/

However none of these files provide the URL of the Kubernetes API, thankfully this is available via environment variables:

/ # env | grep KUBE

Using a combination of these you will be able to authenticate and access the Kubernetes API. Unfortunately the wget that ships with alpine cannot access TLS endpoints so you’ll need to have curl or similar installed before you can access it:

/ # apk update
v3.7.0-46-g1061d3a8d5 []
v3.7.0-45-g32b1d3363c []
OK: 9046 distinct packages available
/ # apk add curl
(1/4) Installing ca-certificates (20171114-r0)
(2/4) Installing libssh2 (1.8.0-r2)
(3/4) Installing libcurl (7.57.0-r0)
(4/4) Installing curl (7.57.0-r0)
Executing busybox-1.27.2-r6.trigger
Executing ca-certificates-20171114-r0.trigger
OK: 6 MiB in 15 packages

With curl installed into our alpine container we can do some very basic API operations to find out information.

/ # TOKEN=$(cat /var/run/secrets/
/ # CACERT=/var/run/secrets/
/ # NAMESPACE=$(cat /var/run/secrets/
/ # curl -H "Authorization: Bearer $TOKEN" --cacert $CACERT $K8S/healthz
/ #

You can check to see if a service exists by asking curl to just provide the http code (200 exists, 404 doesn’t exist) which you can easily use in a while loop or as a test in a bash script:

/ # curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $TOKEN" --cacert $CACERT \
/ #/ # curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $TOKEN" --cacert $CACERT $K8S/api/v1/namespaces/$NAMESPACE/services/not-a-real-service

If you have jq installed (run apk add jq if you want to try this) you can parse the API response to get interesting information, for instance to get the IP of a given Pod:

/ # curl -s -H "Authorization: Bearer $TOKEN" \
--cacert $CACERT $K8S/api/v1/namespaces/$NAMESPACE/pods/alpine \
| jq -r ".status.podIP"

Using curl to access the Kubernetes API can be fine for basic stuff but you may need to construct more complex API queries in which case you may want to look at writing a small go binary to do your bidding or install kubectl inside your pod which knows how to use the serviceaccount secret to talk to the API.

I’ve found this to be super useful when trying to get a piece of shi^H^H^H^H^H^H legacy application working inside Kubernetes, or to create while loops in an init container to wait for a another pod or service to be set up before starting the application itself.