Warrior, now we're entering the Security phase of Kubernetes.
So far, we've focused on making applications:
Now we need to answer:
Who is allowed to do what inside the Kubernetes cluster?
For example:
Developer
โ
Can they delete production Pods?
Frontend Pod
โ
Can it access PostgreSQL?
Node.js API
โ
Can it read Kubernetes Secrets?
Monitoring system
โ
Can it inspect Pods?
Admin
โ
Can they modify everything?Kubernetes security is largely about controlling these permissions and reducing unnecessary access.
A useful simplified model is:
Kubernetes Security
โ
โโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโ
โผ โผ โผ
Authentication Authorization Workload Security
โ โ โ
โผ โผ โผ
"Who are you?" "What can you do?" "How does workload run?"
โ
โผ
RBACThere are several layers:
Identity
โ
Authentication
โ
Authorization
โ
RBAC
โ
Pod / Container Security
โ
Network Security
โ
Secret ManagementWe'll study NetworkPolicy separately in Chapter 20.
This is one of the most important security concepts.
Authentication asks:
Who are you?
Examples:
User = Anubhav
ServiceAccount = node-apiAuthorization asks:
What are you allowed to do?
For example:
Anubhav
โ
Can read Pods? โ
Can delete Pods? โSo:
Authentication
= Who are you?
Authorization
= What can you do?Imagine your production cluster.
Developer:
developer@company.comThey should perhaps be able to:
get pods
get logs
describe deploymentsBut maybe not:
delete namespace
delete production database
modify cluster-wide configurationSo Kubernetes needs an authorization mechanism.
That's where:
comes in.
RBAC stands for:
Role-Based Access Control
Instead of giving permissions individually to every person, you define roles.
Example:
Developer Role
โ
โโโ get Pods
โโโ list Pods
โโโ get Logs
โโโ describe DeploymentsThen assign the role to users or ServiceAccounts.
Think:
WHO
โ
โผ
RoleBinding
โ
โผ
Role
โ
โผ
PermissionsMore accurately:
User / Group / ServiceAccount
โ
โผ
RoleBinding
โ
โผ
Role
โ
โผ
API permissionsFor cluster-wide permissions:
User / Group / ServiceAccount
โ
โผ
ClusterRoleBinding
โ
โผ
ClusterRoleA Kubernetes Role defines permissions within a namespace.
Example:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: development
rules:
- apiGroups: [""]
resources:
- pods
verbs:
- get
- list
- watchThis means:
In the
developmentnamespace, this Role allows reading Pods.
It does not automatically grant access to every namespace.
rules#This section:
rules:
- apiGroups: [""]
resources:
- pods
verbs:
- get
- list
- watchcontains three important pieces.
pods
deployments
services
secrets
configmapsget
list
watch
create
update
patch
deletePods belong to the core API group:
apiGroups: [""]Deployments belong to:
apps| Verb | Meaning |
|---|---|
get |
Read one resource |
list |
List resources |
watch |
Watch changes |
create |
Create resource |
update |
Replace/update resource |
patch |
Partially modify resource |
delete |
Delete resource |
Example:
get podsmeans:
Read a specific Pod.
list podsmeans:
List Pods.
Creating a Role isn't enough.
You need to connect that Role to an identity.
That's what:
RoleBinding
does.
Example:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-binding
namespace: development
subjects:
- kind: User
name: developer@example.com
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.ioArchitecture:
developer@example.com
โ
โผ
RoleBinding
โ
โผ
pod-reader Role
โ
โผ
get/list/watch PodsDon't confuse these.
Defines:
What permissions exist?
Defines:
Who gets those permissions?
Memory trick:
Role
= Rules
RoleBinding
= AssignmentLet's say:
Namespace = developmentWe want:
developer@example.comto read Pods.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: development
rules:
- apiGroups: [""]
resources:
- pods
verbs:
- get
- list
- watchapiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-binding
namespace: development
subjects:
- kind: User
name: developer@example.com
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.ioNow:
developer
โ
RoleBinding
โ
pod-reader
โ
Pods
โโโ get โ
โโโ list โ
โโโ watch โ
โโโ delete โYou could give:
cluster-adminto everyone.
But that's dangerous.
Imagine:
Developer
โ
kubectl delete namespace productionIf they have unrestricted permissions:
๐ฅ Production destroyedInstead:
Developer
โ
Only required permissionsThis is called:
The rule is:
Give an identity only the permissions it actually needs.
For example:
A monitoring service might need:
get pods
list pods
watch podsIt probably doesn't need:
delete pods
delete namespaces
create clusterrolesSo:
Required permissions
โ
onlynot:
Everything
โ
just in caseA Role is namespace-scoped.
A:
ClusterRole
can define permissions usable at cluster scope and can also be bound into namespaces depending on how it's referenced.
Example:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-reader
rules:
- apiGroups: [""]
resources:
- nodes
verbs:
- get
- list
- watchNodes aren't namespace-scoped resources.
So cluster-level access is appropriate here.
To give that ClusterRole to a user:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: node-reader-binding
subjects:
- kind: User
name: developer@example.com
roleRef:
kind: ClusterRole
name: node-reader
apiGroup: rbac.authorization.k8s.ioNow:
Developer
โ
ClusterRoleBinding
โ
ClusterRole
โ
Nodes| Feature | Role | ClusterRole |
|---|---|---|
| Namespace-scoped definition | โ | Can be used |
| Cluster-scoped resources | โ | โ |
| Nodes | โ | โ |
| Namespace-local Pods | โ | โ |
| Typical use | App/team permissions | Cluster-wide permissions |
A ClusterRole can be bound with a RoleBinding to grant its rules within a particular namespace, which is a useful pattern for reusable permission sets.
So far we've talked about humans.
But applications also need identities.
Suppose:
Node.js API Podneeds to communicate with the Kubernetes API.
What identity does it use?
A:
ServiceAccount
A ServiceAccount provides an identity for workloads running inside Kubernetes.
Think:
Human
โ
User identity
Pod
โ
ServiceAccount identityExample:
apiVersion: v1
kind: ServiceAccount
metadata:
name: node-api
namespace: productionThen:
spec:
serviceAccountName: node-apiNow the Pod runs using that ServiceAccount identity.
Imagine an internal operator or controller.
It may need to:
List Pods
Watch Deployments
Read ConfigMapsInstead of giving it an administrator identity:
Pod
โ
ServiceAccount
โ
Minimal RoleExample:
apiVersion: v1
kind: Role
metadata:
name: pod-reader
namespace: production
rules:
- apiGroups: [""]
resources:
- pods
verbs:
- get
- list
- watchServiceAccount:
apiVersion: v1
kind: ServiceAccount
metadata:
name: monitoring-app
namespace: productionRoleBinding:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: monitoring-binding
namespace: production
subjects:
- kind: ServiceAccount
name: monitoring-app
namespace: production
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.ioArchitecture:
Monitoring Pod
โ
โผ
ServiceAccount
โ
โผ
RoleBinding
โ
โผ
Role
โ
โผ
get/list/watch PodsDon't give every Pod:
cluster-adminInstead:
Pod
โ
Dedicated ServiceAccount
โ
Minimal RBAC permissionsThis dramatically reduces blast radius.
Pods can use a namespace's default ServiceAccount if you don't specify one.
For example:
kubectl get serviceaccountsYou may see:
NAME SECRETS
default ...However, production workloads should generally use an explicitly chosen ServiceAccount when they need permissions.
If your application doesn't need to communicate with the Kubernetes API, consider:
automountServiceAccountToken: falseExample:
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 3
template:
metadata:
labels:
app: frontend
spec:
automountServiceAccountToken: false
containers:
- name: frontend
image: my-frontend:1.0This reduces unnecessary credentials exposure to the application.
We covered Secrets in Chapter 9.
A Kubernetes Secret is useful for sensitive configuration, but don't assume:
Secret
=
Automatically encrypted everywhereImportant considerations include:
Remember:
data:
password: bXlQYXNzd29yZA==That is Base64 encoding.
Someone can decode it.
Conceptually:
Base64
โ
Encoding
โ
EncryptionNever treat Base64 as a security mechanism.
Production environments often integrate with secret-management systems such as:
AWS Secrets Manager
Google Secret Manager
Azure Key Vault
HashiCorp VaultArchitecture:
External Secret Manager
โ
โผ
Kubernetes integration
โ
โผ
Secret
โ
โผ
PodThis can reduce the need to store long-lived plaintext credentials directly in application manifests.
Now let's move from API authorization to container security.
Kubernetes supports:
securityContext
It controls security-related settings for Pods and containers.
For example:
securityContext:
runAsNonRoot: trueThis means:
The container should not run as root.
Suppose your application is compromised.
If it runs as root:
Attacker
โ
Compromised application
โ
Root privileges
โ
Potentially greater impactIf it runs as a non-root user:
Attacker
โ
Compromised application
โ
Limited privilegesThis is an example of reducing blast radius.
runAsUser#You can specify a user ID:
securityContext:
runAsUser: 10001
runAsNonRoot: trueNow the container process should run as UID:
10001Your Docker image must be compatible with this user.
readOnlyRootFilesystem#You can make the container's root filesystem read-only:
securityContext:
readOnlyRootFilesystem: trueThen:
Application
โ
Cannot normally write to root filesystemIf the application needs temporary writable storage, you can mount a writable volume such as emptyDir at a specific path.
Linux capabilities provide subsets of privileged operations.
You can drop capabilities:
securityContext:
capabilities:
drop:
- ALLThen selectively add only what is genuinely required.
This follows the same principle:
Least privilege.
apiVersion: v1
kind: Pod
metadata:
name: secure-app
spec:
securityContext:
runAsNonRoot: true
containers:
- name: app
image: my-node-api:1.0
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALLThis is a good starting pattern, but your application must actually be compatible with these restrictions.
allowPrivilegeEscalation#Consider:
allowPrivilegeEscalation: falseThis helps prevent a process from gaining more privileges than its parent process allows through supported Linux privilege mechanisms.
Again:
Security settings should be tested against your application rather than copied blindly.
Avoid:
securityContext:
privileged: trueunless there is a well-understood infrastructure requirement.
A privileged container has substantially elevated access to the host.
For ordinary:
Node.js
Python
Next.js
Nginxapplications, privileged mode is generally unnecessary.
Kubernetes provides Pod Security Standards with profiles commonly described as:
Privileged
Baseline
RestrictedConceptually:
Privileged
โ
More permissions
Baseline
โ
Common restrictions
Restricted
โ
Stronger hardeningFor production workloads, stronger restrictions are generally desirable when the application supports them.
Pod security controls can be applied through namespace labels.
For example, a namespace can be configured to enforce a Pod Security Standard level.
Conceptually:
Namespace: production
โ
โผ
Pod Security policy level
โ
โผ
Pods must satisfy restrictionsThis helps prevent developers from accidentally deploying overly privileged workloads.
Now let's combine everything:
Kubernetes Security
โ
โโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโ
โผ โผ โผ
Identity RBAC Workload
โ โ Security
โผ โผ โผ
User/ServiceAccount Role SecurityContext
โ
RoleBinding
โ
โผ
PermissionsThen networking:
NetworkPolicy
โ
โผ
Pod-to-Pod trafficWe'll study this in Chapter 20.
Imagine:
production
โ
โโโ frontend
โโโ backend
โโโ redis
โโโ workerYou might design identities like:
frontend-sa
backend-sa
worker-saAnd permissions:
frontend-sa
โ almost no Kubernetes API permissions
backend-sa
โ only required API permissions
worker-sa
โ only required API permissionsArchitecture:
Frontend Pod
โ
โผ
frontend-sa
โ
โผ
Minimal permissions
Backend Pod
โ
โผ
backend-sa
โ
โผ
Required permissions only
Worker Pod
โ
โผ
worker-sa
โ
โผ
Required permissions onlySuppose your Node.js backend needs to watch a ConfigMap.
Create:
apiVersion: v1
kind: ServiceAccount
metadata:
name: backend-sa
namespace: productionRole:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: backend-config-reader
namespace: production
rules:
- apiGroups: [""]
resources:
- configmaps
verbs:
- get
- list
- watchRoleBinding:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: backend-config-reader-binding
namespace: production
subjects:
- kind: ServiceAccount
name: backend-sa
namespace: production
roleRef:
kind: Role
name: backend-config-reader
apiGroup: rbac.authorization.k8s.ioDeployment:
spec:
template:
spec:
serviceAccountName: backend-saNow:
Backend
โ
backend-sa
โ
RoleBinding
โ
Role
โ
ConfigMapOne extremely useful command:
kubectl auth can-i get podsThis asks:
Can the current identity get Pods?
You can test:
kubectl auth can-i delete podsMaybe:
noExcellent.
You can also check as a specific user or ServiceAccount:
kubectl auth can-i get pods \
--as=system:serviceaccount:production:backend-saAnd:
kubectl auth can-i delete pods \
--as=system:serviceaccount:production:backend-saThis is very useful for debugging RBAC.
Giving every application:
cluster-adminโ Extremely broad permissions.
Using one ServiceAccount for everything.
All Pods
โ
same identityโ Large blast radius.
Storing secrets in Git.
DATABASE_PASSWORD=myPassword123โ Dangerous.
Thinking Base64 is encryption.
Base64 โ encryptionRunning everything as root.
rootโ Unnecessary privilege.
Using:
privileged: truewithout a strong reason.
Giving applications Kubernetes API permissions they don't need.
A production-oriented application could look like:
Kubernetes Cluster
โ
โโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโ
โ โ โ
โผ โผ โผ
Frontend Backend Worker
โ โ โ
โผ โผ โผ
frontend-sa backend-sa worker-sa
โ โ โ
โผ โผ โผ
Minimal RBAC Required RBAC Required RBAC
โ
โผ
Kubernetes API
Secrets
โ
โผ
External Secret Manager
โ
โผ
Kubernetes
Secrets
NetworkPolicy
โ
โผ
Pod-to-Pod restrictionsFor a human:
Developer
โ
โผ
Identity Provider / Cluster Auth
โ
โผ
Authenticated identity
โ
โผ
RBAC
โ
โผ
Kubernetes APIFor a Pod:
Pod
โ
โผ
ServiceAccount
โ
โผ
RBAC
โ
โผ
Kubernetes APIAlmost every Kubernetes security decision can be simplified to:
Give the smallest amount of access required for the shortest reasonable scope.
That means:
Namespace scope
over
Cluster scopewhen possible.
Specific resource
over
All resourcesRead-only
over
WriteNon-root
over
RootDedicated ServiceAccount
over
Shared powerful identityRole-Based Access Control is Kubernetes' authorization mechanism for controlling what users, groups, and ServiceAccounts can do with Kubernetes resources.
Role
โ permissions
RoleBinding
โ assigns permissionsRole
โ namespace-oriented
ClusterRole
โ cluster-wide resource permissions and reusable permission definitionsAn identity used by workloads running inside Kubernetes.
User
โ typically human/external identity
ServiceAccount
โ workload identityAuthentication
โ Who are you?
Authorization
โ What can you do?Grant only the permissions required to perform the intended task.
To reduce the potential impact if the application or container is compromised.
Not automatically merely because it is a Secret object. Security depends on configuration such as encryption at rest, access controls, and how secrets are handled.
No.
Tolerations are about Pod scheduling onto tainted nodes, not RBAC.
Authentication
โ
"Who are you?"
Authorization
โ
"What can you do?"
RBAC
โ
PermissionsRole
โ
Permissions
RoleBinding
โ
Who gets Role?
ClusterRole
โ
Cluster-level/reusable permissions
ClusterRoleBinding
โ
Who gets ClusterRole?Pod
โ
ServiceAccount
โ
RBACsecurityContext
โโโ runAsNonRoot
โโโ runAsUser
โโโ readOnlyRootFilesystem
โโโ allowPrivilegeEscalation
โโโ capabilitiesLeast privilege everywhere.
For the Node.js/Next.js platform we've been building:
USER
โ
โผ
Ingress
โ
โผ
Service
โ
โผ
โโโโโโโโโโโโโโโโ
โ Node.js API โ
โ Pod โ
โโโโโโโโฌโโโโโโโโ
โ
ServiceAccount
โ
โผ
RBAC
โ
Only required
Kubernetes API
permissions
โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
โผ โผ
Secrets SecurityContext
โ โ
โผ โผ
External Secret Manager Non-root
Read-only FS
No privilege escalation
โ
โผ
NetworkPolicy
โ
โผ
Allowed Pod trafficYou now have the foundation for securing a production Kubernetes application.
This is the natural next step.
We'll answer:
"If every Pod can potentially communicate over the cluster network, how do I control who can talk to whom?"
We'll build rules like:
Internet
โ
โผ
Ingress
โ
โผ
Frontend
โ
โผ
Backend โ
โ
โโโ PostgreSQL โ
โโโ Redis โ
โโโ Other Pods โWe'll cover Ingress/Egress policies, default-deny, labels, namespaces, DNS access, PostgreSQL/Redis isolation, and real production NetworkPolicy YAML.
Mark it as complete to track your mastery.