Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes

Service Accounts & Roles

Learn to configure Kubernetes service accounts and roles for pod-level identity and access control.

Focus: configure service accounts and roles

Sponsored

When a Pod runs in Kubernetes, it doesn't have a built-in identity to prove who it is when talking to the API server or external services. Without a proper identity, every Pod would need to use your personal user credentials or skip authentication entirely—both are security nightmares. That's where ServiceAccounts come in: they give each Pod a distinct, verifiable identity, and with Roles and RoleBindings, you can control exactly what that identity can do. This lesson teaches you to configure service accounts and roles so your Pods can authenticate and authorize themselves securely.

The problem this lesson solves

Imagine you deploy a microservice that needs to list all Pods in a namespace for internal monitoring. If you don't configure a service account and role, the Pod has one of two problems:

  • No identity: The Pod uses the default service account, which usually has no RBAC permissions. The API call fails with a 403 Forbidden.
  • Too much identity: The Pod inherits over-permissive credentials (like a cluster admin token) and accidentally deletes resources it shouldn't.

This is the classic DevOps tension: security vs. convenience. The solution is to configure a dedicated ServiceAccount, attach a Role with minimal permissions, and bind them with a RoleBinding (or ClusterRole/ClusterRoleBinding for cross-namespace access). Without this, your cluster is either broken or insecure.

Core concept / mental model

Think of a ServiceAccount as a badge that the Pod wears. The badge proves "this is the Pod metrics-collector, not an impostor." A Role is a list of permission rules — like a key card that says "you can read Pods and Services in the default namespace." A RoleBinding is the handshake that attaches the badge to the key card.

Important nuance: ServiceAccounts are namespace-scoped objects. If you create a ServiceAccount in namespace-a, a Pod in namespace-b cannot use it unless you use a ClusterRole and ClusterRoleBinding (which are cluster-scoped).

Key terms

  • ServiceAccount: An object that provides an identity for processes running in a Pod.
  • Role: A set of rules that define allowed verbs (get, list, create, delete, etc.) on specific resources (pods, services, deployments).
  • RoleBinding: Links a Role to a user, group, or ServiceAccount within a namespace.
  • ClusterRole / ClusterRoleBinding: Same as Role/RoleBinding but cluster-scoped (no namespace restriction).

When a Pod uses a service account, the API server automatically mounts a token (mounted at /var/run/secrets/kubernetes.io/serviceaccount/token) that the Pod can present for authentication and authorization.

How it works step by step

  1. Create a ServiceAccount with kubectl create serviceaccount <name> or a YAML manifest.
  2. Define a Role with rules specifying apiGroups, resources, and verbs. For example, a Role that allows getting and listing Pods looks like this:

yaml apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: default name: pod-reader rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list"]

  1. Bind the Role to the ServiceAccount using a RoleBinding:

yaml apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: namespace: default name: pod-reader-binding subjects: - kind: ServiceAccount name: my-service-account namespace: default roleRef: kind: Role name: pod-reader apiGroup: rbac.authorization.k8s.io

  1. Assign the ServiceAccount to a Pod by setting spec.serviceAccountName: my-service-account.
  2. The Pod's code uses the mounted token to authenticate against the Kubernetes API. The API server checks the RoleBinding and allows or denies the request.

Hands-on walkthrough

Let's make it real. You'll create a ServiceAccount, a Role that allows listing Pods, bind them, and deploy a Pod that uses the token to prove it works.

Step 1: Create the ServiceAccount

kubectl create serviceaccount my-sa
# OR with YAML:
kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-sa
  namespace: default
EOF

Verify it exists:

kubectl get sa
# Output:
# NAME      SECRETS   AGE
# default   1         30d
# my-sa     1         5s

Step 2: Create the Role

kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list"]
EOF

Step 3: Bind the Role to the ServiceAccount

kubectl apply -f - <<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: default
  name: pod-reader-binding
subjects:
- kind: ServiceAccount
  name: my-sa
  namespace: default
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io
EOF

Step 4: Deploy a Pod that uses the ServiceAccount

Let's deploy a Pod that runs kubectl and uses curl to hit the Kubernetes API.

kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: sa-test-pod
spec:
  serviceAccountName: my-sa
  containers:
  - name: test
    image: bitnami/kubectl:latest
    command: ["sleep", "3600"]
EOF

Wait for the Pod to be ready (kubectl get pod sa-test-pod) and then exec into it:

kubectl exec -it sa-test-pod -- /bin/sh

Inside the container, read the token and namespace:

TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)

# List Pods using the token
curl -s --header "Authorization: Bearer $TOKEN" --insecure \
  https://kubernetes.default.svc/api/v1/namespaces/$NAMESPACE/pods

You should see a JSON response with your Pods. If the token had no permissions, you'd get a 403 Forbidden.

Step 5: Clean up

kubectl delete pod sa-test-pod
kubectl delete rolebinding pod-reader-binding
kubectl delete role pod-reader
kubectl delete serviceaccount my-sa

Compare options / when to choose what

Feature Role + RoleBinding ClusterRole + ClusterRoleBinding
Scope Namespace-specific Cluster-wide (all namespaces)
Resources Namespaced resources (Pods, Services, ConfigMaps) Namespaced + cluster-scoped (Nodes, PVs, StorageClasses)
Non-resource URLs Not supported Supports /healthz, /api, etc.
Use case Scoped microservice permissions, per-team namespaces Cluster admin tasks, monitoring across namespaces

When to use what:

  • Use Role + RoleBinding when your Pod only needs access to resources in its own namespace.
  • Use ClusterRole + ClusterRoleBinding when a component needs to see everything (e.g., Prometheus scraping all namespaces, or an admission webhook).
  • You can also bind a ClusterRole to a RoleBinding (namespace-scoped) — that's common when you want to reuse a ClusterRole definition but restrict it to a single namespace.

Troubleshooting & edge cases

Common errors and fixes

  • 403 Forbidden: The ServiceAccount lacks permissions. Verify the Role rules and the RoleBinding subject. Use kubectl auth can-i --as=system:serviceaccount:default:my-sa list pods -n default to test.
  • Token not mounted: You forgot spec.serviceAccountName in the Pod. The default ServiceAccount is always mounted, but if your Pod can't authenticate, check the mount path manually or inspect the Pod's container spec.
  • Cross-namespace access denied: You tried to use a RoleBinding to give access to a namespace other than where the binding lives. Use a ClusterRoleBinding instead.
  • Token expiration: In Kubernetes 1.24+, the service account token is a bound token with expiration (typically 1 year). If your token stops working after a long time, you need to refresh the Pod or use a custom token controller.

Edge case: Default ServiceAccount automation

If you never explicitly set a service account, Kubernetes uses the default ServiceAccount in the Pod's namespace. By default, the default ServiceAccount has no RBAC permissions. This is secure but can be confusing: a Pod that tries to list objects silently fails unless you bind a Role to the default ServiceAccount.

What you learned & what's next

You now understand how to configure service accounts and roles to give Pods a secure, scoped identity. You can:

  • Explain why service accounts exist (separation of identities for workloads).
  • Create a ServiceAccount, Role, and RoleBinding from YAML.
  • Test permissions with kubectl auth can-i and by exec-ing into a container.
  • Decide between namespaced (Role/RoleBinding) and cluster-scoped (ClusterRole/ClusterRoleBinding) access.

Next up, you'll explore NetworkPolicies — how to control traffic between Pods, not just API access. You'll take that fine-grained identity you just configured and apply it to network segmentation.

Practice recap

Practice: Create a ServiceAccount named deployer, then write a Role that allows * (all verbs) on deployments and pods in the default namespace, and bind them. Deploy a Pod that runs kubectl run nginx-test --image=nginx to verify the permission works. If you get a 403, check the Role and RoleBinding namespaces.

Common mistakes

  • Forgetting to set spec.serviceAccountName on the Pod — the default service account has no permissions, so API calls silently fail with 403.
  • Binding a Role to a ServiceAccount but in the wrong namespace — RoleBindings only apply to the namespace they're created in; use ClusterRoleBinding for cross-namespace access.
  • Using kubectl create role without --verb or --resource flags — you might create a Role with no rules, which effectively denies everything.
  • Assuming the mounted token never expires — bound tokens (Kubernetes 1.24+) have expiration; plan for token rotation or use projected volumes.

Variations

  1. Instead of in-line YAML, use kubectl create role pod-reader --verb=get,list --resource=pods --dry-run=client -o yaml to generate the Role manifest.
  2. For cluster-level monitoring tools like Prometheus, use a ClusterRole with read access across all namespaces and a ClusterRoleBinding.
  3. Use external secrets managers (e.g., Vault) to inject credentials instead of Kubernetes tokens, when interacting with external services.

Real-world use cases

  • A CI/CD pipeline runs in a Pod and needs to create deployments in a dedicated namespace; a ServiceAccount with a Role allows it safely.
  • A monitoring agent (like Prometheus) uses a ClusterRole to scrape metrics from Pods and Nodes across the entire cluster.
  • A sidecar container in a Pod needs to read ConfigMaps from its own namespace to dynamically reconfigure the main app.

Key takeaways

  • ServiceAccounts give Pods a unique identity separate from human users.
  • Roles define allowed actions on resources; RoleBindings attach them to ServiceAccounts.
  • Use ClusterRole + ClusterRoleBinding for cluster-wide access, not for namespace-scoped controls.
  • Always test permissions with kubectl auth can-i before deploying production workloads.
  • Bound tokens automatically expire in modern Kubernetes — plan for rotation.
  • The default service account has no permissions; always create dedicated accounts for each workload.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.