Security - Comprehensive Study Guide
category: Kubernetes Certification
tags: cka, kubernetes, exam, kubectl, certification
WHY Security Matters (Conceptual Foundation)
Kubernetes as a Multi-Tenant Platform
Security in Kubernetes is about controlling access and enforcing boundaries in a shared platform:
- Identity and Access Management - Who can do what to which resources
- Resource Isolation - Preventing workloads from interfering with each other
- Network Segmentation - Controlling communication between services
- Process and Container Security - Limiting privileges and attack surface
- Data Protection - Securing secrets, configurations, and persistent data
Exam Context: Why Security Mastery is Critical
- 25% of exam content focuses on security configuration and troubleshooting
- Cluster hardening - Common exam scenarios for RBAC, NetworkPolicies
- Pod security - SecurityContext configuration and debugging
- Authentication/authorization - ServiceAccount and permission troubleshooting
- Network isolation - Creating and debugging NetworkPolicy restrictions
Key Insight: Kubernetes security is layered defense - no single mechanism provides complete protection. Understanding how RBAC, SecurityContext, and NetworkPolicies work together is essential.
Security Architecture Overview
The Kubernetes Security Model
┌─────────────────────────────────────────────────────────────┐
│ SECURITY LAYERS │
│ │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ Network Security ││
│ │ NetworkPolicies, Ingress/Egress Control ││
│ └─────────────────────────────────────────────────────────┘│
│ ┌─────────────────────────────────────────────────────────┐│
│ │ Runtime Security ││
│ │ SecurityContext, PodSecurityPolicy, Admission ││
│ └─────────────────────────────────────────────────────────┘│
│ ┌─────────────────────────────────────────────────────────┐│
│ │ Identity & Access (RBAC) ││
│ │ Users, ServiceAccounts, Roles, RoleBindings ││
│ └─────────────────────────────────────────────────────────┘│
│ ┌─────────────────────────────────────────────────────────┐│
│ │ API Server Security ││
│ │ Authentication, Authorization, Admission Control ││
│ └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘
Security Request Flow
┌──────────────┐ ┌─────────────────┐ ┌────────────────┐
│ kubectl │───▶│ Authentication │───▶│ Authorization │
│ (client) │ │ (who are you?) │ │ (what can you │
│ │ │ │ │ do?) │
└──────────────┘ └─────────────────┘ └────────────────┘
│
┌─────────────────┐ ▼
│ Pod Created │ ┌────────────────┐
│ with Security │◀───│ Admission │
│ Context │ │ Controllers │
└─────────────────┘ │ (policy │
│ enforcement) │
└────────────────┘
Conceptual Model: Every request flows through Authentication → Authorization → Admission Control, then runtime security is enforced via SecurityContext and NetworkPolicies.
RBAC (Role-Based Access Control)
What RBAC Does (Conceptual)
RBAC is the authorization engine that answers "what can this identity do?":
- Subject - Who is making the request (User, ServiceAccount)
- Verb - What action is being attempted (get, create, delete)
- Resource - What object is being accessed (pods, services, secrets)
- Namespace - Where the action is taking place (optional scope)
RBAC Components Architecture
┌─────────────────────────────────────────────────────────────┐
│ RBAC Model │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ Subject │ │ Binding │ │ Role │ │
│ │ │ │ │ │ │ │
│ │ • User │◀───│ • RoleB │───▶│ • Rules │ │
│ │ • SA │ │ • ClusterRB │ │ • Verbs │ │
│ │ • Group │ │ │ │ • Resources │ │
│ └─────────────┘ └─────────────┘ └─────────────────┘ │
│ │
│ Example: ServiceAccount "api-service" has RoleBinding │
│ that grants Role "pod-reader" permissions │
└─────────────────────────────────────────────────────────────┘
Basic RBAC Objects
Role and RoleBinding (Namespace-scoped)
# Role defines permissions within a namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: development
name: pod-manager
rules:
- apiGroups: [""] # Core API group
resources: ["pods"]
verbs: ["get", "list", "create", "delete"]
- apiGroups: [""]
resources: ["pods/log"] # Subresources
verbs: ["get"]
- apiGroups: ["apps"] # apps API group
resources: ["deployments"]
verbs: ["get", "list", "create", "update", "patch"]
---
# RoleBinding grants Role to subjects
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-manager-binding
namespace: development
subjects:
- kind: User
name: jane.doe
apiGroup: rbac.authorization.k8s.io
- kind: ServiceAccount
name: api-service
namespace: development
roleRef:
kind: Role
name: pod-manager
apiGroup: rbac.authorization.k8s.io
ClusterRole and ClusterRoleBinding (Cluster-scoped)
# ClusterRole for cluster-wide permissions
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-reader
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list"]
- apiGroups: ["metrics.k8s.io"]
resources: ["nodes", "pods"]
verbs: ["get", "list"]
---
# ClusterRoleBinding grants ClusterRole to subjects
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: monitoring-team
subjects:
- kind: Group
name: monitoring-team
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: node-reader
apiGroup: rbac.authorization.k8s.io
Advanced RBAC Patterns
Resource Names and Wildcards
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: specific-pod-access
rules:
# Access specific pods by name
- apiGroups: [""]
resources: ["pods"]
resourceNames: ["web-pod-1", "web-pod-2"] # Specific resources
verbs: ["get", "delete"]
# Access all configmaps but only specific operations
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"] # No create/update/delete
# Wildcard access to all resources in apps group
- apiGroups: ["apps"]
resources: ["*"] # All resources
verbs: ["get", "list"]
# Access subresources
- apiGroups: [""]
resources: ["pods/exec", "pods/portforward"]
verbs: ["create"]
Service Account with Multiple Roles
# ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: microservice-sa
namespace: application
---
# Role 1: Pod management
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: application
name: pod-operator
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "create", "delete"]
---
# Role 2: ConfigMap management
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: application
name: config-reader
rules:
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "list"]
---
# Binding 1
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: microservice-pod-binding
namespace: application
subjects:
- kind: ServiceAccount
name: microservice-sa
namespace: application
roleRef:
kind: Role
name: pod-operator
apiGroup: rbac.authorization.k8s.io
---
# Binding 2
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: microservice-config-binding
namespace: application
subjects:
- kind: ServiceAccount
name: microservice-sa
namespace: application
roleRef:
kind: Role
name: config-reader
apiGroup: rbac.authorization.k8s.io
RBAC Troubleshooting
Testing Permissions
# Check if current user can perform action
kubectl auth can-i create pods
kubectl auth can-i delete pods --namespace=production
kubectl auth can-i "*" "*" # All permissions
# Check permissions for other users/service accounts
kubectl auth can-i create pods --as=system:serviceaccount:default:my-sa
kubectl auth can-i get nodes --as=jane.doe
# List all permissions for a service account
kubectl auth can-i --list --as=system:serviceaccount:default:my-sa
# Debug permission denials
kubectl get events --sort-by='.lastTimestamp' | grep -i forbidden
kubectl logs -n kube-system kube-apiserver-master | grep -i "forbidden\|unauthorized"
Common RBAC Issues
# Issue 1: ServiceAccount doesn't exist
# Error: "User system:serviceaccount:default:non-existent cannot create pods"
kubectl get serviceaccount non-existent # Check if SA exists
kubectl create serviceaccount missing-sa # Create if missing
# Issue 2: No RoleBinding exists
# Error: "User system:serviceaccount:default:my-sa cannot create pods"
kubectl get rolebindings,clusterrolebindings --all-namespaces | grep my-sa
# Issue 3: Wrong namespace in RoleBinding
# Check that RoleBinding and ServiceAccount are in same namespace
kubectl get rolebinding -n correct-namespace
kubectl get serviceaccount my-sa -n correct-namespace
# Issue 4: Insufficient permissions in Role
kubectl describe role my-role -n my-namespace
# Verify that required verbs and resources are included
ServiceAccounts: Identity for Pods
What ServiceAccounts Do (Conceptual)
ServiceAccounts provide identity for pods to authenticate with the API server:
- Pod Identity - Every pod runs with a ServiceAccount identity
- API Authentication - ServiceAccounts use JWT tokens for API calls
- RBAC Integration - ServiceAccounts are subjects in RBAC bindings
- Namespace Scoped - ServiceAccounts belong to specific namespaces
- Automatic Token Mounting - Tokens automatically mounted in pods
ServiceAccount Architecture
┌─────────────────────────────────────────────────────────────┐
│ ServiceAccount Flow │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ Pod │───▶│ SA Token │───▶│ API Server │ │
│ │ │ │ (JWT) │ │ Authentication │ │
│ │/var/run/ │ │ │ │ │ │
│ │secrets/k8s..│ │ │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────────┐ │
│ │ Mounted │ │ RBAC Check │ │
│ │ Token │ │ (what can this │ │
│ │ Files │ │ SA do?) │ │
│ └─────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘
ServiceAccount Creation and Management
Basic ServiceAccount
# ServiceAccount definition
apiVersion: v1
kind: ServiceAccount
metadata:
name: application-sa
namespace: production
automountServiceAccountToken: true # Default: true
---
# Using ServiceAccount in Pod
apiVersion: v1
kind: Pod
metadata:
name: app-pod
namespace: production
spec:
serviceAccountName: application-sa # Use specific SA
containers:
- name: app
image: myapp:latest
# Token automatically mounted at:
# /var/run/secrets/kubernetes.io/serviceaccount/token
# /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
# /var/run/secrets/kubernetes.io/serviceaccount/namespace
ServiceAccount with RBAC
# Complete ServiceAccount setup
apiVersion: v1
kind: ServiceAccount
metadata:
name: pod-reader-sa
namespace: monitoring
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: monitoring
name: pod-reader-role
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-binding
namespace: monitoring
subjects:
- kind: ServiceAccount
name: pod-reader-sa
namespace: monitoring
roleRef:
kind: Role
name: pod-reader-role
apiGroup: rbac.authorization.k8s.io
---
# Pod using the ServiceAccount
apiVersion: apps/v1
kind: Deployment
metadata:
name: monitoring-app
namespace: monitoring
spec:
replicas: 1
selector:
matchLabels:
app: monitoring
template:
metadata:
labels:
app: monitoring
spec:
serviceAccountName: pod-reader-sa
containers:
- name: monitor
image: monitor:latest
# Application can now call Kubernetes API
# using mounted token with pod read permissions
ServiceAccount Token Management
Token Mounting and Access
# Inside a pod, ServiceAccount token is mounted at:
ls -la /var/run/secrets/kubernetes.io/serviceaccount/
# token - JWT token for API authentication
# ca.crt - Cluster CA certificate
# namespace - Current namespace
# Using the token to call API
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
curl -H "Authorization: Bearer $TOKEN" \
--cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
https://kubernetes.default.svc.cluster.local/api/v1/namespaces/$NAMESPACE/pods
Disabling Token Mounting
# ServiceAccount with token mounting disabled
apiVersion: v1
kind: ServiceAccount
metadata:
name: no-token-sa
namespace: production
automountServiceAccountToken: false
---
# Pod can override ServiceAccount setting
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
serviceAccountName: no-token-sa
automountServiceAccountToken: false # Explicitly disable
containers:
- name: app
image: myapp
# No token mounted in this pod
ServiceAccount Security Best Practices
Least Privilege ServiceAccounts
# Specific SA for each application component
apiVersion: v1
kind: ServiceAccount
metadata:
name: web-frontend-sa
namespace: ecommerce
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: ecommerce
name: frontend-role
rules:
# Only permissions needed by frontend
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["frontend-config"] # Specific configmap only
verbs: ["get"]
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["frontend-secrets"] # Specific secret only
verbs: ["get"]
---
# Separate SA for backend with different permissions
apiVersion: v1
kind: ServiceAccount
metadata:
name: api-backend-sa
namespace: ecommerce
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: ecommerce
name: backend-role
rules:
# Backend needs more permissions
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"] # Monitor other pods
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "list"] # Access configuration
SecurityContext: Process and Container Security
What SecurityContext Does (Conceptual)
SecurityContext controls the runtime security settings for pods and containers:
- User and Group IDs - What user/group processes run as
- Capabilities - Linux capabilities granted or dropped
- Privilege Escalation - Whether processes can gain additional privileges
- Read-only Root Filesystem - Prevents filesystem modifications
- SELinux/AppArmor - Mandatory access control integration
SecurityContext Levels
┌─────────────────────────────────────────────────────────────┐
│ SecurityContext Hierarchy │
│ │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ PodSecurityContext ││
│ │ (applies to all containers) ││
│ └─────────────────────────────────────────────────────────┘│
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ Container SecurityContext ││
│ │ (overrides pod settings) ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ Container settings take precedence over Pod settings │
└─────────────────────────────────────────────────────────────┘
Pod SecurityContext
Basic Pod Security Settings
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
securityContext:
# Run as non-root user
runAsNonRoot: true
runAsUser: 1000 # Specific user ID
runAsGroup: 3000 # Specific group ID
fsGroup: 2000 # Volume ownership group
# Security profiles
seccompProfile:
type: RuntimeDefault # Use runtime default seccomp profile
# SELinux context (if SELinux enabled)
seLinuxOptions:
level: "s0:c123,c456"
# Sysctls (kernel parameters)
sysctls:
- name: net.core.somaxconn
value: "1024"
containers:
- name: app
image: nginx:1.20
securityContext:
# Container-specific overrides
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE # Allow binding to privileged ports
# Writable volumes for read-only root filesystem
volumeMounts:
- name: tmp-volume
mountPath: /tmp
- name: var-cache
mountPath: /var/cache/nginx
- name: var-run
mountPath: /var/run
volumes:
- name: tmp-volume
emptyDir: {}
- name: var-cache
emptyDir: {}
- name: var-run
emptyDir: {}
Container SecurityContext
Advanced Security Configuration
apiVersion: v1
kind: Pod
metadata:
name: hardened-pod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
containers:
- name: web
image: nginx:alpine
securityContext:
# Prevent privilege escalation
allowPrivilegeEscalation: false
# Read-only root filesystem
readOnlyRootFilesystem: true
# Drop all capabilities, add only what's needed
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE # nginx needs to bind to port 80
- CHOWN # nginx needs to change file ownership
- SETUID # nginx needs to switch users
- SETGID # nginx needs to switch groups
# Seccomp profile for syscall filtering
seccompProfile:
type: Localhost
localhostProfile: nginx-seccomp.json
# Required volumes for read-only root filesystem
volumeMounts:
- name: nginx-cache
mountPath: /var/cache/nginx
- name: nginx-run
mountPath: /var/run
- name: tmp
mountPath: /tmp
# Init container to set up volumes with correct permissions
initContainers:
- name: setup
image: busybox
securityContext:
runAsUser: 0 # Root needed for setup
command:
- /bin/sh
- -c
- |
mkdir -p /var/cache/nginx /var/run
chown 1000:2000 /var/cache/nginx /var/run /tmp
chmod 755 /var/cache/nginx /var/run /tmp
volumeMounts:
- name: nginx-cache
mountPath: /var/cache/nginx
- name: nginx-run
mountPath: /var/run
- name: tmp
mountPath: /tmp
volumes:
- name: nginx-cache
emptyDir: {}
- name: nginx-run
emptyDir: {}
- name: tmp
emptyDir: {}
Privileged and Host Access
Privileged Containers (Avoid in Production)
# WARNING: Privileged containers have full host access
apiVersion: v1
kind: Pod
metadata:
name: privileged-pod
spec:
containers:
- name: privileged-container
image: busybox
securityContext:
privileged: true # Full host access - dangerous!
# Can access all host devices, kernel modules, etc.
# Use only for system-level utilities like CNI, CSI drivers
Host Namespace Access
# System monitoring pod (like node-exporter)
apiVersion: v1
kind: Pod
metadata:
name: system-monitor
spec:
# Host namespace access
hostNetwork: true # Use host networking
hostPID: true # See host processes
hostIPC: true # Access host IPC
containers:
- name: monitor
image: prom/node-exporter
securityContext:
runAsNonRoot: true
runAsUser: 65534 # nobody user
ports:
- containerPort: 9100
hostPort: 9100 # Expose on host
volumeMounts:
- name: proc
mountPath: /host/proc
readOnly: true
- name: sys
mountPath: /host/sys
readOnly: true
volumes:
- name: proc
hostPath:
path: /proc
- name: sys
hostPath:
path: /sys
# Allow on all nodes including masters
tolerations:
- operator: Exists
SecurityContext Troubleshooting
Common Security Issues
# Issue 1: Permission denied errors
kubectl logs pod-name
# Look for: "Permission denied", "Operation not permitted"
# Solution: Check runAsUser, fsGroup, volume permissions
# Issue 2: Cannot bind to privileged ports
kubectl describe pod pod-name
# Error: "bind: permission denied" for ports < 1024
# Solution: Add NET_BIND_SERVICE capability
# Issue 3: Read-only filesystem errors
kubectl logs pod-name
# Error: "Read-only file system"
# Solution: Mount writable volumes for temp directories
# Issue 4: SELinux/AppArmor denials
# Check node logs for SELinux/AppArmor messages
sudo ausearch -m AVC # SELinux denials
sudo dmesg | grep apparmor # AppArmor denials
Security Validation
# Check effective user/group in running container
kubectl exec pod-name -- id
kubectl exec pod-name -- ps aux
# Verify capabilities
kubectl exec pod-name -- grep Cap /proc/self/status
# Check filesystem permissions
kubectl exec pod-name -- ls -la /
kubectl exec pod-name -- touch /test-write # Should fail with read-only root
# Verify seccomp profile
kubectl exec pod-name -- grep Seccomp /proc/self/status
NetworkPolicies: Traffic Segmentation
What NetworkPolicies Do (Conceptual)
NetworkPolicies provide microsegmentation at the pod level:
- Default Deny - Block all traffic unless explicitly allowed
- Pod Selection - Target specific pods using label selectors
- Traffic Direction - Control ingress (incoming) and egress (outgoing)
- Namespace Isolation - Segment traffic between namespaces
- Protocol and Port Control - Layer 4 traffic filtering
NetworkPolicy Architecture
┌─────────────────────────────────────────────────────────────┐
│ NetworkPolicy Model │
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Frontend │ │ Database │ │
│ │ Pods │──── ✓ ALLOWED ────────────│ Pods │ │
│ │ │ │ │ │
│ └─────────────┘ └─────────────┘ │
│ │ ▲ │
│ ▼ │ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ External │──── ✗ DENIED ─────────────│ Database │ │
│ │ Traffic │ │ Pods │ │
│ │ │ │ │ │
│ └─────────────┘ └─────────────┘ │
│ │
│ NetworkPolicy selects Database pods and allows only │
│ ingress from Frontend pods on specific ports │
└─────────────────────────────────────────────────────────────┘
Important: NetworkPolicies are additive - multiple policies selecting the same pods combine their rules.
Basic NetworkPolicy Patterns
Default Deny All Traffic
# Deny all ingress traffic to all pods in namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
namespace: production
spec:
podSelector: {} # Selects all pods in namespace
policyTypes:
- Ingress
# No ingress rules = deny all ingress
---
# Deny all egress traffic from all pods in namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-egress
namespace: production
spec:
podSelector: {} # Selects all pods in namespace
policyTypes:
- Egress
# No egress rules = deny all egress
---
# Deny all ingress AND egress (complete isolation)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Allow Specific Pod-to-Pod Communication
# Allow frontend to access backend on specific port
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: application
spec:
podSelector:
matchLabels:
tier: backend # Policy applies to backend pods
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
tier: frontend # Allow from frontend pods
ports:
- protocol: TCP
port: 8080
Advanced NetworkPolicy Patterns
Multi-tier Application Security
# Web tier: Allow ingress from internet, egress to API tier
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: web-tier-policy
namespace: ecommerce
spec:
podSelector:
matchLabels:
tier: web
policyTypes:
- Ingress
- Egress
ingress:
- {} # Allow all ingress (internet traffic)
egress:
- to:
- podSelector:
matchLabels:
tier: api
ports:
- protocol: TCP
port: 8080
- to: {} # Allow DNS resolution
ports:
- protocol: UDP
port: 53
---
# API tier: Allow ingress from web tier, egress to database tier
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-tier-policy
namespace: ecommerce
spec:
podSelector:
matchLabels:
tier: api
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
tier: web
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
tier: database
ports:
- protocol: TCP
port: 5432
- to: {} # Allow DNS
ports:
- protocol: UDP
port: 53
---
# Database tier: Allow ingress only from API tier
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database-tier-policy
namespace: ecommerce
spec:
podSelector:
matchLabels:
tier: database
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
tier: api
ports:
- protocol: TCP
port: 5432
egress:
- to: {} # Allow DNS only
ports:
- protocol: UDP
port: 53
Namespace-based Isolation
# Allow cross-namespace communication for monitoring
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-monitoring-access
namespace: production
spec:
podSelector:
matchLabels:
monitoring: "true" # Pods that expose metrics
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: monitoring # From monitoring namespace
- podSelector:
matchLabels:
app: prometheus
ports:
- protocol: TCP
port: 9090 # Metrics port
---
# Allow ingress from specific external IPs
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-external-ips
namespace: production
spec:
podSelector:
matchLabels:
app: web
policyTypes:
- Ingress
ingress:
- from:
- ipBlock:
cidr: 10.0.0.0/8 # Internal networks
- ipBlock:
cidr: 192.168.1.0/24 # Office network
except:
- 192.168.1.100/32 # Exclude specific IP
ports:
- protocol: TCP
port: 80
- protocol: TCP
port: 443
NetworkPolicy Troubleshooting
Testing Network Connectivity
# Test pod-to-pod connectivity
kubectl run test-pod --image=busybox -it --rm -- /bin/sh
# Inside test pod:
wget -qO- http://target-service:8080
nslookup target-service
ping target-pod-ip
# Test specific port connectivity
kubectl run test-pod --image=busybox -it --rm -- \
nc -zv target-service 8080
# Test connectivity with netshoot (advanced debugging)
kubectl run netshoot --image=nicolaka/netshoot -it --rm -- /bin/bash
# Inside netshoot:
nmap -p 8080 target-service
tcptraceroute target-service 8080
NetworkPolicy Debugging
# List all NetworkPolicies
kubectl get networkpolicies --all-namespaces
# Describe specific policy
kubectl describe networkpolicy allow-frontend-to-backend -n application
# Check if CNI supports NetworkPolicies
kubectl get nodes -o jsonpath='{.items[*].status.nodeInfo.containerRuntimeVersion}'
# Calico, Cilium, Weave support NetworkPolicies
# Flannel does NOT support NetworkPolicies
# View policy in effect for specific pod
kubectl get pod frontend-pod -o yaml | grep -A 10 labels
kubectl get networkpolicy -o yaml | grep -A 20 "podSelector"
Common NetworkPolicy Issues
# Issue 1: CNI doesn't support NetworkPolicies
# Solution: Use Calico, Cilium, or Weave instead of Flannel
# Issue 2: DNS resolution blocked
# Error: "nslookup: can't resolve"
# Solution: Allow egress to kube-dns
egress:
- to:
- namespaceSelector:
matchLabels:
name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
# Issue 3: Multiple policies causing confusion
# NetworkPolicies are additive - check all policies selecting the pod
kubectl get networkpolicy -o yaml | grep -B 5 -A 10 "tier: web"
Integrated Security Example
Complete Secure Application Deployment
# Namespace with NetworkPolicy isolation
apiVersion: v1
kind: Namespace
metadata:
name: secure-app
labels:
name: secure-app
---
# ServiceAccount with minimal permissions
apiVersion: v1
kind: ServiceAccount
metadata:
name: web-app-sa
namespace: secure-app
automountServiceAccountToken: true
---
# Role with least privilege
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: secure-app
name: web-app-role
rules:
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["web-config"]
verbs: ["get"]
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["web-secrets"]
verbs: ["get"]
---
# RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: web-app-binding
namespace: secure-app
subjects:
- kind: ServiceAccount
name: web-app-sa
namespace: secure-app
roleRef:
kind: Role
name: web-app-role
apiGroup: rbac.authorization.k8s.io
---
# Secure deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-web-app
namespace: secure-app
spec:
replicas: 2
selector:
matchLabels:
app: web
tier: frontend
template:
metadata:
labels:
app: web
tier: frontend
spec:
serviceAccountName: web-app-sa
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: web
image: nginx:1.20-alpine
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
ports:
- containerPort: 8080
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
volumeMounts:
- name: tmp
mountPath: /tmp
- name: var-cache
mountPath: /var/cache/nginx
- name: var-run
mountPath: /var/run
- name: config
mountPath: /etc/nginx/conf.d
readOnly: true
volumes:
- name: tmp
emptyDir: {}
- name: var-cache
emptyDir: {}
- name: var-run
emptyDir: {}
- name: config
configMap:
name: web-config
---
# NetworkPolicy - default deny + specific allows
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: secure-app
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-web-traffic
namespace: secure-app
spec:
podSelector:
matchLabels:
tier: frontend
policyTypes:
- Ingress
- Egress
ingress:
- from: [] # Allow from anywhere (internet)
ports:
- protocol: TCP
port: 8080
egress:
- to: {} # Allow DNS
ports:
- protocol: UDP
port: 53
Exam-Specific Security Tasks
Common Exam Scenarios
1. Create RBAC for ServiceAccount
# Task: Create ServiceAccount that can create/delete pods in namespace "development"
# Solution:
kubectl create namespace development
kubectl create serviceaccount pod-manager -n development
# Create Role
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: development
name: pod-manager-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["create", "delete", "get", "list"]
EOF
# Create RoleBinding
kubectl create rolebinding pod-manager-binding \
--role=pod-manager-role \
--serviceaccount=development:pod-manager \
-n development
# Test permissions
kubectl auth can-i create pods --as=system:serviceaccount:development:pod-manager -n development
2. Secure Pod with SecurityContext
# Task: Create pod that runs as non-root with read-only filesystem
apiVersion: v1
kind: Pod
metadata:
name: secure-exam-pod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
containers:
- name: app
image: nginx:alpine
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
volumeMounts:
- name: tmp
mountPath: /tmp
- name: var-cache
mountPath: /var/cache/nginx
- name: var-run
mountPath: /var/run
volumes:
- name: tmp
emptyDir: {}
- name: var-cache
emptyDir: {}
- name: var-run
emptyDir: {}
3. NetworkPolicy Implementation
# Task: Block all traffic to database pods except from API pods
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database-isolation
namespace: production
spec:
podSelector:
matchLabels:
tier: database
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
tier: api
ports:
- protocol: TCP
port: 5432
Security Troubleshooting Workflows
Systematic Security Debugging
RBAC Permission Issues
# 1. Identify the subject (user/SA)
kubectl auth whoami
# or check pod's service account
kubectl get pod my-pod -o jsonpath='{.spec.serviceAccountName}'
# 2. Check what permissions they have
kubectl auth can-i --list --as=system:serviceaccount:default:my-sa
# 3. Find relevant RoleBindings/ClusterRoleBindings
kubectl get rolebindings,clusterrolebindings --all-namespaces | grep my-sa
# 4. Examine the Role/ClusterRole
kubectl describe role my-role -n my-namespace
kubectl describe clusterrole my-clusterrole
# 5. Fix by adding missing permissions or creating bindings
SecurityContext Problems
# 1. Check pod events for security-related errors
kubectl describe pod my-pod | grep -A 10 Events
# 2. Check container logs for permission errors
kubectl logs my-pod
# 3. Verify effective user/capabilities in container
kubectl exec my-pod -- id
kubectl exec my-pod -- grep Cap /proc/self/status
# 4. Test filesystem permissions
kubectl exec my-pod -- ls -la /
kubectl exec my-pod -- touch /test-readonly
# 5. Adjust SecurityContext settings as needed
NetworkPolicy Connectivity Issues
# 1. Test basic connectivity
kubectl run test --image=busybox -it --rm -- nc -zv target-service 8080
# 2. Check if NetworkPolicies exist
kubectl get networkpolicy --all-namespaces
# 3. Identify which policies affect your pods
kubectl describe networkpolicy -n my-namespace
# 4. Verify CNI supports NetworkPolicies
kubectl get nodes -o jsonpath='{.items[*].status.nodeInfo.containerRuntimeVersion}'
# 5. Add necessary allow rules or fix policy logic
Conceptual Mastery Framework
Security as Layered Defense
Understanding that no single security mechanism is sufficient:
1. API Server Security - Authentication and authorization
2. RBAC - Fine-grained access control to resources
3. ServiceAccounts - Identity and token management for pods
4. SecurityContext - Process and container runtime security
5. NetworkPolicies - Network-level microsegmentation
Security Integration Patterns
Security mechanisms work together:
- ServiceAccounts provide identity for RBAC authorization
- SecurityContext enforces runtime security for pods
- NetworkPolicies provide network security for pod communication
- All layers must be configured for defense in depth
Least Privilege Principle
Every security configuration should follow minimum necessary access:
- RBAC roles with only required permissions
- ServiceAccounts with specific, limited roles
- SecurityContext dropping all capabilities, adding only needed ones
- NetworkPolicies denying all traffic, allowing only necessary flows
Conceptual Mastery Checklist
✅ Understand RBAC as the authorization mechanism for API access
✅ Master ServiceAccount token mounting and API authentication
✅ Comprehend SecurityContext controls for runtime security
✅ Know NetworkPolicy microsegmentation patterns
✅ Practice integrated security configurations
✅ Internalize troubleshooting workflows for security issues
✅ Apply least privilege principles across all security layers
Mastering Kubernetes security means understanding how authentication, authorization, runtime security, and network controls work together to create defense in depth. Each layer addresses different attack vectors and must be properly configured for comprehensive protection.