← Articulet Kubernetes Zero to Hero Chapter 6.1
Module 6 Security, RBAC, and Policies

Authentication and Authorization

In previous chapters you learned to persist data with StatefulSets. But what happens when anyone who reaches your cluster can delete anything? All that precious state is one malicious kubectl delete away from disaster....

Chapter 14 of 22
Module 6: Security, RBAC, and Policies

Security is not an afterthought. This module builds defense-in-depth from authentication through admission control, with production-ready patterns for GKE.

Module 6 of 8 | Difficulty: Intermediate to Advanced

In previous chapters you learned to persist data with StatefulSets. But what happens when anyone who reaches your cluster can delete anything? All that precious state is one malicious kubectl delete away from disaster. Security is the foundation everything stands on.

This chapter covers Authentication (proving identity) and Authorization (checking permissions). We'll use a building security analogy, then translate it into commands and YAML.


6.1.1 The Kubernetes Security Model: The Three A's

Analogy: The Corporate Building Security System

Imagine walking into a corporate headquarters. To reach a sensitive server room, you pass three checkpoints. First, the lobby guard checks your government ID—proving who you are. Second, you swipe a keycard at the elevator—determining which floors you can access. Third, a policy checker verifies you're following safety protocols before you enter the server room.

These map directly to Kubernetes:

Building Checkpoint Kubernetes Layer Question It Answers
ID check at lobby Authentication (AuthN) "Who are you?"
Keycard floor access Authorization (AuthZ) "What are you allowed to do?"
Policy checker at server room Admission Control "Are you following the rules?"

Every API request—whether from kubectl or a Pod—flows through these three gates before reaching etcd.

Visual Description:

graph LR subgraph "Every API Request Flows Through These Gates" REQ[Incoming Request] --> AUTHN subgraph "Checkpoint 1" AUTHN[Authentication<br/>Show your ID<br/>Who are you?] end AUTHN -->|Identity verified| AUTHZ AUTHN -->|Identity unknown| DEN1[Reject: 401 Unauthorized] subgraph "Checkpoint 2" AUTHZ[Authorization<br/>Swipe keycard<br/>What can you do?] end AUTHZ -->|Permission granted| ADM AUTHZ -->|Permission denied| DEN2[Reject: 403 Forbidden] subgraph "Checkpoint 3" ADM[Admission Control<br/>Policy check<br/>Are rules followed?] end ADM -->|Policy passed| ALLOW[Allow: Persist to etcd] ADM -->|Policy violated| DEN3[Reject: Admission Denied] end style REQ fill:#90caf9 style AUTHN fill:#ef9a9a style AUTHZ fill:#ffcc80 style ADM fill:#a5d6a7 style ALLOW fill:#81c784 style DEN1 fill:#e57373 style DEN2 fill:#e57373 style DEN3 fill:#e57373

GKE Note: On GKE, Authentication is handled through GCP IAM. When you run gcloud container clusters get-credentials, gcloud obtains an OAuth2 token and inserts it into your kubeconfig. The API Server validates it against Google's identity services. No manual client certificate management needed.

Zero-Trust Principles. Kubernetes embraces zero-trust: never trust, always verify. Even internal traffic requires authentication. A Pod calling the API must present credentials like a human user. Defense in depth means each layer provides independent protection.

Threat Model. The API Server is the cluster boundary. Anything that can authenticate to it can control the cluster. Production clusters should use private endpoints and authorized networks.


🛑 PAUSE & RECALL — 2 minutes

  1. What are the three A's of Kubernetes security, and what question does each answer?
  2. What HTTP status code does rejected Authentication return? What about rejected Authorization?
  3. In the building analogy, what is the equivalent of a ServiceAccount token?

Rate your confidence (0-4).


6.1.2 Authentication: Proving Who You Are

Authentication answers: who are you? Kubernetes has no built-in user database. Instead, it delegates identity verification to external systems via authentication plugins.

Client Certificate Authentication. An admin creates a private key and CSR, then a cluster CA signs the certificate. The user presents this certificate with every request. Works well for small teams but scales poorly.

Bearer Tokens. Presented in the Authorization: Bearer <token> header:

  • ServiceAccount tokens: JWT tokens auto-mounted into Pods at /var/run/secrets/kubernetes.io/serviceaccount/token. How applications authenticate to the API Server from inside the cluster.
  • OIDC tokens: Integration with external identity providers (Google Identity, Okta, Azure AD). Preferred for enterprise—enables single sign-on and centralized user management.
  • Webhook token authentication: The API Server forwards tokens to an external service for validation.

⚠️ Common Misconception: Many beginners think Kubernetes has a built-in user database with passwords. It does not. There is no kubectl create user command. Users exist only in certificates, OIDC claims, or webhook responses.


6.1.3 Authorization: RBAC Deep Dive

Once the API Server knows who you are, it decides what you can do. Modern Kubernetes uses RBAC (Role-Based Access Control).

Analogy: The Building Keycard System

The security office maintains a permission matrix. "Floor 3 Employee" can access Floor 3 offices. "Building Manager" can access all floors. "Visitor" can only access the lobby. The matrix itself is the Role. When the security office assigns a keycard to a person, that's the RoleBinding. No keycard, no access.

In Kubernetes, RBAC uses four resource types:

Resource Scope Purpose
Role Namespace Defines permissions (verbs on resources) within one namespace
ClusterRole Cluster-wide Defines permissions across all namespaces or on cluster-level resources
RoleBinding Namespace Assigns a Role or ClusterRole to subjects within one namespace
ClusterRoleBinding Cluster-wide Assigns a ClusterRole to subjects across the entire cluster

Complete Role Example:

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

Bound subjects can read Pods but not create, update, or delete them.

ClusterRole Example:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: node-reader
rules:
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["get", "list"]

Nodes are cluster-scoped—they don't live in a namespace. Only a ClusterRole can grant access to them.

RoleBinding Example:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods-binding
  namespace: development
subjects:
- kind: ServiceAccount
  name: cicd-pipeline
  namespace: development
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

This RoleBinding connects the cicd-pipeline ServiceAccount to the pod-reader Role, granting it read-only Pod access in the development namespace. The subjects field accepts Users, Groups, or ServiceAccounts.

Key verbs: get, list, watch, create, update, patch, delete, impersonate, bind, escalate. Note escalate: controls whether a user can grant permissions they don't possess.

Default ClusterRoles:

Role Purpose
cluster-admin Full control over every resource. The superuser role.
admin Full control within a namespace, including RBAC inside it
edit Read/write most namespace-scoped resources, no RBAC management
view Read-only access to most namespace-scoped resources

A powerful pattern: bind ClusterRoles with a RoleBinding to scope them to one namespace. The ClusterRole defines permissions; the RoleBinding determines where they apply.

Visual Description: RBAC Resource Relationships

graph TD subgraph "Namespace: development" SA1[ServiceAccount<br/>cicd-pipeline] RB1[RoleBinding<br/>read-pods-binding] R1[Role<br/>pod-reader<br/>get/list/watch pods] end subgraph "Cluster Scope" CR1[ClusterRole<br/>node-reader<br/>get/list nodes] CRB1[ClusterRoleBinding<br/>node-reader-binding] SA2[ServiceAccount<br/>monitoring-agent] U1[User<br/>alice@company.com] end RB1 -->|references| R1 RB1 -->|binds to| SA1 CRB1 -->|references| CR1 CRB1 -->|binds to| SA2 CRB1 -->|binds to| U1 R1 -->|grants access to| PODS[pods in<br/>development] CR1 -->|grants access to| NODES[nodes<br/>cluster-wide] style SA1 fill:#90caf9 style SA2 fill:#90caf9 style U1 fill:#ce93d8 style R1 fill:#a5d6a7 style CR1 fill:#a5d6a7 style RB1 fill:#ffcc80 style CRB1 fill:#ffcc80 style PODS fill:#fff9c4 style NODES fill:#fff9c4

6.1.4 RBAC Best Practices

Avoid ClusterRole Unless Necessary. If a CI/CD pipeline only needs Deployments in dev, bind a Role to its ServiceAccount. Every unnecessary ClusterRole expands your blast radius.

Namespace-Scoped Roles for Teams. Give each team a namespace with a RoleBinding to the admin ClusterRole.

Audit Regularly:

# Check if the current user can create pods
kubectl auth can-i create pods

# Check if a specific ServiceAccount can delete secrets in a namespace
kubectl auth can-i delete secrets \
  --as=system:serviceaccount:development:cicd-pipeline \
  -n development

# List ALL permissions for a ServiceAccount
kubectl auth can-i --list \
  --as=system:serviceaccount:development:cicd-pipeline \
  -n development

Avoid Wildcard Permissions. Never use verbs: ["*"] or resources: ["*"] in production. Be explicit. Wildcards violate least privilege and make auditing nearly impossible.


🤔 TRY BEFORE YOU SEE

A developer needs to deploy to the staging namespace: create/update/delete Deployments and Services, read Pod logs. They must NOT modify Secrets, RBAC, or access other namespaces.

Design the RBAC objects yourself. How many Roles? What verbs? What binding?


Reveal: One Role with two rules (Deployments/Services: create/update/patch/delete; Pods: get/list; Pod logs: get), plus one RoleBinding. No ClusterRole needed—everything is namespace-scoped.


🛑 PAUSE & RECALL — 2 minutes

  1. What is the difference between a Role and a ClusterRole?
  2. Can a RoleBinding reference a ClusterRole? What does that mean in practice?
  3. What is the default RBAC behavior when no permission matches—allow or deny?

Rate your confidence (0-4).


6.1.5 GKE Security Integration

GKE Note: GKE integrates Kubernetes RBAC with Google Cloud IAM in a layered model. GKE operates two independent authorization layers: Cloud IAM controls who can access the GKE API (get-credentials, console access), and Kubernetes RBAC controls what users can do inside the cluster. Both must grant permission.

Common GKE IAM roles:

  • roles/container.admin: Full cluster administration
  • roles/container.clusterAdmin: Manage clusters but not K8s objects
  • roles/container.developer: Standard developer access
  • roles/container.viewer: Read-only access

Workload Identity. GKE's most powerful Pod-to-GCP authentication feature. Without it, a Pod accessing Cloud Storage would need a downloaded service account key—a static credential that could leak. With Workload Identity, a Kubernetes ServiceAccount maps to a GCP IAM service account, and the Pod receives a short-lived OAuth2 token automatically.

Visual Description: Workload Identity Flow

sequenceDiagram participant Pod as Pod (running app) participant KSA as Kubernetes<br/>ServiceAccount participant WI as Workload<br/>Identity Pool participant GCPIAM as Google Cloud IAM participant GCP as GCP Service<br/>(Cloud Storage, etc.) Note over Pod,KSA: Kubernetes cluster Note over WI,GCPIAM,GCP: Google Cloud Pod->>KSA: "Who am I?" KSA-->>Pod: JWT token (for KSA) Pod->>WI: Exchange KSA JWT for GCP token WI->>GCPIAM: Validate KSA + check IAM binding GCPIAM-->>WI: Short-lived OAuth2 access token WI-->>Pod: GCP access token Pod->>GCP: API request + OAuth2 token GCP-->>Pod: Response (data granted by IAM) style Pod fill:#90caf9 style KSA fill:#ffcc80 style WI fill:#a5d6a7 style GCPIAM fill:#ce93d8 style GCP fill:#ef9a9a

Identity-Aware Proxy (IAP). Adds an authentication layer in front of GKE workloads. Routes traffic through IAP to enforce Google Identity authentication—only authenticated users reach your applications.

VPC Service Controls. Creates security perimeters preventing data exfiltration from authorized GCP projects and regions. Even compromised credentials cannot transfer data outside the perimeter.


Lab: LAB-6.1 — RBAC in Practice (60 min)

Create a ServiceAccount, grant it limited permissions, verify they work, attempt unauthorized actions (and observe failures), and explore Workload Identity.

Part 1: Create Namespace and ServiceAccount

kubectl create namespace rbac-lab
kubectl create serviceaccount pod-reader-sa -n rbac-lab

Part 2: Create a Role

# pod-reader-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: rbac-lab
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch"]
kubectl apply -f pod-reader-role.yaml

Part 3: Create a RoleBinding

# pod-reader-binding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-reader-binding
  namespace: rbac-lab
subjects:
- kind: ServiceAccount
  name: pod-reader-sa
  namespace: rbac-lab
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io
kubectl apply -f pod-reader-binding.yaml

Part 4: Verify Authorized Access Works

# List pods (should succeed)
kubectl auth can-i list pods \
  --as=system:serviceaccount:rbac-lab:pod-reader-sa \
  -n rbac-lab
# Expected: yes

# Get a specific pod (should succeed)
kubectl auth can-i get pods \
  --as=system:serviceaccount:rbac-lab:pod-reader-sa \
  -n rbac-lab
# Expected: yes

Part 5: Attempt Unauthorized Actions (Expect Failure)

Each of these should fail. Observe the denials carefully—understanding what denial looks like is as important as understanding access.

# CREATE a pod (should fail — no create permission)
kubectl auth can-i create pods \
  --as=system:serviceaccount:rbac-lab:pod-reader-sa \
  -n rbac-lab
# Expected: no

# DELETE a pod (should fail — no delete permission)
kubectl auth can-i delete pods \
  --as=system:serviceaccount:rbac-lab:pod-reader-sa \
  -n rbac-lab
# Expected: no

# List pods in a DIFFERENT namespace (should fail — Role is namespace-scoped)
kubectl auth can-i list pods \
  --as=system:serviceaccount:rbac-lab:pod-reader-sa \
  -n default
# Expected: no

Part 6: List All Permissions

kubectl auth can-i --list \
  --as=system:serviceaccount:rbac-lab:pod-reader-sa \
  -n rbac-lab

Notice Pods show [get list watch] while everything else shows [].

Part 7: Configure Workload Identity (GKE)

GKE Note: Requires a GKE cluster with Workload Identity enabled.

# Create GCP service account
gcloud iam service-accounts create gke-lab-sa \
  --display-name="GKE Lab Workload Identity"

# Allow K8s SA to impersonate GCP SA
gcloud iam service-accounts add-iam-policy-binding \
  --role roles/iam.workloadIdentityUser \
  --member "serviceAccount:PROJECT_ID.svc.id.goog[rbac-lab/pod-reader-sa]" \
  gke-lab-sa@PROJECT_ID.iam.gserviceaccount.com

# Annotate the K8s ServiceAccount
kubectl annotate serviceaccount pod-reader-sa \
  --namespace rbac-lab \
  iam.gke.io/gcp-service-account=gke-lab-sa@PROJECT_ID.iam.gserviceaccount.com

Cleanup

kubectl delete namespace rbac-lab

Chapter Summary

This chapter covered Kubernetes security foundations. Every API request passes through three gates: Authentication, Authorization, and Admission Control. We explored the four RBAC resources and how they implement least privilege. You saw how GKE layers Cloud IAM on Kubernetes RBAC and how Workload Identity enables secure Pod-to-GCP authentication. The lab provided hands-on RBAC experience including permission verification and authorization failures.

📇 KEY CONCEPT CARDS

  1. Q: What are the three A's of Kubernetes security?
    A: Authentication (who are you?), Authorization (what can you do?), Admission Control (are you following the rules?). Requests flow through in that order.
  1. Q: Role vs. ClusterRole?
    A: A Role is namespace-scoped (permissions within one namespace). A ClusterRole is cluster-scoped (permissions on cluster-level resources or across all namespaces).
  1. Q: Default RBAC decision when no permission matches?
    A: Default deny. If no Role or ClusterRole grants the permission, the request is rejected with 403 Forbidden.
  1. Q: What is GKE Workload Identity?
    A: It maps a Kubernetes ServiceAccount to a GCP IAM service account, providing Pods with short-lived OAuth2 tokens instead of static credentials.