cURLing the Kubernetes API server
What I learned today — 14 June 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!