This tutorial will guide you through the process of creating the service account, role, role binding and secret to have API access to the Kubernetes cluster using long lived token.
The best and recommended way to allow API access to the Kubernetes cluster is through service accounts with long lived tokens following the principle of least privilege (PoLP).
Use Cases
Following are the example use cases of Kubernetes service account for external API access.
- Allowing third-party monitoring tools to access Kubernetes data
- External applications to access kubernetes resources.
Now, why would you need this access?
Lets take an example of Prometheus monitoring stack.
Prometheus needs read access to cluster API to get information from metrics server, read pods, etc.
When you deploy Prometheus, you add cluster read permissions to the default service account where the Prometheus pods are deployed. This way, Prometheus pods get read access to cluster resources.
Setup Kubernetes API Access Using Service Account Token
Follow the steps given below to create a service account token for API access.
Step 1: Create service account in a namespace
We will create a service account in a custom namespace rather than the default namespace for demonstration purposes.
Create a devops-tools
namespace.
kubectl create namespace devops-tools
Create a service account named “api-service-account
” in devops-tools
namespace
kubectl create serviceaccount api-service-account -n devops-tools
or use the following manifest.
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
name: api-service-account
namespace: devops-tools
EOF
Step 2: Create a Cluster Role
Assuming that the service account needs access to the entire cluster resources, we will create a cluster role with a list of allowed access.
Create a clusterRole named api-cluster-role
with the following manifest file.
cat <<EOF | kubectl apply -f - --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: api-cluster-role namespace: devops-tools rules: - apiGroups: - "" - apps - autoscaling - batch - extensions - policy - rbac.authorization.k8s.io resources: - pods - componentstatuses - configmaps - daemonsets - deployments - events - endpoints - horizontalpodautoscalers - ingress - jobs - limitranges - namespaces - nodes - pods - persistentvolumes - persistentvolumeclaims - resourcequotas - replicasets - replicationcontrollers - serviceaccounts - services verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] EOF
The above YAML declaration has a ClusterRole
with full access to all cluster resources and a role binding to “api-service-account
“.
It is not recommended to create a service account with all cluster component access without any requirement.
To get the list of available API resources execute the following command.
kubectl api-resources
Step 3: Create a CluserRole Binding
Now that we have the ClusterRole and service account, it needs to be mapped together.
Bind the cluster-api-role
to api-service-account
using a RoleBinding
cat <<EOF | kubectl apply -f -
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: api-cluster-role-binding
subjects:
- namespace: devops-tools
kind: ServiceAccount
name: api-service-account
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: api-cluster-role
EOF
Step 4: Validate Service Account Access Using kubectl
To validate the clusterrole binding, we can use can-i
commands to validate the API access assuming a service account in a specific namespace.
For example, the following command checks if the api-service-account
in the devops-tools
namespace can list the pods.
kubectl auth can-i get pods --as=system:serviceaccount:devops-tools:api-service-account
Here is another example, to check if the service account has permissions to delete deployments.
kubectl auth can-i delete deployments --as=system:serviceaccount:devops-tools:api-service-account
Step 5: Associate a Secret With Service Account
To use a service account with an HTTP call, you need to have the long lived token associated with the service account. A long-lived token in Kubernetes is an authentication token that does not expire quickly, allowing continuous access to the Kubernetes API for an extended period.
For that, you need to create a secret for the service account.
Create a file named sa-token.yaml
, and copy the following content.
apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
name: api-service-account-token
namespace: devops-tools
annotations:
kubernetes.io/service-account.name: api-service-account
Then, create the secret by running the following command.
kubectl apply -f sa-token.yaml
Once the secret is created, use the following command to get the base64 decoded token. It will be used as a bearer token in the API call.
kubectl get secret api-service-account-token -o=jsonpath='{.data.token}' -n devops-tools | base64 --decode
Get the cluster endpoint to validate the API access. The following command will display the cluster endpoint (IP, DNS).
kubectl get endpoints | grep kubernetes
Step 6: Validate Service Account Access Using API call
Now that you have the cluster endpoint and the service account token, you can test the API connectivity using the CURL or the Postman app.
For example, list all the namespaces in the cluster using curl. Use the token after Authorization: Bearer
section.
curl -k https://35.226.193.217/api/v1/namespaces -H "Authorization: Bearer eyJhbGcisdfsdfsdfiJ9.eyJpc3MiOisdfsdfVhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3sdf3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImFwaS1zZXJ2aWNlsdfglkjoer876Y3BmNWYiLsdfsdfRlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmFwaS1zZXJ2aWNlLWFjY291bnQifQ.u5jgk2px_lEs3f5e5lh_UfS40fndtDKMTY5UvsdfrtsuhtgjrUj-ezrRXeLS8SLOae4DuOGGGbInSg_gIo6oO7bLHhCixWOBJNOA5gzrLVioof_kHDR8gH5crrsWoR-GSSsdfgsdfg6fA_LDOqdxzqMC0WlXt6tgHfrwIHerPPvkI6NWLyCqX9tn_akpcihd-bL6GwOKlph17l_ND710FnTkE7kBfdXtQWWxaPPe06UEmoKK9t-0gsOCBxJxViwhHkvwqetr987q9enkadfgd_2cY_CA"
You can also try that same API call in Postman.
The ClusterRole
we created can be attached to pods/deployments as well.
You can also use the token to login to the Kubernetes dashboard.
Conclusion
When using Kubernetes service account for API access from third party applications, ensure you add only required roles to the service account.
Also, never attach a clusterRole to a default service account because the pods get the default service account by default. Meaning all the pods in the namespace have access to the clusterRole.
Also, use a secret management tool like Hashicorp vault to store, retrieve, and share secret tokens.
7 comments
One Question Bibin can I create a service account that has access to the entire cluster which basically allows me to do things like create namespace and then do deployments
Hi Rakesh,
To have cluster wise access, you need to bind a clusterRole to a service account. Your clusterRole should have the required cluster level access added to it.
I’m late to this blog and I really regret. You are a life savour.
Glad it helped Shiju 🙂
Thank you so much for the article, it helped a lot.
I am glad it helped 🙂
After performed all the above steps getting the below status message
{
“kind”: “Status”,
“apiVersion”: “v1”,
“metadata”: {
},
“status”: “Failure”,
“message”: “Unauthorized”,
“reason”: “Unauthorized”,
“code”: 401
}