
Kubernetes management is abstracted via a rest API, which is served over a self signed secure connection. Frequently people run into issues when accessing this rest API because of TLS issues, in this case it can be useful to debug your connection with curl, as it will provide a detailed explanation of what is going wrong with your connection.
To have a grasp understanding on how authentication is taking place in kubernetes we will be creating a new service account with the required permission to perform our test with kubernetes.
Kubernetes is using a role based access system
Role Based Access – The Theory
Before we dive too deep, lets first understand the three pieces in a Kubernetes cluster that are needed to make role based access work. These are Subjects, Resources, and Verbs.
- Subjects – Users or processes that need access to the Kubernetes API.
- Resources – The k8s API objects that you’d grant access to
- Verbs – List of actions that can be taken on a resource
These three items listed above are used in concert to grant permissions such that a user (Subject) is allowed access to take an action (verb) on an object (Resource).
Now we need to look at how we tie these three items together in Kubernetes. The first step will be to create a Role or a ClusterRole. Now both of these roles will be used to tie the Resources together with a Verb, the difference between them is that a Role is used at a namespace level whereas a ClusterRole is for the entire cluster.
Once you’ve created your Role or your Cluster Role, you’ve tied the Resource and Verb together and are only missing the Subject now. To tie the Subject to the Role, a RoleBinding or ClusterRoleBinding is needed. As you can guess the difference between a RoleBinding or a ClusterRoleBinding is whether or not its done at the namespace or for the entire Cluster, much like the Role/ClusterRole described above.
It should be noted that you can tie a ClusterRole with a RoleBinding that lives within a namespace. This enables administrators to use a common set of roles for the entire cluster and then bind them to a specific namespace for use.
So for the creation of our user account, we will create a ServiceAccount, ClusterRole and RoleBinding .
$ kubectl create serviceaccount my-service-account
Now we need to create a ClusterRole which will grant us the necessary permissions on our kubernetes cluster.
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 my-service-account:log-reader --clusterrole log-reader --serviceaccount default:my-service-account
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=my-service-account #-- 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.