cURLing the Kubernetes API server

What I learned today — 14 June 2018

Niel de Wet
2 min readJun 14, 2018

Kubernetes is an entirely API-based system. Exploring an API before building an application on it is always easier with simple tools like cURL or Postman.

To interact with the Kubernetes API you need a ServiceAccount with the correct permissions, obtained through a (Cluster)Role and a RoleBinding. Authenticate by using the ServiceAccount’s token. Since all communication is over TLS you also need the self-signed certificate. Alternatively, allow insecure connections, but this is not recommended.

Create a ServiceAccount, ClusterRole and RoleBinding

First, create a ServiceAccount.

kubectl create serviceaccount api-explorer

Create a (Cluster)Role granting access to the necessary resources. I prefer ClusterRoles for roles that are reusable across the system. In this example I grant access to pods and their logs, which we’ll use in an example use case later.

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name:
log-reader
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["pods", "pods/log"]
verbs: ["get", "watch", "list"]

Bind the ClusterRole to the ServiceAccount in the current namespace (eg. ‘default’).

kubectl create rolebinding api-explorer:log-reader --clusterrole log-reader --serviceaccount default:api-explorer

Get the Bearer Token, Certificate and API Server URL

Get the token and certificate from the ServiceAccount’s token secret for use in your API requests. This script relies on the swiss army knife of JSON parsing on the command line, jq. Start by setting the SERVICE_ACCOUNT variable.

SERVICE_ACCOUNT=api-explorer# Get the ServiceAccount's token Secret's name
SECRET=$(kubectl get serviceaccount ${SERVICE_ACCOUNT} -o json | jq -Mr '.secrets[].name | select(contains("token"))')
# Extract the Bearer token from the Secret and decode
TOKEN=$(kubectl get secret ${SECRET} -o json | jq -Mr '.data.token' | base64 -d)
# Extract, decode and write the ca.crt to a temporary location
kubectl get secret ${SECRET} -o json | jq -Mr '.data["ca.crt"]' | base64 -d > /tmp/ca.crt
# Get the API Server location
APISERVER=https://$(kubectl -n default get endpoints kubernetes --no-headers | awk '{ print $2 }')

Explore the API

You can see the API documentation at /openapi/v2

curl -s $APISERVER/openapi/v2  --header "Authorization: Bearer $TOKEN" --cacert /tmp/ca.crt | less

Use case: Get pod logs

To get the logs of a pod, first list all the pods. Select only the names with the JsonPath .items[].metadata.name.

curl -s $APISERVER/api/v1/namespaces/default/pods/ --header "Authorization: Bearer $TOKEN" --cacert /tmp/ca.crt | jq -rM '.items[].metadata.name'

Insert the desired pod name into the request path.

curl -s $APISERVER/api/v1/namespaces/default/pods/nginx-5dc7fbd98-hvv6s/log  --header "Authorization: Bearer $TOKEN" --cacert /tmp/ca.crt

That’s it! You can now explore the API using your favourite tool without proxying the server or any other tricks. Remember to assign roles as needed to access various resources.

Thanks to Daisuke Maki for the inspiration!

--

--