Cloud Native 20 min read

Master Kubernetes ServiceAccounts and RBAC: From Basics to Custom Roles

This guide explains the difference between Kubernetes UserAccounts and ServiceAccounts, shows how default and custom ServiceAccounts create associated secrets, demonstrates mounting credentials in pods, adds image pull secrets, and walks through RBAC concepts with Roles, ClusterRoles, and bindings to restrict a user to a specific namespace.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
Master Kubernetes ServiceAccounts and RBAC: From Basics to Custom Roles

1. ServiceAccount

1.1 ServiceAccount Introduction

Kubernetes distinguishes between User Accounts (used by external users such as operators via kubectl) and Service Accounts (used by processes running inside Pods). User Accounts are global and unique across all namespaces, while Service Accounts are scoped to a namespace and a default one is created automatically.

UserAccount: for external users, global, default admin.

ServiceAccount: for Pods, namespace‑scoped, default SA created per namespace; Pods use the default SA if none is specified.

1.2 Secret and ServiceAccount Relationship

Kubernetes automatically creates a kubernetes.io/service-account-token Secret for each ServiceAccount. Users can also create custom opaque Secrets.

1.3 Default ServiceAccount

When a namespace is created, a default ServiceAccount and its corresponding Secret are generated. The Secret is mounted into Pods at /var/run/secrets/kubernetes.io/serviceaccount.

# kubectl create ns vfan
namespace/vfan created

# kubectl get sa -n vfan
NAME      SECRETS   AGE
default   1         67s

# kubectl describe sa default -n vfan
Name:               default
Namespace:          vfan
Mountable secrets:  default-token-wwbc8
Tokens:             default-token-wwbc8

# kubectl get secret -n vfan
NAME                TYPE                                 DATA   AGE
default-token-wwbc8 kubernetes.io/service-account-token   3     3m15s
Creating a namespace automatically creates a ServiceAccount, which in turn creates a service-account-token Secret.

Creating a Pod using the default ServiceAccount:

apiVersion: v1
kind: Pod
metadata:
  name: test-sa
  namespace: vfan
spec:
  containers:
  - name: test-sa
    image: nginx:1.2.1
    ports:
    - containerPort: 80
# kubectl create -f pods.yaml
pod/test-sa created

# kubectl describe pod test-sa -n vfan
...Mounts:
  /var/run/secrets/kubernetes.io/serviceaccount from default-token-wwbc8 (ro)
...
Without specifying a ServiceAccount, a Pod uses the namespace's default ServiceAccount, and its token Secret is automatically mounted.

Inside the Pod you can view the three files:

# cd /var/run/secrets/kubernetes.io/serviceaccount/
# ls
ca.crt  namespace  token

These are the CA certificate, the namespace identifier, and a JWT token signed by the API server.

1.4 Using a Custom ServiceAccount

# kubectl create sa vfansa -n vfan
serviceaccount/vfansa created

# kubectl get sa -n vfan
NAME      SECRETS   AGE
default   1         19m
vfansa    1         7s

# kubectl describe sa vfansa -n vfan
Name:               vfansa
Namespace:          vfan
Mountable secrets:  vfansa-token-9s8f7
Tokens:             vfansa-token-9s8f7
Creating a ServiceAccount also creates a corresponding Secret.

Update the Pod definition to use the custom ServiceAccount:

apiVersion: v1
kind: Pod
metadata:
  name: test-sa
  namespace: vfan
spec:
  containers:
  - name: test-sa
    image: nginx:1.2.1
    ports:
    - containerPort: 80
  serviceAccountName: vfansa  # added
# kubectl create -f pods.yaml
pod/test-sa created

# kubectl describe pod test-sa -n vfan
...Mounts:
  /var/run/secrets/kubernetes.io/serviceaccount from vfansa-token-9s8f7 (ro)
...

1.5 Adding Image Pull Secrets to a ServiceAccount

First create a docker-registry Secret that stores private registry credentials:

# kubectl create secret docker-registry myregistrykey \
  --docker-server=hub.vfancloud.com \
  --docker-username=admin \
  --docker-password=admin@123 \
  [email protected] -n vfan
secret/myregistrykey created

Then edit the ServiceAccount to reference the secret:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: vfansa
  namespace: vfan
secrets:
- name: vfansa-token-9s8f7
imagePullSecrets:
- name: myregistrykey
# kubectl describe sa vfansa -n vfan
Name:               vfansa
Namespace:          vfan
Image pull secrets: myregistrykey
Mountable secrets:  vfansa-token-9s8f7
Pods that use this ServiceAccount can now pull images from the private registry without additional login steps.

2. RBAC

2.1 RBAC Introduction

All Kubernetes resources are accessed via the API server, which authenticates requests (e.g., using ServiceAccount tokens) and authorizes them using Role‑Based Access Control (RBAC).

2.2 Role and ClusterRole

A Role defines permissions within a single namespace, while a ClusterRole defines cluster‑wide permissions.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: test-role
  namespace: vfan
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get","watch","list"]
This Role grants get , watch , and list permissions on Pods in the vfan namespace.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: test-clusterrole
rules:
- apiGroups: [""]
  resources: ["services"]
  verbs: ["get","create","list"]
This ClusterRole grants get , create , and list permissions on Services across the entire cluster.

2.3 RoleBinding and ClusterRoleBinding

RoleBinding

assigns a Role (or ClusterRole) to a user, group, or ServiceAccount within a namespace; ClusterRoleBinding does the same cluster‑wide.

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: test-rolebinding
  namespace: vfan
subjects:
- kind: User
  name: vfan
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: test-role
  apiGroup: rbac.authorization.k8s.io
This binds the test-role permissions to the user vfan in the vfan namespace.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: test-rolebinding2
  namespace: vfan
subjects:
- kind: User
  name: vfan
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: test-clusterrole
  apiGroup: rbac.authorization.k8s.io
This binds a ClusterRole to a user within a single namespace.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: test-clusterrolebinding
subjects:
- kind: Group
  name: vfan
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: test-clusterrole
  apiGroup: rbac.authorization.k8s.io
This grants every member of the vfan group the permissions defined in test-clusterrole across the whole cluster.

3. Practical Example: Restrict a User to Manage Only the vfan Namespace

3.1 Create a System User

# useradd vfan
# su - vfan
# kubectl get pod
The connection to the server localhost:8080 was refused - did you specify the right host or port?
The user cannot access the cluster until a client certificate is created.

3.2 Generate a Client Certificate for vfan

Download cfssl tools, create a CSR JSON, and generate the certificate:

# wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
# wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
# chmod +x cfssl cfssljson
# mkdir /usr/local/vfancert && cd /usr/local/vfancert
# cfssl gencert -ca=ca.crt -ca-key=ca.key -profile=kubernetes /usr/local/vfancert/vfan-csr.json | cfssljson -bare vfanuser

This creates vfanuser.pem, vfanuser-key.pem, and vfanuser.csr in /etc/kubernetes/pki.

3.3 Create a kubeconfig for vfan

# export KUBE_APISERVER="https://192.168.152.53:6443"
# kubectl config set-cluster kubernetes \
    --certificate-authority=/etc/kubernetes/pki/ca.crt \
    --embed-certs=true \
    --server=${KUBE_APISERVER} \
    --kubeconfig=vfan.kubeconfig
# kubectl config set-credentials vfanuser \
    --client-certificate=/etc/kubernetes/pki/vfanuser.pem \
    --client-key=/etc/kubernetes/pki/vfanuser-key.pem \
    --embed-certs=true \
    --kubeconfig=vfan.kubeconfig
# kubectl config set-context kubernetes \
    --cluster=kubernetes \
    --user=vfan \
    --namespace=vfan \
    --kubeconfig=vfan.kubeconfig

Copy the kubeconfig to /home/vfan/.kube/config and adjust ownership.

3.4 Verify RoleBinding Permissions

# kubectl create -f vfanrolebind.yaml

Now as vfan:

$ kubectl get pod
No resources found.

$ kubectl get svc
Error from server (Forbidden): services is forbidden: User "vfan" cannot list resource "services" in API group "" in the namespace "vfan"
The user can list Pods but not Services, matching the permissions defined in the Role.

Creating a Deployment as root in the vfan namespace:

# kubectl run deployment test-vfan --replicas=3 --image=nginx:1.2.1 --namespace=vfan

When logged in as vfan, the Pods are visible, confirming the default namespace is correctly set.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

CloudNativeKubernetesRBACRoleBindingServiceAccount
MaGe Linux Operations
Written by

MaGe Linux Operations

Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.