└── README.md /README.md: -------------------------------------------------------------------------------- 1 | # CKS Exam Hints 2 | 3 | ## Useful Links 4 | 5 | - https://github.com/walidshaari/Certified-Kubernetes-Security-Specialist#books 6 | 7 | - https://github.com/kodekloudhub/certified-kubernetes-security-specialist-cks-course/tree/main/docs/08-Mock-Exams 8 | 9 | 10 | ## Labs Practice 11 | 12 | - KodeKloud Mock Exams 13 | - ACloudGuru Labs 14 | 15 | 16 | 17 | ## CKS KodeKloud Mock Exam solution video 18 | 19 | - https://www.youtube.com/watch?v=7eH7vfT0axA&list=PLglXbBWxN2H9-ATq0ShHVlMWskhRgvdJz 20 | 21 | 22 | ## Useful Bookmarks 23 | 24 | kubectl Cheat Sheet -- https://kubernetes.io/docs/reference/kubectl/cheatsheet/ 25 | 26 | Kubectl Commands -- https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands 27 | 28 | Network Policies -- https://kubernetes.io/docs/concepts/services-networking/network-policies/ 29 | 30 | Security Context -- https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ 31 | 32 | Secrets -- https://kubernetes.io/docs/concepts/configuration/secret/ 33 | 34 | RBAC -- https://kubernetes.io/docs/reference/access-authn-authz/rbac/ 35 | 36 | Seccomp -- https://kubernetes.io/docs/tutorials/clusters/seccomp/ 37 | 38 | Apparmor -- https://kubernetes.io/docs/tutorials/clusters/apparmor/ 39 | 40 | ImageWebhookPolicy -- https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/ 41 | 42 | Audit Policy -- https://kubernetes.io/docs/tasks/debug-application-cluster/audit/ 43 | 44 | PodSecurityPolicy -- https://kubernetes.io/docs/concepts/policy/pod-security-policy/ 45 | 46 | Kubelet Config -- https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/ 47 | 48 | RuntimeClaas -- https://kubernetes.io/docs/concepts/containers/runtime-class/ 49 | 50 | Admission Controllers -- https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#podsecuritypolicy 51 | 52 | automountServiceAccountToken -- https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ 53 | 54 | Pod Volumes -- https://kubernetes.io/docs/concepts/storage/volumes/ 55 | 56 | PV PVC -- https://kubernetes.io/docs/tasks/configure-pod-container/configure-persistent-volume-storage/ 57 | 58 | Ingress -- https://kubernetes.io/docs/concepts/services-networking/ingress/ 59 | 60 | 61 | ## Useful Commands 62 | 63 | ```bash 64 | crictl -r /var/run/containerd/containerd.sock pods 65 | 66 | crictl -r /var/run/containerd/containerd.sock ps 67 | 68 | crictl -r /var/run/containerd/containerd.sock logs -f ef86e6ecf0bcb 69 | ``` 70 | 71 | ## Fix CIS Benchmark Issues 72 | 73 |
show 74 |

75 | 76 | ### kubelet 77 | ```yaml 78 | vim /var/lib/kubelet/config.yaml 79 | authentication: 80 | anonymous: 81 | enabled: false 82 | webhook: 83 | enabled: true 84 | authorization: 85 | mode: Webhook 86 | protectKernelDefaults: true 87 | 88 | systemctl restart kubelet.service 89 | systemctl status kubelet.service 90 | ``` 91 | 92 | ### kube-apiserver 93 | ```bash 94 | vim /etc/kubernetes/manifests/kube-apiserver.yaml 95 | - --authorization-mode=Node,RBAC 96 | - --profiling=false 97 | ``` 98 | 99 | ### etcd 100 | ```bash 101 | mv /etc/kubernetes/manifests/etcd.yaml /etc/kubernetes/ 102 | vim /etc/kubernetes/etcd.yaml 103 | - --client-cert-auth=true 104 | ``` 105 | 106 |

107 |
108 | 109 | ## Configure Admission Control | ImageWebhookPolicy 110 | 111 |
show 112 |

113 | 114 | ### admission-control.conf 115 | ```yaml 116 | vim /etc/kubernetes/admission-control/admission-control.conf 117 | apiVersion: apiserver.config.k8s.io/v1 118 | kind: AdmissionConfiguration 119 | plugins: 120 | - name: ImagePolicyWebhook 121 | path: imagepolicy.conf 122 | ``` 123 | 124 | ### imagepolicy.conf | imagepolicy.json 125 | ```bash 126 | vim /etc/kubernetes/admission-control/imagepolicy.conf 127 | { 128 | "imagePolicy": { 129 | "kubeConfigFile": "/etc/kubernetes/admission-control/imagepolicy_backend.kubeconfig", 130 | "allowTTL": 50, 131 | "denyTTL": 50, 132 | "retryBackoff": 500, 133 | "defaultAllow": false 134 | } 135 | } 136 | Note: Change true to false and Take note of kubeConfigFile 137 | ``` 138 | 139 | ### imagepolicy_backend.kubeconfig 140 | ```yaml 141 | vim /etc/kubernetes/admission-control/imagepolicy_backend.kubeconfig 142 | apiVersion: v1 143 | kind: Config 144 | clusters: 145 | - name: trivy-k8s-webhook 146 | cluster: 147 | certificate-authority: /etc/kubernetes/admission-control/imagepolicywebhook-ca.crt 148 | server: https://acg.trivy.k8s.webhook:8090/scan 149 | contexts: 150 | - name: trivy-k8s-webhook 151 | context: 152 | cluster: trivy-k8s-webhook 153 | user: api-server 154 | current-context: trivy-k8s-webhook 155 | preferences: {} 156 | users: 157 | - name: api-server 158 | user: 159 | client-certificate: /etc/kubernetes/admission-control/api-server-client.crt 160 | client-key: /etc/kubernetes/admission-control/api-server-client.key 161 | # Note: Edit server value 162 | ``` 163 | 164 | ### kube-apiserver 165 | ```bash 166 | vim /etc/kubernetes/manifests/kube-apiserver.yaml 167 | - --admission-control-config-file=/etc/kubernetes/admission-control/admission-control.conf 168 | - --enable-admission-plugins=NodeRestriction,ImagePolicyWebhook 169 | ``` 170 | 171 |

172 |
173 | 174 | ## Audit Policy 175 | 176 |
show 177 |

178 | 179 | ### audit-policy.yaml 180 | ```yaml 181 | apiVersion: audit.k8s.io/v1 182 | kind: Policy 183 | omitStages: 184 | - "RequestReceived" 185 | rules: 186 | - level: None 187 | resources: 188 | - group: "" 189 | resources: ["pods/log", "pods/status"] 190 | - level: RequestResponse 191 | resources: 192 | - group: "" 193 | resources: ["configmaps"] 194 | - level: Request 195 | resources: 196 | - group: "" 197 | resources: ["services", "pods"] 198 | namespaces: ["web"] 199 | - level: Metadata 200 | resources: 201 | - group: "" 202 | resources: ["secrets"] 203 | - level: Metadata 204 | ``` 205 | 206 | ### kube-apiserver.yaml 207 | ```bash 208 | vim /etc/kubernetes/manifests/kube-apiserver.yaml 209 | - --audit-policy-file=/etc/kubernetes/audit-policy.yaml 210 | - --audit-log-path=/var/log/kubernetes/audit.log 211 | - --audit-log-maxage=10 212 | - --audit-log-maxbackup=1 213 | ``` 214 | 215 |

216 |
217 | 218 | 219 | ## PodSecurityPolicy 220 | 221 |
show 222 |

223 | 224 | ```yaml 225 | vim nopriv-psp.yml 226 | apiVersion: policy/v1beta1 227 | kind: PodSecurityPolicy 228 | metadata: 229 | name: nopriv-psp 230 | spec: 231 | privileged: false 232 | runAsUser: 233 | rule: "RunAsAny" 234 | fsGroup: 235 | rule: "RunAsAny" 236 | seLinux: 237 | rule: "RunAsAny" 238 | supplementalGroups: 239 | rule: "RunAsAny" 240 | k apply -f nopriv-psp.yml 241 | ``` 242 | 243 | ```yaml 244 | /home/cloud_user/use-nopriv-psp.yml 245 | apiVersion: rbac.authorization.k8s.io/v1 246 | kind: ClusterRole 247 | metadata: 248 | name: use-nopriv-psp 249 | rules: 250 | - apiGroups: ['policy'] 251 | resources: ['podsecuritypolicies'] 252 | verbs: ['use'] 253 | resourceNames: 254 | - nopriv-psp 255 | k apply -f /home/cloud_user/use-nopriv-psp.yml 256 | ``` 257 | 258 | ```yaml 259 | /home/cloud_user/hoth-sa-use-nopriv-psp.yml 260 | apiVersion: rbac.authorization.k8s.io/v1 261 | kind: ClusterRoleBinding 262 | metadata: 263 | name: hoth-sa-use-nopriv-psp 264 | roleRef: 265 | kind: ClusterRole 266 | name: use-nopriv-psp 267 | apiGroup: rbac.authorization.k8s.io 268 | subjects: 269 | - kind: ServiceAccount 270 | name: hoth-sa 271 | namespace: hoth 272 | k apply -f /home/cloud_user/hoth-sa-use-nopriv-psp.yml 273 | ``` 274 | 275 |

276 |
277 | 278 | 279 | ## RuntimeClass | gVisor 280 | 281 |
show 282 |

283 | 284 | ### RuntimeClass 285 | ```yaml 286 | vim /home/cloud_user/sandbox.yml 287 | apiVersion: node.k8s.io/v1 288 | kind: RuntimeClass 289 | metadata: 290 | name: sandbox 291 | handler: runsc 292 | k apply -f /home/cloud_user/sandbox.yml 293 | ``` 294 | 295 | ### Edit deployment 296 | ```bash 297 | k -n sunnydale edit deployments.apps buffy # runtimeClassName: sandbox 298 | k -n sunnydale edit deployments.apps giles 299 | k -n sunnydale edit deployments.apps spike 300 | ``` 301 | 302 | ### Verification 303 | ```bash 304 | k -n sunnydale exec buffy-7bdbdfc554-ls5q5 -- dmesg 305 | 306 | [ 0.000000] Starting gVisor... 307 | [ 0.453650] Forking spaghetti code... 308 | [ 0.939306] Conjuring /dev/null black hole... 309 | [ 1.162591] Searching for socket adapter... 310 | [ 1.450979] Generating random numbers by fair dice roll... 311 | [ 1.907884] Waiting for children... 312 | [ 2.063679] Checking naughty and nice process list... 313 | [ 2.554570] Recruiting cron-ies... 314 | [ 3.023213] Gathering forks... 315 | [ 3.300373] Synthesizing system calls... 316 | [ 3.401099] Searching for needles in stacks... 317 | [ 3.521588] Setting up VFS2... 318 | [ 3.938928] Ready! 319 | ``` 320 | 321 |

322 |
323 | 324 | 325 | ## Security Best Practices 326 |
show 327 |

328 | 329 | - Fixing issues in Dockerfile 330 | - Fixing issues in Deployment 331 | 332 |

333 |
334 | 335 | ## Ensure Containers Are Static and Immutable 336 | 337 |
show 338 |

339 | 340 | - runAsUser: 0 341 | - readOnlyRootFilesystem: false 342 | - priveledged: true 343 | 344 |

345 |
346 | 347 | 348 | ## Trivy Commands 349 | 350 |
show 351 |

352 | 353 | ```bash 354 | k -n development get pods 355 | k -n development get pods --output=custom-columns="NAME:.metadata.name,IMAGE:.spec.containers[*].image" 356 | NAME IMAGE 357 | work1 busybox:1.33.1 358 | work2 nginx:1.14.2 359 | work3 amazonlinux:2 360 | work4 amazonlinux:1 361 | work5 centos:7 362 | trivy image -s HIGH,CRITICAL busybox:1.33.1 363 | trivy image -s HIGH,CRITICAL nginx:1.14.2 #HIGH and CRITICAL 364 | trivy image -s HIGH,CRITICAL amazonlinux:2 365 | trivy image -s HIGH,CRITICAL amazonlinux:1 366 | trivy image -s HIGH,CRITICAL centos:7 #HIGH and CRITICAL 367 | ``` 368 | 369 |

370 |
371 | 372 | ## Falco rules 373 | 374 |
show 375 |

376 | 377 | ```bash 378 | sudo falco -M 45 -r /home/cloud_user/monitor_rules.yml > /home/cloud_user/falco_output.log 379 | ``` 380 | 381 | ```bash 382 | - /etc/falco/falco_rules.local.yaml 383 | - /etc/falco/falco_rules.yaml 384 | - /etc/falco/falco.yaml 385 | systemctl restart falco.service 386 | ``` 387 | 388 | 389 |

390 |
391 | 392 | 393 | ## AppArmor Profile 394 | 395 |
show 396 |

397 | 398 | ```bash 399 | cat k8s-deny-write 400 | #include 401 | profile k8s-deny-write flags=(attach_disconnected) { 402 | #include 403 | file, 404 | # Deny all file writes. 405 | deny /** w, 406 | } 407 | sudo aa-status | grep k8s-deny-write 408 | 409 | sudo apparmor_parser k8s-deny-write 410 | 411 | sudo aa-status | grep k8s-deny-write 412 | k8s-deny-write 413 | ``` 414 | 415 | 416 | ```yaml 417 | vim ~/writedeny.yml 418 | apiVersion: v1 419 | kind: Pod 420 | metadata: 421 | name: writedeny 422 | namespace: dev 423 | annotations: 424 | container.apparmor.security.beta.kubernetes.io/busybox: localhost/k8s-deny-write 425 | spec: 426 | containers: 427 | - name: busybox 428 | image: busybox:1.33.1 429 | command: ['sh', '-c', 'while true; do echo writedeny > password.txt; sleep 5; done'] 430 | # Note: annotations, container and apparmor profile to be edited 431 | # container.apparmor.security.beta.kubernetes.io/<>: localhost/<> 432 | ``` 433 |

434 |
435 | 436 | 437 | ## Other topics 438 | - Seccomp Profile 439 | - Fix a Pod's Service Account That Has Too Many Permissions 440 | - Create a Network Policy 441 | - Get a Username, Password from an Existing Secret. Create a Secret and Mount It to a Pod 442 | - automountServiceAccountToken: false --------------------------------------------------------------------------------