Kubernetes Fundamentals · Module 12 of 14

ServiceAccounts, RBAC and workload security basics

Introduce least privilege for API access and safer container execution using ServiceAccounts, Roles/Bindings and securityContext.

Learning objectives

By the end of this module, you should be able to:

  • Explain ServiceAccount identity for Pods.
  • Grant narrow namespace permissions with RBAC.
  • Apply basic workload hardening such as non-root execution and no privilege escalation.

ServiceAccounts identify workloads

Pods use ServiceAccounts as workload identities for Kubernetes API access. Applications should not automatically receive broader API permissions than they need.

RBAC separates permissions from subjects

Roles contain namespaced permission rules. RoleBindings attach those rules to users, groups or ServiceAccounts in a namespace. ClusterRoles and ClusterRoleBindings apply to cluster-scoped or reusable permission sets.

securityContext constrains execution

runAsNonRoot, allowPrivilegeEscalation=false, dropped Linux capabilities, read-only root filesystems and seccomp profiles reduce container privileges. Exact settings must still match the application’s runtime needs.

NetworkPolicy is separate from RBAC

RBAC governs Kubernetes API authorization. NetworkPolicy governs allowed Pod network traffic when the cluster networking implementation enforces it. They solve different problems.

Worked examples

See the idea in practice.

Ask the API what an identity can do

kubectl auth can-i list pods --as=system:serviceaccount:gnu-k8s-fundamentals:reader -n gnu-k8s-fundamentals
  • can-i is a useful RBAC diagnostic.
  • The answer should reflect bindings, not assumptions.
Hands-on lab

Lab — Grant read-only Pod access

Goal: Create a ServiceAccount, Role and RoleBinding, verify permissions, and run a non-root Pod.

Before you start

  • kubectl is installed and can reach the lab cluster.
  • Use the dedicated gnu-k8s-fundamentals namespace unless a step explicitly says otherwise.
STEP 1

Create the ServiceAccount and RBAC

cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  name: reader
  namespace: gnu-k8s-fundamentals
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: gnu-k8s-fundamentals
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get","list","watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-reader
  namespace: gnu-k8s-fundamentals
subjects:
- kind: ServiceAccount
  name: reader
  namespace: gnu-k8s-fundamentals
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: pod-reader
EOF
STEP 2

Verify allowed and denied actions

kubectl auth can-i list pods --as=system:serviceaccount:gnu-k8s-fundamentals:reader -n gnu-k8s-fundamentals
kubectl auth can-i delete pods --as=system:serviceaccount:gnu-k8s-fundamentals:reader -n gnu-k8s-fundamentals
STEP 3

Run a hardened Pod

cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: secure-demo
  namespace: gnu-k8s-fundamentals
spec:
  serviceAccountName: reader
  securityContext:
    runAsNonRoot: true
    runAsUser: 65534
    seccompProfile: {type: RuntimeDefault}
  containers:
  - name: app
    image: busybox:1.36
    command: ["sh","-c","id; sleep 3600"]
    securityContext:
      allowPrivilegeEscalation: false
      capabilities: {drop: ["ALL"]}
EOF
kubectl -n gnu-k8s-fundamentals wait --for=condition=Ready pod/secure-demo --timeout=90s
kubectl -n gnu-k8s-fundamentals logs secure-demo
STEP 4

Clean up

kubectl -n gnu-k8s-fundamentals delete pod secure-demo
kubectl -n gnu-k8s-fundamentals delete rolebinding pod-reader
kubectl -n gnu-k8s-fundamentals delete role pod-reader
kubectl -n gnu-k8s-fundamentals delete serviceaccount reader

Verify

  • list pods returns yes.
  • delete pods returns no.
  • The Pod runs as UID 65534 with no extra capabilities requested.

Expected outcome

  • RBAC demonstrates least privilege independent of container Linux privileges.

If it fails

  • If auth can-i differs, inspect RoleBinding subject namespace/name.
  • If a hardened image fails, determine which filesystem or privilege requirement the application actually needs rather than disabling every control.
Real-world connection

Production security combines workload identity, least-privilege API authorization, hardened container execution and network controls.

Avoid these traps

Common mistakes

  • Binding application ServiceAccounts to cluster-admin.
  • Confusing RBAC with network access control.
  • Setting runAsNonRoot without verifying that the image can actually run as a non-root user.
Knowledge check

Can you explain it without looking back?

Open each answer only after you have tried to answer the question yourself.

1What does RBAC control?

Authorization to Kubernetes API resources/actions.

2What does a RoleBinding do?

Binds Role/ClusterRole permissions to subjects within a namespace.

3Does NetworkPolicy replace RBAC?

No. NetworkPolicy controls network traffic; RBAC controls API authorization.