Back to Blog

CKS Exam Topics 2026: Supply Chain Security, Runtime Security and More

Detailed breakdown of all CKS exam domains, topics, and key tools tested in 2026.

By Sailor Team , March 20, 2026

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

DomainWeightFocusKey Tools
Cluster Setup10%Network policies, PSS, API securityNetworkPolicy, Pod Security Standards, RBAC
Cluster Hardening15%RBAC, access controls, auditingkubectl auth, audit logging, admission controllers
System Hardening15%Linux security modules, syscallsAppArmor, SELinux, Seccomp, SecurityContext
Minimize Microservice Vulnerabilities20%Image scanning, pod security, secretsTrivy, private registries, Secret encryption
Supply Chain Security20%Image signing, verification, binary authorizationcosign, Notary, binary authorization
Monitoring, Logging, Runtime Security20%Falco, audit logs, runtime threat detectionFalco, 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 profiles
  • runtime/default for Kubernetes default
  • unconfined disables 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-root
  • allowPrivilegeEscalation: false: Prevent sudo-like privilege escalation
  • readOnlyRootFilesystem: true: Mount root as read-only
  • capabilities.drop: [ALL]: Remove all Linux capabilities
  • capabilities.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

DomainKey FocusMust Know
Cluster SetupNetwork policies, PSS enforcementDeny-all policies, label selectors
Cluster HardeningRBAC, audit logs, admission controlCan-i testing, audit policy yaml
System HardeningAppArmor, Seccomp, SecurityContextProfile creation, capability dropping
Microservice VulnerabilitiesImage scanning, secrets, encryptionTrivy scanning, secret encryption
Supply Chain SecurityImage signing, binary authorizationcosign commands, policy enforcement
Monitoring/RuntimeFalco, audit analysis, threat detectionRule 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.

Limited Time Offer: Get 80% off all Mock Exam Bundles | Sale ends in 7 days. Start learning today.

Claim Now