Lesson 05 ServiceAccounts & RBAC
Theme:
Lesson 05 · Slide 1

ServiceAccounts & RBAC

Every pod in Kubernetes runs under a ServiceAccount that determines what it can do via the API server. RBAC (Role-Based Access Control) is the policy engine that grants or denies those permissions.

Learning Objectives

Lesson 05 · Slide 2

ServiceAccount Fundamentals

A ServiceAccount provides an identity for processes running in a pod. When a pod makes a request to the Kubernetes API server, it authenticates using the token mounted from its ServiceAccount.

Helm ServiceAccount Template

# templates/serviceaccount.yaml
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
  name: {{ include "myapp.serviceAccountName" . }}
  labels:
    {{- include "myapp.labels" . | nindent 4 }}
  {{- with .Values.serviceAccount.annotations }}
  annotations:
    {{- toYaml . | nindent 4 }}
  {{- end }}
automountServiceAccountToken: {{ .Values.serviceAccount.automount }}
{{- if .Values.serviceAccount.imagePullSecrets }}
imagePullSecrets:
  {{- toYaml .Values.serviceAccount.imagePullSecrets | nindent 2 }}
{{- end }}
{{- end }}
Note: automountServiceAccountToken: false is the secure default. Only enable it when your app actually calls the Kubernetes API.
Lesson 05 · Slide 3

The RBAC Model

Kubernetes RBAC has four resource types that work together to grant permissions.

ResourceScopePurpose
RoleNamespaceDefines a set of permissions within a single namespace
ClusterRoleCluster-wideDefines permissions across all namespaces or for cluster resources
RoleBindingNamespaceGrants a Role (or ClusterRole) to subjects in a namespace
ClusterRoleBindingCluster-wideGrants a ClusterRole to subjects across the entire cluster

Key insight: A RoleBinding can reference a ClusterRole but still limits the permissions to its own namespace. This is a common pattern for reusing permission sets.

Lesson 05 · Slide 4

Role & RoleBinding in Helm

The most common pattern: your app needs to read ConfigMaps and Secrets in its own namespace.

# templates/role.yaml
{{- if .Values.rbac.create -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: {{ include "myapp.fullname" . }}
  labels:
    {{- include "myapp.labels" . | nindent 4 }}
rules:
  - apiGroups: [""]
    resources: ["configmaps", "secrets"]
    verbs: ["get", "list", "watch"]
{{- end }}
# templates/rolebinding.yaml
{{- if .Values.rbac.create -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: {{ include "myapp.fullname" . }}
  labels:
    {{- include "myapp.labels" . | nindent 4 }}
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: {{ include "myapp.fullname" . }}
subjects:
  - kind: ServiceAccount
    name: {{ include "myapp.serviceAccountName" . }}
    namespace: {{ .Release.Namespace }}
{{- end }}
Lesson 05 · Slide 5

Common RBAC Patterns

Read-Only Namespace

rules:
  - apiGroups: [""]
    resources: ["pods", "services",
                "configmaps"]
    verbs: ["get", "list", "watch"]

Namespace Admin

rules:
  - apiGroups: ["", "apps", "batch"]
    resources: ["*"]
    verbs: ["*"]

Specific Resource Access

rules:
  - apiGroups: [""]
    resources: ["secrets"]
    resourceNames: ["db-creds"]
    verbs: ["get"]

CRD Manager

rules:
  - apiGroups: ["myapp.io"]
    resources: ["widgets"]
    verbs: ["get", "list", "watch",
            "create", "update", "delete"]
Lesson 05 · Slide 6

Values & Conditional Templating

A well-structured values.yaml lets users control ServiceAccount and RBAC creation independently.

# values.yaml
serviceAccount:
  create: true
  name: ""                    # auto-generated if empty
  automount: false            # secure default
  annotations: {}
  imagePullSecrets: []

rbac:
  create: true
  rules:
    - apiGroups: [""]
      resources: ["configmaps", "secrets"]
      verbs: ["get", "list", "watch"]

Helper Template

# templates/_helpers.tpl
{{- define "myapp.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "myapp.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
Lesson 05 · Slide 7

Image Pull Secrets & Least Privilege

ServiceAccounts can carry imagePullSecrets so every pod using that account automatically authenticates to private container registries.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: myapp
imagePullSecrets:
  - name: ghcr-credentials
  - name: ecr-credentials

Least Privilege Checklist

  • Set automountServiceAccountToken: false unless API access is needed
  • Use Role (namespace-scoped) instead of ClusterRole when possible
  • Restrict verbs to exactly what the app needs — avoid ["*"]
  • Use resourceNames to limit access to specific objects
  • Audit with kubectl auth can-i --list --as=system:serviceaccount:ns:name
Lesson 05 · Slide 8

Lab & Homework

Lab Exercises

  1. Create a Helm chart with ServiceAccount and RBAC templates
  2. Deploy an app that reads ConfigMaps via the Kubernetes API
  3. Verify least-privilege by testing denied operations

Homework Tasks

  1. Build a multi-role chart with conditional ClusterRole support
  2. Implement image pull secret automation via ServiceAccount
  3. Audit and harden an over-permissioned chart
Key takeaway: Every chart that interacts with the Kubernetes API needs a ServiceAccount and RBAC rules. Defaulting to least privilege protects both the application and the cluster.
1 / ?