├── LICENSE └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Johannes Schnatterer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | cks-short-tips 2 | === 3 | 4 | 1. [Have a plan for preparation](#have-a-plan-for-preparation) 5 | - [Curated CKS Resources](#curated-cks-resources) 6 | 2. [Train for speed](#train-for-speed) 7 | - [Disable unsafe pasting](#disable-unsafe-pasting) 8 | - [Use aliases and tab completion](#use-aliases-and-tab-completion) 9 | - [Be fast with CLI tools](#be-fast-with-cli-tools) 10 | 3. [Know your tools and technologies](#know-your-tools-and-technologies) 11 | 4. [Be thorough](#be-thorough) 12 | 5. [Don't give up](#dont-give-up) 13 | 14 | 15 | 16 | # Have a plan for preparation 17 | 18 | There a [tons of resources](#curated-cks-resources) out there. 19 | Use them to acquire a wider knowledge, before training specifically for the exam. 20 | 21 | Here's my plan, as an example: 22 | 23 | I invested about 5 working days over a period of three weeks before the exam. 24 | As a seasoned developer in the public cloud I was quick with kubectl, security-context and so on, but not so much with api-server config. 25 | Retrospectively, spending maybe one more day would not have been advisable, as I had to look up a lot of api-server-related stuff in the docs during the exam. 26 | 27 | 1. **Read the Docs for the Certs.** 28 | IMO most importantly: [Resources Allowed: All LF Certification Programs - T&C DOCS (Candidate Facing Resources)](https://docs.linuxfoundation.org/tc-docs/certification/certification-resources-allowed#certified-kubernetes-security-specialist-cks). 29 | 2. **Work your way through the curriculum.** 30 | * read through [Walid Shaari's curated resources](https://github.com/walidshaari/Certified-Kubernetes-Security-Specialist), which add a lot of useful detail to rather abstract curriculum. 31 | * follow-up reading on every topic! 32 | * get your handy dirty! Install every tool on your local kubernetes cluster and apply the getting started docs. 33 | I use k3d via [gitops playground](https://github.com/cloudogu/gitops-playground) 34 | 3. **Solve example questions, learn from the results and from your errors.** 35 | * [Mohamed Abukar's mock exam questions](https://github.com/moabukar/CKS-Exercises-Certified-Kubernetes-Security-Specialist/tree/main/7-mock-exam-questions) 36 | * [These](https://github.com/snigdhasambitak/cks) look like old killer.sh Questions with solutions, but no harm in having a look at them before having you first killer.sh try. 37 | * These look promising, including a learning platform: [ViktorUJ/cks](https://github.com/ViktorUJ/cks/tree/master/tasks/cks/labs) 38 | I discovered them only after I passed my CKS, though. 39 | 4. **Have your first try at killer.sh (the week before the exam)** 40 | * Take it serious, but be prepared to fail. 41 | * Main objective: Get accustomed to the exam environment and find out what to improve 42 | * Note down all your weak spots, both technologically as well es regarding efficiency on the shell/keyboard 43 | 5. **Have your second try at killer.sh (one or two days before the exam)** 44 | * This should give you confidence that you're now fully prepared and very time efficient with the tools 45 | * Note down some more fine-tuning 46 | * Follow up on the things that were not perfect 47 | 6. **Pass the exam** 48 | * Begin with the first question and try to solve as many questions as possible 49 | * Only if you're very unsure, flag some questions and come back later. 50 | Note that this takes some time, because you'll likely read the question and think about it twice. 51 | On the other hand, losing a lot of time with one question might lead to not having enough time to complete easier tasks later. 52 | * [Don't give up until the exam ends 💪](#dont-give-up) 53 | * 🥂 54 | 55 | ## Curated CKS Resources 56 | 57 | * Interactive learning environments 58 | * Two tries for interactive killer.sh included in your exam voucher. Use them, but use them wisely! 59 | * If you need more, create an account as [killercoda](https://killercoda.com/killer-shell-cka) 60 | * [ViktorUJ/cks](https://github.com/ViktorUJ/cks/tree/master/tasks/cks/labs) - local platform for learning kubernetes and preparation for CKS 61 | * Community resources 62 | * [Walid Shaari's curated resources](https://github.com/walidshaari/Certified-Kubernetes-Security-Specialist) 63 | * [Video Tutorials by Venkata Ramana Gali](https://www.youtube.com/watch?v=jvmShTBSBoA&list=PLFkEchqXDZx6Bw3B2NRVc499j1TavjOvm), 64 | corresponding [Repo](https://github.com/ramanagali/Interview_Guide/blob/main/CKS_Preparation_Guide.md) 65 | * Example questions 66 | * [Mohamed Abukar's mock exam questions](https://github.com/moabukar/CKS-Exercises-Certified-Kubernetes-Security-Specialist/tree/main/7-mock-exam-questions) 67 | * These look promising, including a learning platform: [ViktorUJ/cks](https://github.com/ViktorUJ/cks/tree/master/tasks/cks/labs) 68 | * [These](https://github.com/snigdhasambitak/cks) look like old killer.sh Questions with solutions, but no harm in having a look at them before having you first killer.sh try. 69 | * [Udemy Courses](https://www.udemy.com/topic/certified-kubernetes-security-specialist-cks/) 70 | even when you don't take a course, having a look at the content might help discovering topics that are relevant 71 | * There are a lot more, when you follow the links in the repos above. 72 | 73 | # Train for speed 74 | 75 | ## Disable unsafe pasting 76 | 77 | [Disable](https://killer.sh/faq) "unsafe pasting" in VM terminal emulator 78 | `"Terminal Preferences->General->Show unsafe paste dialog".` 79 | 80 | ## Use aliases and tab completion 81 | 82 | Those are the ones I used 83 | ```shell 84 | vi ~/.bashrc 85 | alias kg='k get' 86 | alias kd='k describe' 87 | alias ka='k apply -f' 88 | alias kn='k config set-context --current --namespace' 89 | # : wq 90 | source ~/.bashrc 91 | ``` 92 | 93 | Note: 94 | * Tab completion does not work for aliases 😐️ 95 | So I mainly use them to get a fast overview of pods, services, etc. 96 | ```bash 97 | kg po 98 | kg svc 99 | kg ing 100 | kg deploy 101 | ``` 102 | * There already is an alias `k=kubectl`. 103 | Tab completion does work for it, so use e.g. `k get po ` instead of typing or copying pod names 104 | * killer.sh recommends defining these variables, but I use `ctrl` + `z` + `bg` instead 105 | ```bash 106 | export do="--dry-run=client -o yaml" # k create deploy nginx --image=nginx $do 107 | 108 | export now="--force --grace-period 0" # k delete pod x $now 109 | ``` 110 | * vi is already set up with useful options, usually no need to edit `~/.vimrc` 111 | 112 | ## Be fast with CLI tools 113 | 114 | * Bash: 115 | * `ctrl` + `z`: keep open but return to shell 116 | * then `fg` return e.g. in `vi` 117 | * or `bg` keeps running in background e.g. for killing pods 118 | * `tmux` - first things in an exam: edit `bashrc` (see above), then start `tmux` 119 | * split pane, preferable horizontal (`ctrl`+`b`+`"`) (easier for copying with mouse) 120 | * move from pane to pane using `ctrl`+`b` + cursor keys 121 | * select mode (scrolling) `ctrl`+`b` + `]` - then use search or cursor keys or page up/down for navigating 122 | Careful: `ctrl`+`w` might close tab. Better use mouse for copying. 123 | * search: in select mode `ctrl`+`b`+`s` or `r` for reverse 124 | `n` for next hit; `Shift+n` for previous hit 125 | * increase size of pane by keeping `ctrl`+`b` pressed and using cursor keys 126 | * `ctrl`+`z` to toggle full screen for a pane 127 | * `vim` 128 | * `w` write, don't quit. Hints: 129 | * use other tmux pane to run `ka`, then come back to fix potential syntactic errors 130 | * or use `ctrl` + `z` to send `vim` to background, run `ka` then `fg` to return to `vim` 131 | * `q` quit, can be combined to `wq` 132 | * `y` = yank = copy 133 | * `p` = paste 134 | * `d` = delete = cut. If you want to delete more lines just to, e.g. `dddd` 135 | * `u` = undo 136 | * redo: `ctrl` + `r` 137 | * `v` = visual (select), use cursor keys, then `y` or `p` 138 | * indent: select then `>` or `<` (repeat with `.`) 139 | * `less` 140 | * switch search to case-insensitive using `:i` 141 | * search using `/` 142 | * `ssh` / `scp`, to access or copy files to/from nodes 143 | * `cut --delimiter ' ' --fields 9 # delimiter space, print field 9` 144 | 145 | # Know your tools and technologies 146 | 147 | * curl 148 | * Validate certificate: `curl -vk 2>&1 https://xyz | grep -i subject` 149 | * [Accessing the Kubernetes API from a Pod](https://kubernetes.io/docs/tasks/run-application/access-api-from-pod/) 150 | Note the path to the secrets 151 | ```bash 152 | k run debug-node --rm -it --image alpine -- 153 | 'curl --cacert ${CACERT} --header "Authorization: Bearer ${TOKEN}" -X GET ${APISERVER}/api/v1/namespaces/default/secrets' 154 | ``` 155 | * `kube-apiserver`, `kubelet`, etc. 156 | * interne YAMLs konfigurierbar: 157 | * `/etc/kubernetes/manifests` 158 | * `/etc/kubernetes/manifests/kube-apiserver.yaml` 159 | * `/etc/kubernetes/manifests/kube-controller-manager.yaml` 160 | * `/var/lib/kubelet/config.yaml` 161 | * apiserver is automatically restarted when `kube-apiserver.yaml` is changed. 162 | If need be this can be forced using `crictl rmp` , or even using `kubectl` (`k delete pod`) on a controlplane node or using restarting the service 163 | ```shell 164 | #SystemD 165 | systemctl status kubelet 166 | systemctl restart kubelet 167 | # or system V 168 | service kubelet restart 169 | service kubelet status 170 | ``` 171 | * [AppArmor](https://kubernetes.io/docs/tutorials/security/apparmor/) 172 | * AppArmor profiles are specified _per-container_. To specify the AppArmor profile to run a Pod container with, add an annotation to the Pod's metadata 173 | * `container.apparmor.security.beta.kubernetes.io/: ` 174 | * `container.apparmor.security.beta.kubernetes.io/c1: localhost/very-secure` 175 | * or `runtime/default` 176 | * Profile must be present on node 177 | * Accessing [App Armor Docs](https://gitlab.com/apparmor/apparmor/-/wikis/Documentation) ist permitted 178 | * See [k8s docs](https://kubernetes.io/docs/tutorials/security/apparmor/) for an example 179 | ```shell 180 | apparmor_parser -q < `cat /var/log/syslog | grep -i xyz` or `journalctl -fu falco | grep "xyz error"` 214 | * Output UID and Container ID: `%user.uid,%container.id` see [supported fields doc](https://falco.org/docs/reference/rules/supported-fields/) (allowed in exam!) 215 | ```yaml 216 | rules_file: 217 | - /etc/falco/falco_rules.yaml 218 | - /etc/falco/falco_rules.local.yaml 219 | - /etc/falco/rules.d # custom rules 220 | ``` 221 | * Tracee 222 | similar to falco, ebpf kernel events, signatures tigger alert. 223 | * Trivy 224 | * `trivy image alpine --severity=HIGH,CRITICAL` 225 | * Kubesec 226 | * `kubesec scan k8s-deployment.yaml | jq` 227 | * `kubesec scan jenkins/tmp-docker-gid-grepper.yaml | jq '.[].scoring.advise'` 228 | ```yaml 229 | apiVersion: v1 230 | kind: Pod 231 | spec: 232 | enableServiceLinks: false 233 | automountServiceAccountToken: false 234 | containers: 235 | - name: restricted 236 | securityContext: 237 | runAsNonRoot: true 238 | runAsUser: 100000 239 | runAsGroup: 100000 240 | allowPrivilegeEscalation: false 241 | readOnlyRootFilesystem: true 242 | seccompProfile: 243 | type: RuntimeDefault 244 | capabilities: 245 | drop: 246 | - ALL 247 | ``` 248 | * Kube-bench 249 | * Has to run on node! Either operator, pod or binary on node 250 | * `kube-bench run --targets=master > bench.txt` 251 | * `kube-bench run --targets=node > bench.txt` 252 | * Using `--target` makes solving specific tasks much easier because there usually are a lot of results 253 | * Writing to file allows for comparing the results after mitigation. 254 | * `kube-bench run --targets=master | less` also works 255 | * crictl, similar to `docker` but for CRI 256 | ```shell 257 | crictl pods 258 | crictl ps 259 | 260 | crictl ps --pod $podid # all containers of pod, also works with grep $podid 261 | crictl logs $containerid # see output of crcitcl ps --pod for $containerid 262 | crictl rmp $podid #remove pod 263 | ``` 264 | * `etcdctl`: Access secrets directly: (command can be found in docs for [encryption at rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/)): 265 | ```shell 266 | ETCDCTL_API=3 etcdctl \ 267 | --cacert=/etc/kubernetes/pki/etcd/ca.crt \ 268 | --cert=/etc/kubernetes/pki/etcd/server.crt \ 269 | --key=/etc/kubernetes/pki/etcd/server.key \ 270 | get /registry/secrets/default/secret1 | hexdump -C 271 | ``` 272 | * `strace` 273 | Count time, calls, and errors for each system call and report a summary on program exit: 274 | `strace -p pid -c` 275 | or ongoing output, e.g. in separate tmux pane/window `strace -p pid 2>&1 | grep -i kill` 276 | e.g. syscalls of container 277 | ```shell 278 | crictl pods # -> POD_ID 279 | critctl ps --pod POD_ID # -> CONTAINER_ID 280 | crictl inspect CONTAINER_ID | grep -i pid # -> PID 281 | strace -p PID -c 282 | # Ctrl + C 283 | #% time seconds usecs/call calls errors syscall 284 | #------ ----------- ----------- --------- --------- --------------- 285 | # 81,08 0,000030 30 1 1 rt_sigtimedwait 286 | # 18,92 0,000007 3 2 wait4 287 | #------ ----------- ----------- --------- --------- ---------------- 288 | #100,00 0,000037 12 3 1 total 289 | ``` 290 | * OPA [conftest](https://www.conftest.dev/) 291 | * `conftest test some.yaml` 292 | * looks for policies in folder `policy` 293 | * OPA [Gatekeeper](https://open-policy-agent.github.io/gatekeeper/website/) 294 | * OPA = general purpose policy engine; Gatekeeper = kubernetes-specific impl of OPA as K8s Admission controller 295 | * `ConstraintTemplate` -> describe rego 296 | * `Constraint` -> describes matching rules, parameters, etc., lists violations 297 | * Violations of constraints are listed in the `status` field of the corresponding constraint 298 | * The audit pod emits JSON-formatted audit logs to stdout. 299 | * Prometheus Metrics (not relevant for CKS) 300 | * [example](https://open-policy-agent.github.io/gatekeeper/website/docs/howto): 301 | ```yaml 302 | apiVersion: templates.gatekeeper.sh/v1 303 | kind: ConstraintTemplate 304 | metadata: 305 | name: k8srequiredlabels 306 | --- 307 | apiVersion: constraints.gatekeeper.sh/v1beta1 308 | kind: K8sRequiredLabels 309 | metadata: 310 | name: ns-must-have-gk 311 | spec: 312 | enforcementAction: dryrun # deny|warn 313 | ``` 314 | 315 | ```sh 316 | # from killer.sh 317 | ## Question 7 318 | k get crd | grep gatekeeper 319 | k edit blacklistimages pod-trusted-images # constraint: add parameter 320 | k edit constrainttemplates blacklistimages #-> template: change rego expression 321 | 322 | ## Preview Question 2 323 | # constraint, add parameter for namespace 324 | k edit requiredlabels namespace-mandatory-labels 325 | # template, fix rego 326 | k edit constrainttemplates requiredlabels 327 | ``` 328 | * `dmesg` - prints kernel logs 329 | * `kubeadm` 330 | ```shell 331 | # control plane 332 | k drain $NODE 333 | # ssh to master 334 | apt update && apt install kubeadm=1.29.0-1.1 # if necessary 335 | kubeadm upgrade plan # outputs commands for apply 336 | kubeadm upgrade apply v1.24.1 #use specific version! Outputs message to upgrade kubelet 337 | apt install kubelet=1.29.0-1.1 kubectl=1.29.0-1.1 338 | service kubelet restart #systemctl restart kubelet 339 | k uncordon $NODE 340 | 341 | # node: drain, ssh 342 | apt update && apt install kubeadm=1.29.0-1.1 343 | kubeadm upgrade node 344 | service kubelet restart 345 | # exit, k uncordon 346 | ``` 347 | * sha512sum 348 | ```bash 349 | sha512sum -c FILE # can contain all sums and binaries 350 | # FILE 351 | #SUM1 /a/file 352 | #SUM2 another-file 353 | # or indivudal files 354 | sha512sum -c <<< "$1 $2" 355 | ``` 356 | 357 | * You might want to install helpful software. Not sure if it is allowed, though 358 | * `apt install bat`-> binary is called `batcat` - syntax highlighted YAML files 359 | * or `tldr` if you need examples for using binaries 360 | or `curl cheat.sh/cut` 361 | 362 | # Be thorough 363 | 364 | * Switch to the correct kubecontext first (there is a command to copy at the beginning of each question) 365 | * Read questions carefully! There a several subtasks. 366 | * Read again when done to see if you did not miss anything. 367 | * Validate your work, e.g. `k get node`, `k get pod`, `k exec -it ...` 368 | * Double check if you wrote the result to the right file 369 | * Sometimes it has to be written to a file on the main host 370 | * Sometimes it has to be written to a file on a node 371 | * Sometimes it is not necessary to write a result 372 | * Every exercise features links to the relevant docs in the header. Have a look a them before searching in the docs first! 373 | * Copy each YAML before editing to your home folder, to be able to reset after possibly messing it up. 374 | Don't copy it to the folder of the original file, this might confuse a running api server, for example. 375 | 376 | In both my killer.sh tries I missed some points. 377 | Even though I solved things correctly or would have been able to, I wrote the result into a wrong file or missed to solve a subtask. 378 | Don't do that, be thorough! 379 | 380 | # Don't give up 381 | 382 | * You are going to need every point to can score and every second you're granted 383 | * If some tasks might seem to difficult, flag them and tackle them again at the end 384 | * Having only one or two minutes left is enough time to score some points by partially solving some question 385 | * You'll be surprised how fast you can learn to solve tasks under pressure 386 | * If you don't know how to solve, start by reading the docs linked at the top 387 | * You don't need to solve the whole question, partial solutions score points as well 388 | * You never know, a partial solution saved in the last seconds might be the one point you need for the 70% passing score! 389 | 390 | Don't give up until you're kicked out of the exam 💪 --------------------------------------------------------------------------------