CKS — Exam Setup & Speed Tips
First 2 Minutes: Terminal Setup
The moment the exam starts, before reading any question, run this setup in your terminal. It will save you 10+ minutes over the 2-hour exam.
Essential Aliases and Exports
Run these commands immediately:
alias k=kubectl
alias kn='kubectl config set-context --current --namespace'
export do="--dry-run=client -o yaml"
export now="--force --grace-period=0"
What Each One Does
| Alias/Export | Purpose | Example |
|---|---|---|
k |
Short for kubectl |
k get pods instead of kubectl get pods |
kn |
Switch namespace quickly | kn secure instead of kubectl config set-context --current --namespace secure |
$do |
Generate YAML without creating | k run nginx --image=nginx $do > pod.yaml |
$now |
Force-delete pods instantly | k delete pod nginx $now |
kubectl Autocomplete
Enable tab completion for kubectl and the k alias:
source <(kubectl completion bash)
complete -o default -F __start_kubectl k
After this, you can type k get pod<TAB> and it auto-completes to k get pods. You can also tab-complete resource names: k describe pod ng<TAB> completes to k describe pod nginx.
Important: If you switch to a new terminal or SSH into a node, you must re-run all aliases and completion commands. They do not persist across sessions in the exam environment.
Vim Configuration
Create your ~/.vimrc at the start of the exam:
cat << 'EOF' > ~/.vimrc
set tabstop=2
set shiftwidth=2
set expandtab
set number
EOF
What Each Setting Does
| Setting | Purpose |
|---|---|
tabstop=2 |
Tab key displays as 2 spaces (YAML standard) |
shiftwidth=2 |
Indentation uses 2 spaces (for >> and << commands) |
expandtab |
Converts tabs to spaces (YAML does not allow literal tabs) |
number |
Shows line numbers (helps when debugging YAML errors) |
Essential Vim Commands for the Exam
| Command | Action |
|---|---|
i |
Enter insert mode |
Esc |
Exit insert mode |
dd |
Delete current line |
5dd |
Delete 5 lines |
yy |
Copy (yank) current line |
5yy |
Copy 5 lines |
p |
Paste below current line |
u |
Undo last change |
Ctrl+r |
Redo |
:set paste |
Enable paste mode (preserves indentation when pasting) |
:set nopaste |
Disable paste mode |
/searchterm |
Search forward for “searchterm” |
n |
Jump to next search match |
N |
Jump to previous search match |
:%s/old/new/g |
Replace all occurrences of “old” with “new” |
:wq |
Save and quit |
:q! |
Quit without saving |
gg |
Go to first line |
G |
Go to last line |
:42 |
Go to line 42 |
v |
Enter visual mode (for selecting text) |
V |
Enter visual line mode (select entire lines) |
> |
Indent selected text (in visual mode) |
< |
Unindent selected text (in visual mode) |
Pro tip: When pasting YAML from the docs, always enter
:set pastemode first. Otherwise, vim auto-indentation will corrupt your YAML structure. After pasting, run:set nopaste.
Must-Know Security Aliases
Beyond the basic aliases, these security-specific shortcuts save significant time on CKS questions:
# Quick context check (run before EVERY question)
alias kctx='kubectl config get-contexts'
alias kns='kubectl config view --minify --output jsonpath="{..namespace}"'
# Security-focused shortcuts
alias kgp='kubectl get pods'
alias kgpa='kubectl get pods --all-namespaces'
alias kgsa='kubectl get serviceaccounts'
alias kgnp='kubectl get networkpolicies'
alias kgsec='kubectl get secrets'
alias kdp='kubectl describe pod'
alias kaf='kubectl apply -f'
# Quick Pod creation with security context
alias krun='kubectl run --image=nginx --dry-run=client -o yaml'
Security Shortcuts Reference Table
| Task | Fast Command |
|---|---|
| Check current context | k config current-context |
| Switch context | k config use-context <name> |
| Check current namespace | k config view --minify -o jsonpath='{..namespace}' |
| Switch namespace | kn <namespace> |
| Generate Pod YAML | k run test --image=nginx $do > pod.yaml |
| Generate Role YAML | k create role myrole --verb=get,list --resource=pods $do |
| Generate RoleBinding YAML | k create rolebinding mybinding --role=myrole --serviceaccount=ns:sa $do |
| Generate ClusterRole YAML | k create clusterrole myrole --verb=get,list --resource=pods $do |
| Generate NetworkPolicy | Copy from kubernetes.io docs — no imperative command exists |
| Force delete a pod | k delete pod <name> $now |
| Check API server flags | cat /etc/kubernetes/manifests/kube-apiserver.yaml |
| Check kubelet config | cat /var/lib/kubelet/config.yaml |
| SSH to a node | ssh <node-name> |
| Check AppArmor profiles | aa-status (on the node) |
| Check Seccomp profiles | ls /var/lib/kubelet/seccomp/ |
Key Bookmarks to Prepare
Before exam day, familiarize yourself with these documentation pages. During the exam, you can navigate to them from the allowed sites. Knowing exactly where to find each resource saves 2–3 minutes per question.
Kubernetes Official Docs
| Topic | URL Path |
|---|---|
| NetworkPolicy | kubernetes.io/docs/concepts/services-networking/network-policies/ |
| Audit Policy | kubernetes.io/docs/tasks/debug/debug-cluster/audit/ |
| AppArmor | kubernetes.io/docs/tutorials/security/apparmor/ |
| Seccomp | kubernetes.io/docs/tutorials/security/seccomp/ |
| Pod Security Admission | kubernetes.io/docs/concepts/security/pod-security-admission/ |
| Pod Security Standards | kubernetes.io/docs/concepts/security/pod-security-standards/ |
| RBAC | kubernetes.io/docs/reference/access-authn-authz/rbac/ |
| Encryption at Rest | kubernetes.io/docs/tasks/administer-cluster/encrypt-data/ |
| Service Accounts | kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ |
| Security Context | kubernetes.io/docs/tasks/configure-pod-container/security-context/ |
| Admission Controllers | kubernetes.io/docs/reference/access-authn-authz/admission-controllers/ |
External Tool Docs (Allowed in Exam)
| Tool | URL |
|---|---|
| Falco | falco.org/docs/rules/ |
| Trivy | aquasecurity.github.io/trivy/ |
| AppArmor (upstream) | gitlab.com/apparmor/apparmor/-/wikis/ |
Practice this: Before the exam, navigate to each of these pages at least 3 times. Know the page layout so you can find the relevant YAML example in under 30 seconds.
kubectl Cheat Sheet for Security Tasks
This table covers the most common kubectl operations you will need during the CKS exam:
Cluster & Context
| Command | Purpose |
|---|---|
k config get-contexts |
List all available contexts |
k config use-context <ctx> |
Switch to a specific context |
k config current-context |
Show current context |
k config set-context --current --namespace=<ns> |
Set default namespace |
k cluster-info |
Show cluster endpoint info |
k get nodes |
List all nodes |
k get nodes -o wide |
List nodes with IPs and OS info |
RBAC
| Command | Purpose |
|---|---|
k create role <name> --verb=get,list --resource=pods -n <ns> |
Create a Role |
k create rolebinding <name> --role=<role> --user=<user> -n <ns> |
Create a RoleBinding |
k create clusterrole <name> --verb=get,list --resource=pods |
Create a ClusterRole |
k create clusterrolebinding <name> --clusterrole=<role> --user=<user> |
Create a ClusterRoleBinding |
k auth can-i get pods --as=<user> -n <ns> |
Test permissions |
k auth can-i --list --as=<user> -n <ns> |
List all permissions for a user |
Pods & Security
| Command | Purpose |
|---|---|
k run test --image=nginx $do > pod.yaml |
Generate Pod YAML |
k exec -it <pod> -- /bin/sh |
Exec into a pod |
k exec <pod> -- cat /run/secrets/kubernetes.io/serviceaccount/token |
Check SA token mount |
k get pod <pod> -o jsonpath='{.spec.securityContext}' |
Check Pod security context |
k get pod <pod> -o jsonpath='{.spec.containers[0].securityContext}' |
Check container security context |
k label ns <ns> pod-security.kubernetes.io/enforce=restricted |
Apply PSA label |
Secrets & Encryption
| Command | Purpose |
|---|---|
k create secret generic <name> --from-literal=key=value -n <ns> |
Create a Secret |
k get secret <name> -o jsonpath='{.data.key}' \| base64 -d |
Decode a Secret value |
ETCDCTL_API=3 etcdctl get /registry/secrets/<ns>/<name> --cert ... --key ... --cacert ... |
Read Secret directly from etcd |
Network & Policies
| Command | Purpose |
|---|---|
k get networkpolicies -n <ns> |
List NetworkPolicies |
k describe networkpolicy <name> -n <ns> |
Describe a NetworkPolicy |
k exec <pod> -- wget -qO- --timeout=2 <target> |
Test network connectivity |
k exec <pod> -- nslookup <service> |
Test DNS resolution |
API Server & Static Pods
| Command | Purpose |
|---|---|
cat /etc/kubernetes/manifests/kube-apiserver.yaml |
View API server config |
cat /etc/kubernetes/manifests/etcd.yaml |
View etcd config |
cat /var/lib/kubelet/config.yaml |
View kubelet config |
systemctl restart kubelet |
Restart kubelet |
crictl ps |
List running containers (containerd) |
crictl logs <container-id> |
View container logs |
Speed Techniques for YAML Editing
Technique 1: Generate, Don’t Write From Scratch
Never write YAML from memory. Always generate a base and modify it:
# Generate a Pod spec
k run secure-pod --image=nginx $do > pod.yaml
# Generate a Role
k create role pod-reader --verb=get,list --resource=pods $do > role.yaml
# Generate a RoleBinding
k create rolebinding pod-reader-binding --role=pod-reader \
--serviceaccount=default:mysa $do > rb.yaml
Technique 2: Copy From Docs, Modify in vim
For resources without imperative generation (like NetworkPolicy):
- Open the Kubernetes docs page for NetworkPolicy
- Find the closest example to what you need
- Copy the YAML
- In terminal:
vi np.yaml - Type
:set paste, pressi, paste, pressEsc, type:set nopaste - Modify the fields you need (namespace, labels, ports)
- Save with
:wqand apply withk apply -f np.yaml
Technique 3: Use kubectl edit for Quick Fixes
If a resource already exists and needs a small change:
k edit pod <pod-name>
# or
k edit deployment <deploy-name>
This opens the live resource in vim. Make your change, save, and it is applied immediately.
Technique 4: Redirect and Append
# Create a base file
k run pod1 --image=nginx $do > pod.yaml
# View the API server manifest and search for a flag
grep -i "enable-admission" /etc/kubernetes/manifests/kube-apiserver.yaml
# Append to an existing file
echo "---" >> combined.yaml
k create role viewer --verb=get --resource=pods $do >> combined.yaml
Technique 5: Use grep to Find Things Fast
# Find which node has an AppArmor profile loaded
ssh node01 'aa-status | grep my-profile'
# Find a specific flag in API server config
grep -i "audit" /etc/kubernetes/manifests/kube-apiserver.yaml
# Find Falco rules mentioning a specific syscall
grep -r "spawned_process" /etc/falco/
Exam Environment Gotchas
You Lose Aliases When You SSH
When you ssh node01 to work on a node (for AppArmor, Seccomp, etc.), your aliases are gone. Re-set them if needed:
ssh node01
alias k=kubectl # if you need kubectl on the node
Static Pod Changes Need Kubelet Restart (Sometimes)
After modifying /etc/kubernetes/manifests/kube-apiserver.yaml, the kubelet watches this directory and automatically restarts the API server. However:
- It can take 30–60 seconds for the restart
- If you made a YAML error, the API server will crash-loop
- Monitor with:
crictl ps | grep apiserverorwatch crictl ps - If the API server does not come back, check your YAML:
cat /etc/kubernetes/manifests/kube-apiserver.yaml | python3 -c "import sys,yaml;yaml.safe_load(sys.stdin.read())"(validates YAML syntax)
Copy-Paste Behavior
- Copy: select text in terminal, it auto-copies (or use
Ctrl+Shift+C) - Paste:
Ctrl+Shift+Vin terminal - In vim:
:set pastebefore pasting,:set nopasteafter
Practice Questions
Question 1: Write the exact commands you would run in the first 2 minutes of the CKS exam to set up your environment.
# Aliases
alias k=kubectl
alias kn='kubectl config set-context --current --namespace'
export do="--dry-run=client -o yaml"
export now="--force --grace-period=0"
# Autocomplete
source <(kubectl completion bash)
complete -o default -F __start_kubectl k
# Vim config
cat << 'EOF' > ~/.vimrc
set tabstop=2
set shiftwidth=2
set expandtab
set number
EOF
This should take under 60 seconds if you have it memorized. Practice typing this from memory until it becomes muscle memory.
Question 2: During the exam, you need to create a NetworkPolicy. No imperative `kubectl create networkpolicy` command exists. What is the fastest approach?
- Open the allowed documentation:
kubernetes.io/docs/concepts/services-networking/network-policies/ - Find the example closest to what you need
- Copy the YAML example
- In the terminal:
vi np.yaml - In vim:
- Type
:set pasteand press Enter - Press
ito enter insert mode - Paste with
Ctrl+Shift+V - Press
Esc - Type
:set nopasteand press Enter - Modify the namespace, labels, ports as needed
- Type
:wqto save and quit
- Type
- Apply:
k apply -f np.yaml - Verify:
k get networkpolicy -n <namespace>
This should take 2–3 minutes total with practice.
Question 3: You SSH into a worker node to load an AppArmor profile. After loading it, you try to run `k get pods` but get "command not found". Why? How do you fix it?
Your aliases (alias k=kubectl) are set in the control plane terminal session. When you SSH into a worker node, you start a new shell session where those aliases do not exist.
Fix:
# Option 1: Use the full command
kubectl get pods
# Option 2: Re-set the alias on the node
alias k=kubectl
# Option 3: Exit back to the control plane
exit
k get pods
In most cases, you do not need kubectl on the worker node. You SSH to the node only to:
- Load AppArmor profiles (
apparmor_parser -r /etc/apparmor.d/profile) - Place Seccomp profiles (copy JSON to
/var/lib/kubelet/seccomp/) - Check node-level configuration
- Harden SSH or other services
After completing node-level tasks, exit back to the control plane to create/modify Kubernetes resources.
Question 4: You modify `/etc/kubernetes/manifests/kube-apiserver.yaml` to add an audit policy flag, but the API server does not come back. How do you debug this?
Step-by-step debugging:
# 1. Check if the API server container is running
crictl ps | grep apiserver
# 2. If it shows restarting/crash-looping, check the logs
crictl logs $(crictl ps -a | grep apiserver | head -1 | awk '{print $1}')
# 3. Validate your YAML syntax
python3 -c "import yaml; yaml.safe_load(open('/etc/kubernetes/manifests/kube-apiserver.yaml'))"
# 4. Common mistakes to check:
# - Did you mount the audit policy file as a volume?
# - Is the volume mount path correct?
# - Does the audit policy file exist at the mounted host path?
# - Did you introduce a YAML indentation error?
# 5. If you cannot fix it, restore the original
# (Hopefully you made a backup before editing)
cp /etc/kubernetes/manifests/kube-apiserver.yaml.bak \
/etc/kubernetes/manifests/kube-apiserver.yaml
Pro tip: Always back up the API server manifest before editing:
cp /etc/kubernetes/manifests/kube-apiserver.yaml \
/etc/kubernetes/manifests/kube-apiserver.yaml.bak
Question 5: You need to verify the integrity of the kubectl binary on a node. Write the exact commands.
# 1. Check the current kubectl version
kubectl version --client --short
# 2. Download the checksum for that version from kubernetes.io
# Example for v1.29.0:
curl -LO "https://dl.k8s.io/v1.29.0/bin/linux/amd64/kubectl.sha256"
# 3. Generate the sha256sum of the installed binary
sha256sum $(which kubectl)
# 4. Compare the checksums
echo "$(cat kubectl.sha256) $(which kubectl)" | sha256sum --check
# If the output says "OK", the binary is verified.
# If it says "FAILED", the binary has been tampered with.
On the exam, the question may provide the expected hash or ask you to download it from a specific URL. Always check which version is installed first.
Alternative using sha512:
sha512sum $(which kubectl)
# Compare with the expected sha512 hash provided in the question