Feb 19, 2025
Kubernetes RBAC: Service Account, Token Auth & Role Binding
In this tutorial, you will learn how to secure a Kubernetes microservice—called the “Grade Submission API”—using Role-Based Access Control (RBAC). You will:
Deploy the grade-submission API with endpoints:
POST /grades
to add a grade record.GET /grades
to retrieve all grade records.
Add a kube-rbac-proxy sidecar to ensure only valid tokens (from authorized users) can pass through.
Configure ServiceAccounts, ClusterRoles, and ClusterRoleBindings so each component—client and proxy—gets only the minimal privileges it needs.
By following these steps, you will see the API in two modes:
Open/Unauthenticated: Anyone can read/write grades.
Secured/Authenticated: Only valid bearer tokens can perform API calls.
Prerequisites & Course Resources
GitHub Starter Code:https://github.com/rslim087a/k8s-rbac-starter
kube-rbac-proxy Image:
gcr.io/kubebuilder/kube-rbac-proxy:v0.14.0
kube-rbac-proxy Example Configuration:https://github.com/brancz/kube-rbac-proxy/blob/af1a90b60796a6d6acb3673bd58336e1a6319c2b/examples/rewrites/README.md?plain=1#L106
ClusterRoleBinding Example:https://kubernetes.io/docs/reference/access-authn-authz/rbac/#clusterrolebinding-example
ClusterRole Example:https://kubernetes.io/docs/reference/access-authn-authz/rbac/#clusterrole-example
Note: Windows users should run commands (particularly curl
) inside Git Bash for better compatibility with the syntax shown.
Step 1: Clone the Starter Repository
Clone and open the repository:
Inside, you will find all relevant YAML files (e.g., namespace.yaml
, deployment.yaml
, service.yaml
, and RBAC resources).
Step 2: Deploy the Grade Submission API (Unsecured)
Apply all the manifests to your cluster:
This will:
Create a Namespace:
grade-demo
.Create a Deployment for
grade-submission-api
(listening on port 3000).Create a NodePort Service on port
31000
.
Test the Unauthenticated API
According to the README, you can POST grades with:
Retrieve all grades:
These calls succeed without any authentication, which highlights the need for role-based access control.
Step 3: Introduce the kube-rbac-proxy Sidecar
To lock down these endpoints, you will add a kube-rbac-proxy container to the same Pod. That container will:
Listen on port
8443
(HTTPS).Validate incoming requests (by checking the bearer token against the Kubernetes API).
Forward valid requests to the main container at port
3000
.
The Service now targets 8443
(named https
) instead of 3000
. Any request coming to NodePort 31000
gets routed to the sidecar first.
Test with HTTPS and -k
(to skip certificate verification):
You should get Unauthorized
—kube-rbac-proxy now requires valid tokens.
Step 4: Set Up a ServiceAccount & Token for the Client
To authenticate, the client (curl) must present a valid Kubernetes token.
ServiceAccount for the client:
Secret of type
kubernetes.io/service-account-token
:
Apply these, then extract the token:
Still likely Unauthorized
or Forbidden
, because you must define RBAC permissions first.
Step 5: Give kube-rbac-proxy Permission to Verify Tokens
ServiceAccount for the Proxy
Our Deployment references serviceAccountName: grade-service-proxy
. Create that:
ClusterRole for the Proxy
The proxy must create tokenreviews
(in authentication.k8s.io
) and subjectaccessreviews
(in authorization.k8s.io
):
ClusterRoleBinding for the Proxy
Bind this role to grade-service-proxy
:
Now kube-rbac-proxy can validate tokens properly.
Step 6: Grant the Client Access to the Grade Submission API
We must define which non-resource URLs (e.g., /grades
) the client can access. In Kubernetes RBAC, these are configured via nonResourceURLs
.
ClusterRole for the Client
For more fine-grained control, specify ["/grades", "/grades/"], etc.
ClusterRoleBinding for the Client
Now your grade-service-account can call the microservice endpoints at /grades
.
Step 7: Test the Authenticated API
Reapply all resources, re-extract the token, and make authenticated requests:
From the README, here is how you POST grades with authentication (using -k
to ignore TLS cert warnings and Authorization: Bearer
for the token):
And verify with:
This time, calls succeed only if you have the correct bearer token. Without the token, or with an invalid token, the request should fail (Unauthorized
).
Conclusion
You have successfully:
Deployed the Grade Submission API.
Secured it via a kube-rbac-proxy sidecar that checks requests against Kubernetes RBAC.
Created two ServiceAccounts:
grade-service-proxy: Has ClusterRole rules allowing it to create token/subjectaccess reviews.
grade-service-account: Used by the client (curl) to authenticate and authorized for
GET
/POST
at/grades
.
Tested the API using both unauthenticated (HTTP on port 31000) and authenticated (HTTPS on port 31000 with bearer token).
Next Steps:
Narrow down
nonResourceURLs: ["/*"]
to just the endpoints you want accessible, such as"/grades"
.Explore advanced scenarios where different roles can have read-only vs. write permissions for certain API paths.
Combine resource-based rules (e.g., Pods, Deployments) with these non-resource URL rules for a full production scenario.
With this pattern, you ensure that only appropriately credentialed users can interact with your microservice, keeping your cluster more secure and better aligned with the principle of least privilege.
Kubernetes Training
If you find these guides helpful, check out our Kubernetes Training course