Part 2: How to use TokenRequest API and TokenVolume Projection in Kubernetes?
Kubernetes has an API that lets you do CRUD tasks on the cluster.
What can I do with the API?
You may delete a pod. You may list pods in a namespace. You may list the namespaces in the cluster and so on.
Let’s deploy a pod:
00-pod.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: web-pod
spec:
containers:
- image: nginx
name: web-container
Apply and get into the shell:
➜ ~ kubectl apply -f 00-pod.yaml
pod/web-pod created
➜ ~ kubectl exec -it web-pod -- /bin/bash
root@web-pod:/#
I want to use the Kubernetes API to get a list of all the pods in the default namespace. (Here’s the reference).
You can use the kubernetes.default.svc domain to access the Kubernetes API.
Let’s try:
root@web-pod:/# curl -k https://kubernetes.default.svc/api/v1/namespaces/default/pods
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "pods is forbidden: User \"system:anonymous\" cannot list resource \"pods\" in API group \"\" in the namespace \"default\"",
"reason": "Forbidden",
"details": {
"kind": "pods"
},
"code": 403
}
To access the API, we must have a token. Kubernetes API assumed the request came from an Anonymous System User because we didn’t send a token.
To make calls to the Kubernetes API, we need to have a Service Account
If you want to access the Kubernetes API via kubectl, you don’t need to create a service account.
Get all pods in the default namespace:
Get the web-pod in the default namespace:
Default Service Account
A service account is generated automatically whenever a Kubernetes cluster is created. It’s called default
service account:
➜ ~ kubectl get serviceaccounts
NAME SECRETS AGE
default 0 28m
The default service account is automatically attached to the pod.
A token for the default
service account is automatically created. The token is added to the pod automatically as a file:
The file token
is there. Let’s use the token to call the Kubernetes API:
curl -k --header "Authorization: Bearer ${token}" https://kubernetes.default.svc/api/v1/namespaces/default/pods
Similar to the above error. However, now, Kubernetes API can recognize our user: default
This is because the default service account does not have the right permissions to list the pods in the default namespace.
Let’s not change anything and instead set up a new service account.
01-service-account.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: sa-account-blog
namespace: default
Apply:
➜ ~ kubectl apply -f 01-service-account.yaml
serviceaccount/sa-account-blog created
➜ ~ kubectl get serviceaccounts
NAME SECRETS AGE
default 0 43m
sa-account-blog 0 10s
In Kubernetes, a Service account is used for authentication, and a Role is used for authorization.
We have to create a role.
02-role.yaml
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: sa-role-blog
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
Apply:
➜ ~ kubectl apply -f 02-role.yaml
role.rbac.authorization.k8s.io/sa-role-blog created
There are two kinds of roles in Kubernetes: Role and ClusterRole
Role is valid for a particular namespace (in our case, default
)
ClusterRole is valid across all namespaces.
The role sa-role-blog
needs to be attached to the user sa-account-blog
. We need a RoleBinding for this:
03-role-binding.yaml
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: role-binding-blog
namespace: default
subjects:
- kind: ServiceAccount
name: sa-account-blog
namespace: default
roleRef:
kind: Role
name: sa-role-blog
apiGroup: rbac.authorization.k8s.io
Apply:
➜ ~ kubectl apply -f 03-role-binding.yaml
rolebinding.rbac.authorization.k8s.io/role-binding-blog created
➜ ~ kubectl get rolebindings -o wide
NAME ROLE AGE USERS GROUPS SERVICEACCOUNTS
role-binding-blog Role/sa-role-blog 33s default/sa-account-blog
We can now use the service account sa-account-blog
. Let’s deploy another pod with the new service account:
04-pod.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: web-pod-with-sa
spec:
serviceAccountName: sa-account-blog
containers:
- image: nginx
name: web-container
Apply:
➜ ~ kubectl apply -f 04-pod.yaml
pod/web-pod-with-sa created
The service account is attached to the pod:
Let’s get into the shell and test the token:
We can call the Kubernetes API with the token.