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:
- I am connecting to a k3s cluster (see post from yesterday).
- From creating the Kubernetes cluster, there is only one cluster and user in my
k3s.conf
file - if you use a more standard file with a couple of clusters and users, you may have to adapt your approach accordingly - I will assume the exact location of the config file is in
$FILE
- I assume the Kubernetes host is in
$K_HOST
and the port in$K_PORT
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;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,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
metadata:
name: adminprime-serviceaccount
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: adminprime-clusterrole
rules:
- apiGroups: [""]
resources: ["*"]
verbs: ["*"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: adminprime-global-clusterrolebinding
subjects:
- kind: ServiceAccount
name: adminprime-serviceaccount
namespace: default
roleRef:
kind: ClusterRole
name: adminprime-clusterrole
apiGroup: rbac.authorization.k8s.io
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;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,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¶
- How To Call Kubernetes API using Simple HTTP Client - similar content, but with a lot more detail!
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"