The Certified Kubernetes Security Specialist exam covers six primary domains, each with specific weightings that determine how many exam questions focus on that area. Understanding the exam domains in detail is crucial for allocating your study time efficiently and ensuring you’re prepared for every topic type.
This guide provides a comprehensive breakdown of all CKS exam topics, key commands, tools, and what you’ll actually face on test day.
Overview: The Six CKS Domains
| Domain | Weight | Focus | Key Tools |
|---|---|---|---|
| Cluster Setup | 10% | Network policies, PSS, API security | NetworkPolicy, Pod Security Standards, RBAC |
| Cluster Hardening | 15% | RBAC, access controls, auditing | kubectl auth, audit logging, admission controllers |
| System Hardening | 15% | Linux security modules, syscalls | AppArmor, SELinux, Seccomp, SecurityContext |
| Minimize Microservice Vulnerabilities | 20% | Image scanning, pod security, secrets | Trivy, private registries, Secret encryption |
| Supply Chain Security | 20% | Image signing, verification, binary authorization | cosign, Notary, binary authorization |
| Monitoring, Logging, Runtime Security | 20% | Falco, audit logs, runtime threat detection | Falco, audit logging, metrics monitoring |
Domain 1: Cluster Setup (10%)
Overview and Importance
Cluster setup security forms the foundation. Mistakes here expose your entire cluster to compromise.
Network Policies (Most Important)
Network policies are a cornerstone of Kubernetes security. They implement zero-trust networking by denying all traffic by default, then explicitly allowing required connections.
Key Concepts
- Selectors: Target pods by labels
- Ingress Rules: Control inbound traffic
- Egress Rules: Control outbound traffic
- Ports and Protocols: Specify TCP/UDP ports
Common Exam Scenarios
Scenario 1: Namespace Isolation
# Deny all traffic between namespaces
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
namespace: secure
spec:
podSelector: {}
policyTypes:
- Ingress
# No ingress rules = deny all
---
# Allow traffic only from specific namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-frontend
namespace: backend
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: frontend
ports:
- protocol: TCP
port: 8080
Scenario 2: Egress Filtering
# Deny all egress, then allow only DNS and database
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: app-egress-control
namespace: production
spec:
podSelector:
matchLabels:
tier: app
policyTypes:
- Egress
egress:
# Allow DNS
- to:
- namespaceSelector:
matchLabels:
name: kube-system
ports:
- protocol: UDP
port: 53
# Allow database
- to:
- podSelector:
matchLabels:
tier: database
ports:
- protocol: TCP
port: 5432
Exam Tips:
- Network policies are namespace-scoped (can’t restrict cross-cluster traffic)
podSelector: {}with no ingress rules = deny all ingress- Test policies with kubectl debug pods
- Understand both label selectors and namespace selectors
Pod Security Standards (PSS)
Pod Security Standards define security profiles (restricted, baseline, unrestricted) enforced at namespace or cluster level.
Enforcement Levels
- enforce: Violating pods are rejected
- audit: Violations are logged but pods run
- warn: Violations trigger warnings but pods run
Common Configuration
# Namespace with restricted PSS enforcement
apiVersion: v1
kind: Namespace
metadata:
name: secure
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
Exam Focus:
- Difference between enforce, audit, warn
- Creating PSS policies that reject privileged containers
- Understanding what makes a pod “restricted” vs “baseline”
- Exempting system pods from PSS enforcement
RBAC Fundamentals
RBAC is tested in multiple domains. At the Cluster Setup level, understand basic role creation.
# Create role that allows read-only secret access
kubectl create role secret-reader --verb=get,list --resource=secrets
# Create cluster-wide admin role
kubectl create clusterrole admin-role --verb=* --resource=*
# Bind role to service account
kubectl create rolebinding reader-binding --role=secret-reader \
--serviceaccount=default:app-sa
# Test if user can perform action
kubectl auth can-i get secrets --as=system:serviceaccount:default:app-sa
Domain 2: Cluster Hardening (15%)
RBAC in Depth
Cluster Hardening heavily emphasizes RBAC implementation and troubleshooting.
Advanced RBAC Scenarios
Scenario: Principle of Least Privilege
# ServiceAccount for deployment pipeline
apiVersion: v1
kind: ServiceAccount
metadata:
name: deployer
namespace: production
---
# Role with minimal permissions - only update deployments
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: deployer-role
namespace: production
rules:
# Can view, update deployments
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "patch", "update"]
# Can view pods to check status
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
# Can't access secrets, configmaps, or anything else
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: deployer-binding
namespace: production
subjects:
- kind: ServiceAccount
name: deployer
roleRef:
kind: Role
name: deployer-role
Exam Tips:
- Understand apiGroups ("" for core API, “apps” for deployments/statefulsets)
- Resource names vs resource collections (can be specific)
- Wildcard verbs (*) grant all permissions—minimize this
- Test permissions with
kubectl auth can-i
Auditing and Audit Policies
Audit logging records API requests for compliance and security analysis.
Audit Policy Configuration
# Example audit policy
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# Log all requests at Metadata level
- level: Metadata
omitStages:
- RequestReceived
---
# Log pod exec with request body
- level: RequestResponse
verbs: ["create"]
resources:
- group: ""
resources: ["pods/exec"]
---
# Log all secret access at RequestResponse
- level: RequestResponse
resources:
- group: ""
resources: ["secrets"]
---
# Default: log at Metadata level
- level: Metadata
Audit Levels:
- None: Don’t log
- Metadata: Request metadata only (user, resource, verb)
- Request: Include request body
- RequestResponse: Include request and response bodies
Enabling Audit Logging
# Add to kube-apiserver manifest
--audit-policy-file=/etc/kubernetes/audit-policy.yaml
--audit-log-maxage=30
--audit-log-maxbackup=10
--audit-log-maxsize=100
# View audit logs
tail -f /var/log/kubernetes/audit/audit.log | grep "secret" | jq .
Service Account Management
Restrict service account capabilities and prevent token leakage.
# ServiceAccount with minimal permissions
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-sa
namespace: production
automountServiceAccountToken: true # Set false for pods not needing SA token
---
# Pod using service account
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
serviceAccountName: app-sa
automountServiceAccountToken: true
containers:
- name: app
image: myapp:latest
volumeMounts:
- name: sa-token
mountPath: /var/run/secrets/kubernetes.io/serviceaccount
readOnly: true
volumes:
- name: sa-token
projected:
sources:
- serviceAccountToken:
path: token
expirationSeconds: 3600
Disabling Insecure Features
Remove Insecure Ports
# kubelet should NOT listen on insecure port (default 10250)
--port=0 # Disable insecure port on kubelet
API Server Security
# Disable anonymous auth
--anonymous-auth=false
# Disable basic auth (deprecated)
--basic-auth-file= # Don't set this
# Require authorization
--authorization-mode=Node,RBAC
Domain 3: System Hardening (15%)
Linux Security Modules
System hardening focuses on restricting what containers can do at the Linux level.
AppArmor
AppArmor restricts programs’ capabilities through mandatory access control.
AppArmor Profile Structure:
#include <tunables/global>
profile restrict-app flags=(attach_disconnected,mediate_deleted) {
#include <abstractions/base>
# Deny everything by default for this app
deny /root/** rwkl,
deny /etc/shadow rwkl,
# Allow specific files
/etc/hostname r,
/proc/sys/kernel/hostname r,
# Allow network
network inet stream,
network inet dgram,
# Allow specific capabilities
capability net_bind_service,
capability setuid,
# Deny sensitive capabilities
deny capability sys_admin,
deny capability sys_module,
deny capability sys_ptrace,
}
Using AppArmor in Kubernetes:
apiVersion: v1
kind: Pod
metadata:
name: app-with-apparmor
annotations:
container.apparmor.security.beta.kubernetes.io/app: localhost/restrict-app
spec:
containers:
- name: app
image: myapp:latest
AppArmor Exam Focus:
- Profiles are node-specific (installed on nodes)
localhost/prefix for local profilesruntime/defaultfor Kubernetes defaultunconfineddisables AppArmor
Seccomp
Seccomp filters system calls, preventing containers from executing dangerous syscalls.
Seccomp Profile (JSON):
{
"defaultAction": "SCMP_ACT_ERRNO",
"defaultErrnoRet": 1,
"archMap": [
{
"architecture": "SCMP_ARCH_X86_64",
"subArchitectures": ["SCMP_ARCH_X86", "SCMP_ARCH_X32"]
}
],
"syscalls": [
{
"names": [
"accept4", "arch_prctl", "bind", "clone", "close",
"connect", "dup", "dup2", "execve", "exit", "exit_group",
"fcntl", "fork", "fstat", "futex", "getcwd", "getpeername",
"getpid", "getppid", "getrandom", "getsockname", "getsockopt",
"listen", "lseek", "madvise", "mmap", "mprotect", "munmap",
"openat", "poll", "prctl", "pread64", "prlimit64", "pwrite64",
"read", "recvfrom", "recvmsg", "rt_sigaction", "rt_sigprocmask",
"rt_sigreturn", "sched_getaffinity", "sched_yield", "sendmsg",
"sendto", "set_robust_list", "set_tid_address", "setitimer",
"setsockopt", "sigaltstack", "sigreturn", "socket", "stat",
"statx", "write"
],
"action": "SCMP_ACT_ALLOW"
}
]
}
Apply to Pod:
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
securityContext:
seccompProfile:
type: Localhost
localhostProfile: restricted.json
containers:
- name: app
image: myapp:latest
SecurityContext
SecurityContext controls pod and container security at Kubernetes level.
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: myapp:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
volumeMounts:
- name: tmp
mountPath: /tmp
- name: var
mountPath: /var
volumes:
- name: tmp
emptyDir: {}
- name: var
emptyDir: {}
Key SecurityContext Fields:
runAsNonRoot: true: Container must run as non-rootallowPrivilegeEscalation: false: Prevent sudo-like privilege escalationreadOnlyRootFilesystem: true: Mount root as read-onlycapabilities.drop: [ALL]: Remove all Linux capabilitiescapabilities.add: Add back only necessary capabilities
Domain 4: Minimize Microservice Vulnerabilities (20%)
Image Scanning with Trivy
Container images often contain known vulnerabilities. Trivy scans for them.
Scanning Practices
# Scan image for vulnerabilities
trivy image nginx:latest
# Scan with severity filter
trivy image --severity HIGH,CRITICAL ubuntu:20.04
# Output as JSON for processing
trivy image --format json --output scan.json gcr.io/project/app:v1
# Scan Kubernetes manifests
trivy config deployment.yaml
# Scan with detailed output
trivy image --severity CRITICAL --verbose nginx:latest
Blocking Vulnerable Images
# ValidatingWebhook that blocks images with vulnerabilities
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: image-vulnerability-check
webhooks:
- name: image-check.example.com
clientConfig:
service:
name: image-scanner
namespace: default
path: "/validate"
caBundle: LS0tLS1CRU...
rules:
- operations: ["CREATE", "UPDATE"]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
admissionReviewVersions: ["v1"]
sideEffects: None
Pod Security Standards and Policies
Besides network-level enforcement, runtime pod security is critical.
# Restrict pods to non-root, non-privileged
apiVersion: v1
kind: Pod
metadata:
name: restricted-pod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
containers:
- name: app
image: myapp:latest
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
Secret Management and Encryption
Secret Encryption at Rest
# Generate encryption key
head -c 32 /dev/urandom | base64
# Update kube-apiserver with encryption config
--encryption-provider-config=/etc/kubernetes/encryption-config.yaml
Encryption Config:
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded-32-bytes>
- identity: {}
Secret Best Practices
# Store sensitive data in Secrets, not ConfigMaps
apiVersion: v1
kind: Secret
metadata:
name: app-credentials
type: Opaque
stringData:
username: admin
password: secure-password
---
# Mount as volume, not environment variables
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
containers:
- name: app
image: myapp:latest
volumeMounts:
- name: secrets
mountPath: /etc/secrets
readOnly: true
volumes:
- name: secrets
secret:
secretName: app-credentials
defaultMode: 0400
Domain 5: Supply Chain Security (20%)
Image Signing and Verification
Ensure images come from trusted sources and haven’t been modified.
Using cosign for Image Signing
# Generate key pair
cosign generate-key-pair
# Sign image
cosign sign --key cosign.key gcr.io/project/myimage:v1.0
# Verify signature
cosign verify --key cosign.pub gcr.io/project/myimage:v1.0
# Sign and push
cosign sign --key cosign.key gcr.io/project/myimage:v1.0
cosign attach sbom --sbom sbom.spdx gcr.io/project/myimage:v1.0
Binary Authorization
Enforce that only signed images can be deployed.
# Binary authorization policy
apiVersion: binaryauthorization.grafeas.io/v1beta1
kind: Policy
metadata:
name: binary-authorization-policy
spec:
kubernetesNamespaceAdmissions:
- requireAttestationsBy:
- projects/PROJECT_ID/attestors/prod-attestor
namespacePattern: "prod-*"
defaultAdmissionRule:
requireAttestationsBy:
- projects/PROJECT_ID/attestors/qa-attestor
enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
Secure Build Pipeline
# Minimal base image
FROM alpine:3.18
# Run as non-root
RUN addgroup -g 1000 appuser && adduser -D -u 1000 appuser
# Copy application
COPY app /app
# Change ownership
RUN chown -R appuser:appuser /app
# Use non-root user
USER appuser
# Run application
CMD ["/app/main"]
Exam Focus:
- Image source verification
- Provenance tracking
- Signed image enforcement
- CI/CD pipeline security
Domain 6: Monitoring, Logging, Runtime Security (20%)
Falco for Runtime Threat Detection
Falco monitors container behavior at runtime and detects suspicious activities.
Falco Rules
# Detect suspicious shell spawning
- rule: Suspicious Shell in Container
desc: Detect when a shell is spawned in a container
condition: |
spawned_process and
container and
(proc.name = bash or proc.name = sh or proc.name = zsh) and
parent.name != sshd
output: |
Suspicious shell process
(user=%user.name shell=%proc.name container=%container.name)
priority: WARNING
---
# Detect privilege escalation attempts
- rule: Privilege Escalation Attempt
desc: Detect attempts to run privileged commands
condition: |
spawned_process and
container and
(proc.cmdline contains "sudo" or proc.name = sudo) and
user.uid != 0
output: |
Non-root user attempting privilege escalation
(user=%user.name command=%proc.cmdline container=%container.name)
priority: CRITICAL
Deploying Falco
# Install via Helm
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm install falco falcosecurity/falco --namespace falco --create-namespace
# Check Falco alerts
kubectl logs -n falco -l app.kubernetes.io/name=falco | grep -i alert
Audit Log Analysis
# View audit logs for secret access
cat /var/log/kubernetes/audit/audit.log | jq 'select(.verb=="get" and .objectRef.resource=="secrets")'
# Find which user created a resource
cat /var/log/kubernetes/audit/audit.log | jq 'select(.verb=="create")' | grep -i "user\|username"
# Check for unauthorized API calls (403)
cat /var/log/kubernetes/audit/audit.log | jq 'select(.status.code==403)'
Monitoring and Metrics
# ServiceMonitor for Prometheus (if using Prometheus Operator)
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: kubernetes-metrics
spec:
selector:
matchLabels:
app: metrics
endpoints:
- port: metrics
interval: 30s
Exam-Specific Tips by Domain
| Domain | Key Focus | Must Know |
|---|---|---|
| Cluster Setup | Network policies, PSS enforcement | Deny-all policies, label selectors |
| Cluster Hardening | RBAC, audit logs, admission control | Can-i testing, audit policy yaml |
| System Hardening | AppArmor, Seccomp, SecurityContext | Profile creation, capability dropping |
| Microservice Vulnerabilities | Image scanning, secrets, encryption | Trivy scanning, secret encryption |
| Supply Chain Security | Image signing, binary authorization | cosign commands, policy enforcement |
| Monitoring/Runtime | Falco, audit analysis, threat detection | Rule writing, log searching |
Practice Resources
Master these exam topics with hands-on practice. Sailor.sh’s CKS practice exams cover all six domains with detailed explanations and real-world scenarios.
Start practicing all exam domains on the Sailor.sh platform today.
FAQ
What’s the most heavily tested domain?
Supply Chain Security and Monitoring/Runtime Security each account for 20% of the exam—these are the heaviest weighted. Focus here first for maximum exam points.
Do I need to know all the details of every tool?
No. You need working knowledge of Falco, Trivy, AppArmor, and kubectl. Deep mastery of every command isn’t required—understanding concepts and being able to implement configurations is.
Are there tools I should skip?
No. All tools mentioned (Falco, Trivy, AppArmor, Seccomp, cosign) appear on the exam. Budget study time proportional to exam weighting.
What’s the relationship between domains?
Domains build on each other. Network policies (Cluster Setup) are foundational for application security (Microservice Vulnerabilities). Focus on foundational domains first.
How are questions weighted within domains?
Questions may have different point values. A complex scenario might be worth 5 points while a simple configuration is worth 3 points. Focus on understanding concepts, not just completing tasks.
Are there cloud-specific security topics?
CKS covers Kubernetes security universally. Cloud-specific security (AWS IAM, GCP service accounts) is not tested. Focus on native Kubernetes security.