Curl and Kubernetes

A quicky...

Curl is an amazing tool that every IT enthusiast should use. From debugging to quick testing and troubleshooting, curl provides huge flexibility that allow us to test requests made to HTTP servers.

Kubernetes exposes a REST API that we can interact with. However, there are some security layers in place and it is perhaps very valuable to know how to work with the Kubernetes API properly with a tool like curl.

Of course, the kubectl command helps us to not have all that intimate knowledge of the API or how to parse the output - it's all done for us. Also, the various clients serves a similar purpose while using your favorite language. Still, knowing how to troubleshoot something with curl is an invaluable skill and I thought it would be worth the effort to demonstrate the basics of getting going with using curl to interact with the Kubernetes API.

Curl and Mutual TLS Authentication

Getting authenticated

I am starting to play a little more with the Kubernetes API and tried to figure out how to do this with curl.

On Linux (Ubuntu 20.04), using zsh, I found the following to work fairly nice. But first a couple of important notes:

First, get all the certs:

cat $FILE | yq '.clusters[0].cluster."certificate-authority-data"' | sed -e 's/^"//' -e 's/"$//' | base64 -d - > ~/.kube/curl_ca.pem

cat $FILE | yq '.users[0].user."client-certificate-data"' | sed -e 's/^"//' -e 's/"$//' | base64 -d - > ~/.kube/curl_user.pem

cat $FILE | yq '.users[0].user."client-key-data"' | sed -e 's/^"//' -e 's/"$//' | base64 -d - > ~/.kube/curl_user-key.pem

chmod 600 ~/.kube/curl*

The test

Next, I created an alias:

alias kubecurl='curl --cert $HOME/.kube/curl_user.pem --key $HOME/.kube/curl_user-key.pem --cacert $HOME/.kube/curl_ca.pem -v -XGET  -H "Accept: application/json;as=Table;v=v1;,application/json;as=Table;v=v1beta1;,application/json" -H "User-Agent: kubectl/v1.23.4 (linux/amd64) kubernetes/e6c093d" '

And then a simple test:

kubecurl https://$K_HOST:$K_PORT/api/v1/namespaces

And boooom! I have access to the Kubernetes API.

Using a ServiceAccount Token

Creating a Service Account

Another way is to use a JWT token. A JWT token can be created/obtained using a Service Account.

I used the following configuration in a file called admin_serviceaccount.yaml to test:

apiVersion: v1
kind: ServiceAccount
  name: adminprime-serviceaccount
  namespace: default
kind: ClusterRole
  name: adminprime-clusterrole
- apiGroups: [""]
  resources: ["*"]
  verbs: ["*"]
kind: ClusterRoleBinding
  name: adminprime-global-clusterrolebinding
- kind: ServiceAccount
  name: adminprime-serviceaccount
  namespace: default
  kind: ClusterRole
  name: adminprime-clusterrole

I applied it with the command:

kubectl apply -f admin_serviceaccount.yaml -n default

Obtaining the JWT Token and Testing

To obtain the JWT token, I ran the following command:

export JWT_TOKEN=$(kubectl get secrets $(kubectl get serviceaccount adminprime-serviceaccount -n default -o jsonpath='{.secrets[0].name}') -o jsonpath='{.data.token}' | base64 --decode)

To update the kubecurl alias, run the following:

alias kubecurl='curl -H "Authorization: Bearer $JWT_TOKEN" --cacert $HOME/.kube/curl_ca.pem -v -XGET  -H "Accept: application/json;as=Table;v=v1;,application/json;as=Table;v=v1beta1;,application/json" -H "User-Agent: kubectl/v1.23.4 (linux/amd64) kubernetes/e6c093d" '

The simple test should still yield the same result as before:

kubecurl https://$K_HOST:$K_PORT/api/v1/namespaces

Bonus Swag

As a bonus, you can also dump the Swagger (OpenAPI v2):

kubecurl https://$K_HOST:$K_PORT/openapi/v2 > openapi.json

In VSCode, the extension "Swagger Viewer" is able to open and render the Swagger file

Further reading and other resources

Below is a great video going into yet more detail - presented by Joe Thompson: "A Basic Kubernetes Debugging Kit: curl, jq, openssl, and Other Best Friends"