CKS — Security Tools Overview
Why Security Tools Matter for CKS
The CKS exam tests your ability to use real security tools on live clusters. Unlike CKA, which relies almost entirely on kubectl, CKS requires you to run scanners, write detection rules, and apply mandatory access control profiles.
This page provides a high-level overview of each tool. Detailed hands-on usage is covered in dedicated chapters later in the tutorial.
kube-bench — CIS Benchmark Scanning
What it does: Runs automated checks against the CIS Kubernetes Benchmark — a set of security best practices for Kubernetes cluster configuration.
Why it’s on the exam: The Cluster Setup domain (10%) tests your ability to identify and remediate CIS benchmark failures.
How kube-bench Works
kube-bench inspects your cluster components (API server, etcd, kubelet, scheduler, controller-manager) and checks them against CIS-recommended settings. It reports:
- PASS — Configuration meets the benchmark
- FAIL — Configuration violates the benchmark (fix required)
- WARN — Manual review recommended
- INFO — Informational, no action needed
Key Commands
# Run all checks on master node
kube-bench run --targets=master
# Run all checks on worker node
kube-bench run --targets=node
# Run specific check section (e.g., API server)
kube-bench run --targets=master --check=1.2
# Run a single specific check
kube-bench run --targets=master --check=1.2.6
# Output as JSON
kube-bench run --targets=master --json
Example Output
[INFO] 1 Control Plane Security Configuration
[INFO] 1.1 Control Plane Node Configuration Files
[PASS] 1.1.1 Ensure that the API server pod specification file permissions are set to 644 or more restrictive
[PASS] 1.1.2 Ensure that the API server pod specification file ownership is set to root:root
[FAIL] 1.1.3 Ensure that the controller manager pod specification file permissions are set to 644 or more restrictive
[PASS] 1.1.4 Ensure that the controller manager pod specification file ownership is set to root:root
Exam Relevance
| Task | What You Do |
|---|---|
| Run kube-bench | Execute against master/worker targets |
| Read output | Identify FAIL items |
| Remediate | Fix the specific configuration (file permissions, API server flags) |
| Verify | Re-run kube-bench to confirm PASS |
Trivy — Image Vulnerability Scanning
What it does: Scans container images for known vulnerabilities (CVEs) by checking image layers against vulnerability databases.
Why it’s on the exam: The Supply Chain Security domain (20%) tests your ability to identify vulnerable images and enforce image security policies.
How Trivy Works
Trivy pulls the image (or reads from local cache), extracts the OS packages and application dependencies, and matches them against CVE databases. It reports vulnerabilities by severity: CRITICAL, HIGH, MEDIUM, LOW.
Key Commands
# Scan an image for vulnerabilities
trivy image nginx:1.27
# Scan and filter by severity
trivy image --severity CRITICAL,HIGH nginx:1.27
# Scan and fail if CRITICAL vulnerabilities found (exit code 1)
trivy image --exit-code 1 --severity CRITICAL nginx:1.27
# Scan a local image (not pulling from registry)
trivy image --input /path/to/image.tar
# Output as JSON
trivy image --format json nginx:1.27
# Output as table (default)
trivy image --format table nginx:1.27
Example Output
nginx:1.27 (debian 12.5)
Total: 42 (CRITICAL: 2, HIGH: 8, MEDIUM: 20, LOW: 12)
┌──────────────┬────────────────┬──────────┬───────────────┬──────────────────────┐
│ Library │ Vulnerability │ Severity │ Version │ Fixed Version │
├──────────────┼────────────────┼──────────┼───────────────┼──────────────────────┤
│ libssl3 │ CVE-2024-XXXX │ CRITICAL │ 3.0.11 │ 3.0.13 │
│ libcurl4 │ CVE-2024-YYYY │ HIGH │ 7.88.1 │ 7.88.1-10+deb12u5 │
└──────────────┴────────────────┴──────────┴───────────────┴──────────────────────┘
Exam Relevance
| Task | What You Do |
|---|---|
| Scan images | Identify images with CRITICAL/HIGH CVEs |
| Filter results | Use --severity to focus on actionable vulnerabilities |
| Recommend fixes | Suggest updated image tags with patched versions |
| Integrate with policies | Combine with ImagePolicyWebhook to block vulnerable images |
Falco — Runtime Threat Detection
What it does: Monitors container and host activity in real time by intercepting Linux syscalls. It detects anomalous behavior based on configurable rules.
Why it’s on the exam: The Monitoring, Logging & Runtime Security domain (20%) heavily tests Falco rule writing and configuration.
How Falco Works
Falco operates at the kernel level:
- Syscall capture — Falco hooks into the kernel to capture system calls (file access, network connections, process execution)
- Rule matching — Each syscall event is evaluated against a set of rules
- Alert generation — When a rule matches, Falco generates an alert (stdout, file, syslog, HTTP)
Key Files
/etc/falco/falco.yaml # Main configuration
/etc/falco/falco_rules.yaml # Default rules (DO NOT edit)
/etc/falco/falco_rules.local.yaml # Custom rules (edit THIS file)
Falco Rule Structure
- rule: Terminal shell in container
desc: A shell was spawned in a container
condition: >
spawned_process and container and
proc.name in (bash, sh, zsh)
output: >
Shell spawned in container
(user=%user.name container=%container.name
shell=%proc.name parent=%proc.pname)
priority: WARNING
tags: [container, shell, mitre_execution]
Key Commands
# Start Falco
systemctl start falco
# Check Falco status
systemctl status falco
# View Falco logs
journalctl -u falco
# Run Falco in foreground (for testing)
falco -r /etc/falco/falco_rules.local.yaml
# Validate rules without running
falco --validate /etc/falco/falco_rules.local.yaml
What Falco Detects
| Detection | Example |
|---|---|
| Shell spawned in container | kubectl exec -it pod -- /bin/bash |
| Sensitive file read | Container reads /etc/shadow or /etc/passwd |
| Unexpected outbound connection | Container connects to an IP outside the cluster |
| Binary modified at runtime | New executable written inside a running container |
| Privilege escalation | Process gains capabilities or runs as root |
| Cryptomining activity | Known mining process names detected |
AppArmor — Mandatory Access Control
What it does: Enforces per-program security profiles that restrict what files, network resources, and capabilities a program can access. AppArmor is a Linux Security Module (LSM).
Why it’s on the exam: The System Hardening domain (15%) tests your ability to create, load, and apply AppArmor profiles to containers.
How AppArmor Works with Kubernetes
- Write a profile — Define what the container can access (files, network, capabilities)
- Load the profile — Parse and load it into the kernel using
apparmor_parser - Apply to Pod — Reference the profile in the Pod’s annotation or security context
- Enforce — The kernel blocks any access that violates the profile
Key Commands
# Check AppArmor status
aa-status
# Load a profile
apparmor_parser -q /etc/apparmor.d/my-profile
# Reload a profile (after editing)
apparmor_parser -r /etc/apparmor.d/my-profile
# Remove a profile
apparmor_parser -R /etc/apparmor.d/my-profile
# List loaded profiles
aa-status | grep my-profile
Example AppArmor Profile
#include <tunables/global>
profile my-container-profile flags=(attach_disconnected) {
#include <abstractions/base>
# Allow read access to specific paths
/usr/bin/nginx mr,
/var/log/nginx/** rw,
/etc/nginx/** r,
# Deny write to sensitive paths
deny /etc/shadow rw,
deny /etc/passwd w,
deny /proc/** w,
}
Applying to a Pod (Kubernetes 1.30+)
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
securityContext:
appArmorProfile:
type: Localhost
localhostProfile: my-container-profile
containers:
- name: app
image: nginx:1.27
Exam Relevance
| Task | What You Do |
|---|---|
| Create profile | Write an AppArmor profile restricting file access |
| Load profile | Use apparmor_parser to load on the correct node |
| Apply to Pod | Reference the profile in the Pod spec |
| Verify enforcement | Test that restricted actions are blocked |
Common trap: Forgetting to load the AppArmor profile (apparmor_parser) before creating the Pod. The Pod will fail to schedule if the profile isn’t loaded on the node.
Seccomp — Syscall Filtering
What it does: Restricts which Linux syscalls a container can make. Seccomp profiles define an allowlist or denylist of syscalls.
Why it’s on the exam: The System Hardening domain (15%) tests your ability to apply Seccomp profiles to Pods.
How Seccomp Works
Every process makes syscalls (system calls) to interact with the kernel — opening files, creating sockets, forking processes. Seccomp filters these calls:
- Allow — The syscall proceeds normally
- Block (EPERM) — The syscall is denied with a permission error
- Kill — The process is terminated
- Log — The syscall is allowed but logged
Seccomp Profile Types
| Type | Description |
|---|---|
RuntimeDefault |
Uses the container runtime’s default Seccomp profile (recommended) |
Localhost |
Uses a custom profile file from the node |
Unconfined |
No Seccomp restrictions (least secure) |
Applying Seccomp to a Pod
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
securityContext:
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: nginx:1.27
Custom Seccomp Profile
{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": ["SCMP_ARCH_X86_64"],
"syscalls": [
{
"names": ["read", "write", "open", "close", "stat",
"fstat", "mmap", "mprotect", "brk", "exit_group"],
"action": "SCMP_ACT_ALLOW"
}
]
}
Custom profiles are stored at: /var/lib/kubelet/seccomp/profiles/
# Reference a custom profile
securityContext:
seccompProfile:
type: Localhost
localhostProfile: profiles/my-custom-profile.json
OPA Gatekeeper / Kyverno — Policy Enforcement
What they do: Enforce custom policies on Kubernetes resources via admission controllers. They evaluate resource creation/modification requests against policy rules and can reject non-compliant resources.
Why they’re on the exam: The Minimize Microservice Vulnerabilities domain (20%) tests policy enforcement via admission controllers.
OPA Gatekeeper
Gatekeeper uses ConstraintTemplates (define the policy logic in Rego) and Constraints (apply the policy to specific resources).
# ConstraintTemplate — defines the policy
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredlabels
violation[{"msg": msg}] {
provided := {label | input.review.object.metadata.labels[label]}
required := {label | label := input.parameters.labels[_]}
missing := required - provided
count(missing) > 0
msg := sprintf("Missing labels: %v", [missing])
}
# Constraint — applies the policy
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: require-team-label
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters:
labels: ["team"]
Kyverno
Kyverno uses native Kubernetes YAML for policies (no Rego required):
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-labels
spec:
validationFailureAction: Enforce
rules:
- name: check-team-label
match:
any:
- resources:
kinds:
- Pod
validate:
message: "The label 'team' is required."
pattern:
metadata:
labels:
team: "?*"
Gatekeeper vs Kyverno
| Feature | OPA Gatekeeper | Kyverno |
|---|---|---|
| Policy language | Rego (custom language) | Native Kubernetes YAML |
| Learning curve | Steeper (must learn Rego) | Easier (pure YAML) |
| Flexibility | Very high (Rego is powerful) | High (covers most use cases) |
| CKS exam coverage | Primary focus | May appear as alternative |
Tools-to-Exam-Domain Mapping
| Tool | Exam Domain | Weight |
|---|---|---|
| kube-bench | Cluster Setup | 10% |
| kubectl (RBAC, SA hardening) | Cluster Hardening | 15% |
| AppArmor | System Hardening | 15% |
| Seccomp | System Hardening | 15% |
| OPA Gatekeeper / Kyverno | Minimize Microservice Vulnerabilities | 20% |
| Trivy | Supply Chain Security | 20% |
| Falco | Monitoring, Logging & Runtime Security | 20% |
Key Commands Reference
| Tool | Most-Used Command | Purpose |
|---|---|---|
| kube-bench | kube-bench run --targets=master |
Scan control plane against CIS benchmark |
| Trivy | trivy image --severity CRITICAL,HIGH <image> |
Scan image for high-severity CVEs |
| Falco | falco -r /etc/falco/falco_rules.local.yaml |
Run Falco with custom rules |
| AppArmor | apparmor_parser -q /etc/apparmor.d/<profile> |
Load an AppArmor profile |
| Seccomp | Applied via Pod securityContext.seccompProfile |
Restrict syscalls in Pod spec |
| Gatekeeper | kubectl apply -f constraint-template.yaml |
Deploy policy template |
| Kyverno | kubectl apply -f cluster-policy.yaml |
Deploy cluster policy |
| aa-status | aa-status |
List loaded AppArmor profiles |
| crictl | crictl ps |
List running containers |
Practice Questions
Q1: What tool would you use to check if your cluster API server configuration follows CIS best practices?
Show Answer
kube-bench. Run it with:
kube-bench run --targets=master
This checks the API server, controller-manager, scheduler, and etcd configurations against the CIS Kubernetes Benchmark.
Q2: You need to find all container images in namespace production that have CRITICAL vulnerabilities. What command would you use?
Show Answer
First, list all images in the namespace:
kubectl get pods -n production -o jsonpath='{.items[*].spec.containers[*].image}' | tr ' ' '\n' | sort -u
Then scan each image with Trivy:
trivy image --severity CRITICAL <image-name>
To fail on CRITICAL findings (useful in scripts):
trivy image --exit-code 1 --severity CRITICAL <image-name>
Q3: Where should you place custom Falco rules, and why?
Show Answer
Custom rules go in /etc/falco/falco_rules.local.yaml.
You should never edit /etc/falco/falco_rules.yaml (the default rules file) because:
- It gets overwritten during Falco upgrades
- Your custom rules would be lost
- The local file takes precedence and can override default rules
Q4: What is the difference between Seccomp profile types RuntimeDefault and Localhost?
Show Answer
RuntimeDefault— Uses the container runtime’s built-in default Seccomp profile. This blocks a standard set of dangerous syscalls and is the recommended baseline for most workloads.Localhost— Uses a custom Seccomp profile file stored on the node at/var/lib/kubelet/seccomp/. Use this when you need a tighter or more specific syscall filter than the runtime default.
Q5: Name the two components required to define a policy in OPA Gatekeeper.
Show Answer
- ConstraintTemplate — Defines the policy logic using the Rego language. It specifies what the policy checks.
- Constraint — Applies the ConstraintTemplate to specific Kubernetes resources (e.g., Pods in a namespace). It provides parameters and match rules.
Both must exist for a policy to have effect. The ConstraintTemplate defines the “what” and the Constraint defines the “where.”
Next: Assess your readiness with Prerequisites & Study Plan →