← Road to Kubestronaut

KUBESTRONAUT · 2-HOUR PERFORMANCE-BASED · CURRENT CURRICULUM

CKS — The Certified Kubernetes Security Specialist Cheatsheet.

kubernetesckssecuritysupply-chainexam-prep

Road to Kubestronaut · Certification 5

CKS: Security specialist

Guide 5 of 5

CKS is the terminal-speed security finish line: a 2-hour, performance-based exam on Kubernetes v1.35. You must have passed CKA before attempting it. Current domains: Cluster Setup 15% · Cluster Hardening 15% · System Hardening 10% · Minimize Microservice Vulnerabilities 20% · Supply Chain Security 20% · Monitoring, Logging & Runtime Security 20%. Make the smallest safe change, preserve availability, and prove the control works.

0. First-minute setup and evidence loop

alias k=kubectl
export do="--dry-run=client -o yaml"
source <(kubectl completion bash)
complete -o default -F __start_kubectl k

# every task
k config use-context <named-context>
k config set-context --current --namespace=<namespace>
k get nodes

# preserve before editing host/control-plane files
sudo cp /etc/kubernetes/manifests/kube-apiserver.yaml \
  /etc/kubernetes/manifests/kube-apiserver.yaml.bak-outside-manifest-dir
backups outside static-pod directoryAny valid manifest left in /etc/kubernetes/manifests can be read by the kubelet as another static Pod. Put backups elsewhere, change one flag at a time, and watch the component return before continuing.

For each task: identify boundary → inspect current state → preserve rollback → change → wait → verify positive behavior → verify denied behavior. A policy that exists but selects nothing is not a security control.

1. Cluster Setup (15%)

Network security policies

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: { name: api-ingress, namespace: team }
spec:
  podSelector: { matchLabels: { app: api } }
  policyTypes: [Ingress]
  ingress:
  - from:
    - namespaceSelector: { matchLabels: { kubernetes.io/metadata.name: ingress } }
      podSelector: { matchLabels: { app: gateway } }
    ports: [{ protocol: TCP, port: 8443 }]
# verify labels and actual reachability from allowed and denied sources
k get pods -n team --show-labels
k get ns --show-labels
k describe netpol api-ingress -n team
k exec -n ingress deploy/gateway -- wget -qO- --timeout=2 https://api.team:8443
k run denied -n default --image=busybox:1.36 --rm -it --restart=Never -- \
  wget -qO- --timeout=2 http://api.team:8443
and vs ornamespaceSelector and podSelector in the same from item are ANDed. Separate list items are ORed. Indentation changes the security meaning.

CIS benchmark review

# use the binary/config supplied by the exam environment
kube-bench run --targets master
kube-bench run --targets node

# confirm the effective configuration, not only flags
ps -ef | grep kube-apiserver
sudo grep -nE 'anonymous-auth|authorization-mode|read-only-port' \
  /var/lib/kubelet/config.yaml /etc/kubernetes/manifests/*.yaml

CIS output is an assessment, not an automatic mandate. Fix the named control in the named component and validate availability. Some managed or lab configurations have justified exceptions.

Ingress TLS

k create secret tls web-tls --cert=tls.crt --key=tls.key -n app
spec:
  tls:
  - hosts: [app.example.com]
    secretName: web-tls
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service: { name: web, port: { number: 80 } }

Certificate hostnames must match the request host, the Secret must be in the Ingress namespace, and a controller must implement the Ingress.

Node metadata, endpoints and binaries

  • Prevent Pods from reaching cloud metadata unless explicitly needed; prefer workload identity to node-wide credentials.
  • Restrict kubelet, etcd, runtime sockets and control-plane ports by network and authentication.
  • Download binaries from the official channel and verify checksum/signature before execution.
sha256sum kubectl
echo '<expected-sha256>  kubectl' | sha256sum --check
openssl x509 -in tls.crt -noout -subject -issuer -dates -ext subjectAltName

2. Cluster Hardening (15%)

Least-privilege RBAC

k auth can-i --list --as=jane -n team
k auth can-i get secrets --as=system:serviceaccount:team:builder -n team
k get rolebindings,clusterrolebindings -A -o wide

k create role deploy-reader --verb=get,list,watch --resource=deployments.apps -n team
k create rolebinding jane-deploy-read --role=deploy-reader --user=jane -n team
k auth can-i list deployments --as=jane -n team
k auth can-i delete deployments --as=jane -n team
  • Avoid wildcards in verbs/resources and avoid cluster-admin for routine workloads.
  • Permissions to create Pods can indirectly expose mounted Secrets, service-account tokens, host paths or privileged execution.
  • Permissions to create/update Roles or bindings can be privilege escalation.
  • Test allowed and forbidden operations with the exact identity and namespace.

Service-account hygiene

apiVersion: v1
kind: Pod
metadata: { name: worker }
spec:
  serviceAccountName: worker
  automountServiceAccountToken: false
  containers:
  - { name: worker, image: example/worker:1.2 }

Use dedicated service accounts, minimal RoleBindings and projected short-lived tokens. Disable automount when the process does not call the Kubernetes API.

Restrict API access and upgrade

  • Disable anonymous authentication where required and use secure authorization modes.
  • Expose the API on trusted networks; use TLS and controlled bastion/VPN paths.
  • Protect admin kubeconfigs and rotate compromised credentials.
  • Upgrade supported Kubernetes releases to receive security fixes; drain and verify nodes as in CKA.
sudo grep -n -- '--anonymous-auth\|--authorization-mode' \
  /etc/kubernetes/manifests/kube-apiserver.yaml
k get --raw='/readyz?verbose'
k version
k get nodes -o custom-columns=NAME:.metadata.name,KUBELET:.status.nodeInfo.kubeletVersion

3. System Hardening (10%)

Reduce the host attack surface: minimal OS/packages, patched kernel/runtime, no unused network services, protected runtime sockets, least-privilege users, strong file permissions and host-level mandatory access control.

# inspect listening services and running units
sudo ss -lntup
sudo systemctl --type=service --state=running
sudo find /etc/kubernetes -type f -maxdepth 3 -ls

# AppArmor availability and profiles
sudo aa-status

# seccomp is expressed in the Pod security context
k get pod app -o jsonpath='{.spec.securityContext.seccompProfile.type}'
ControlWhat it restricts
seccompLinux system calls available to a process
AppArmorProfile-based file, capability, signal and network access
capabilitiesBreaks root privilege into discrete powers
runAsNonRootPrevents UID 0 execution when enforceable
readOnlyRootFilesystemReduces runtime filesystem mutation
layers, not substitutesseccomp, AppArmor, capabilities and non-root identity constrain different attack paths. One enabled field does not make the others redundant.

4. Minimize Microservice Vulnerabilities (20%)

Restricted workload pattern

apiVersion: v1
kind: Pod
metadata: { name: api, namespace: team }
spec:
  automountServiceAccountToken: false
  securityContext:
    runAsNonRoot: true
    seccompProfile: { type: RuntimeDefault }
  containers:
  - name: api
    image: registry.example/api@sha256:<digest>
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities: { drop: ["ALL"] }
    resources:
      requests: { cpu: 100m, memory: 128Mi }
      limits: { cpu: 500m, memory: 256Mi }
    volumeMounts:
    - { name: tmp, mountPath: /tmp }
  volumes:
  - { name: tmp, emptyDir: {} }

If a read-only image needs writable paths, mount narrow emptyDir volumes instead of making the whole root filesystem writable. Never add privilege merely to silence an application error without understanding the required access.

Pod Security Admission

# stage with warn/audit, then enforce after remediation
k label ns team pod-security.kubernetes.io/warn=restricted \
  pod-security.kubernetes.io/warn-version=latest --overwrite
k label ns team pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/audit-version=latest --overwrite
k label ns team pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/enforce-version=latest --overwrite

Secrets and isolation

  • Encrypt Secret data at rest; restrict RBAC and backup access; rotate leaked values.
  • Use separate namespaces, identities, quotas and NetworkPolicies for tenants, but recognize namespaces alone are not hard multi-tenancy.
  • Use sandboxed runtimes/VM isolation for stronger untrusted-workload boundaries.
  • Use Cilium, Istio or another appropriate dataplane for workload-to-workload encryption when required; NetworkPolicy alone does not encrypt.

5. Supply Chain Security (20%)

Minimize and inspect images

FROM golang:1.24 AS build
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -trimpath -ldflags='-s -w' -o /out/app ./cmd/app

FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=build /out/app /app
USER nonroot:nonroot
ENTRYPOINT ["/app"]
  • Smaller base, fewer packages and no shell/package manager reduce attack surface.
  • Run as non-root, pin digest and rebuild from maintained bases.
  • Do not place build credentials or secrets in layers; multi-stage builds do not erase a secret copied into an earlier published stage.

Scan, inventory, sign and admit

# exact commands depend on tools installed in the exam environment
trivy image --severity HIGH,CRITICAL registry.example/app:1.4
trivy config deployment.yaml
kube-linter lint deployment.yaml
kubesec scan deployment.yaml

# example Sigstore workflow when cosign is supplied
cosign verify --key cosign.pub registry.example/app@sha256:<digest>
cosign verify-attestation --key cosign.pub \
  --type slsaprovenance registry.example/app@sha256:<digest>
Evidence/controlAnswers
Vulnerability scanDoes known affected software exist?
Static manifest analysisDoes configuration violate a policy or best practice?
SBOMWhich software components are present?
SignatureWho signed this exact artifact; is integrity intact?
Provenance attestationHow and where was the artifact built?
Admission policyMay this artifact/configuration enter the cluster?

Enforce trusted registries, digest pinning, signatures/attestations and policy through an admission mechanism available in the environment. Test an allowed image and a deliberately disallowed image.

6. Monitoring, Logging and Runtime Security (20%)

Kubernetes audit logging

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata
  resources:
  - group: ""
    resources: ["secrets"]
- level: RequestResponse
  verbs: ["create", "update", "patch", "delete"]
- level: None
  nonResourceURLs: ["/healthz*", "/readyz*"]
- level: Metadata
# API server flags need both policy and log destination plus hostPath mounts
sudo grep -n -- '--audit-' /etc/kubernetes/manifests/kube-apiserver.yaml
sudo tail -f /var/log/kubernetes/audit/audit.log
k get --raw=/readyz

Audit levels are None, Metadata, Request, RequestResponse. Rules are evaluated in order; first match wins. Avoid logging sensitive request bodies unless the task explicitly requires it.

Runtime detection and investigation

Behavioral detection observes what running workloads actually do: unexpected shells, package installation, writes to sensitive paths, privilege changes, suspicious network connections or access to credentials. Falco-style rules commonly match kernel/runtime events against conditions.

# investigate a suspicious workload
k get pod suspicious -o yaml
k describe pod suspicious
k logs suspicious --all-containers --since=30m
k get events --field-selector involvedObject.name=suspicious
k auth can-i --list --as=system:serviceaccount:team:app -n team

# node/runtime evidence when authorized
sudo crictl ps -a
sudo crictl inspect <container-id>
sudo journalctl -u kubelet --since '30 min ago'
  1. Preserve relevant evidence and timestamps.
  2. Scope identity, namespace, node, image digest, network and affected objects.
  3. Contain with minimal blast radius—policy, scale/isolate, credential rotation as appropriate.
  4. Remove persistence and repair the exploited control.
  5. Recover from trusted artifacts and verify monitoring catches recurrence.

Runtime immutability

  • Use read-only root filesystems with explicit writable volumes.
  • Disallow exec/package-manager workflows for production change; rebuild and redeploy a new image.
  • Pin images by digest and detect drift from declared state.
  • Drop privilege and prevent hostPath/host namespaces unless explicitly required.

7. Admission policy and encryption at rest

Validate before persistence

Admission runs after authentication and authorization but before an object is stored. Mutating admission changes a request; validating admission accepts or rejects it. Policy can enforce trusted registries, digest pinning, required labels, restricted security context and prohibited host access. Failure policy matters: Fail preserves enforcement when a webhook is unavailable; Ignore favors availability but can fail open.

k get validatingwebhookconfigurations,mutatingwebhookconfigurations
k get validatingadmissionpolicies,validatingadmissionpolicybindings 2>/dev/null || true
k get events -A --sort-by=.lastTimestamp | tail -30

# test policy with server-side dry-run before persistence
k apply --dry-run=server -f compliant.yaml
k apply --dry-run=server -f deliberately-denied.yaml
do not lock out the control planeScope webhooks carefully with selectors and rules, use reachable TLS endpoints, and exclude the webhook's own recovery path where appropriate. A broad failing webhook can block every matching API write.

Encrypt Kubernetes API data at rest

apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources: [secrets]
  providers:
  - aesgcm:
      keys:
      - name: key1
        secret: <base64-encoded-32-byte-key>
  - identity: {}

The first provider writes new data; later providers can read existing data. The identity fallback supports migration from plaintext but means plaintext remains readable. Mount the configuration into the API server, add --encryption-provider-config, verify readiness, then rewrite existing Secrets so they are re-encrypted:

# after the API server is healthy with the provider
k get secrets -A -o json | k replace -f -

# verify storage carefully from etcd: ciphertext should not expose the value
ETCDCTL_API=3 etcdctl get /registry/secrets/team/db \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

Protect and rotate encryption keys; losing them can make data unrecoverable. Encryption at rest does not replace RBAC, TLS in transit or secret rotation.

Runtime rule reasoning

# conceptual Falco-style rule; use the installed tool's schema
- rule: Shell in production container
  condition: container and proc.name in (bash, sh, zsh) and k8s.ns.name = "prod"
  output: "shell in prod (user=%user.name pod=%k8s.pod.name cmd=%proc.cmdline)"
  priority: WARNING

A useful runtime rule has a narrow behavior, enough context for triage and tolerable noise. Baseline legitimate automation, exclude by stable identity rather than broad process names, and test with a controlled event. Runtime detection complements prevention because signed, scanned and admitted software can still be exploited after startup.

8. Security verification matrix

ControlPositive testNegative test
RBACRequired verb succeeds as target identityUnneeded verb returns forbidden
NetworkPolicyAllowed source reaches exact portDenied source times out/fails
Pod securityCompliant Pod admits and startsPrivileged/non-compliant Pod is rejected
Image policyTrusted signed digest admitsUnknown registry/signature is denied
AuditRelevant request produces expected eventNoise/sensitive bodies are excluded as designed
Control plane/readyz and kubectl returnAnonymous/unauthorized access fails

9. Common mistakes and final study order

  • Editing the wrong cluster or namespace.
  • Leaving a static-Pod manifest backup in the manifests directory.
  • Applying a default-deny policy before proving required DNS/egress paths.
  • Writing a NetworkPolicy that selects no Pods because labels are wrong.
  • Granting broad RBAC because the narrow Role was slightly harder to write.
  • Assuming non-root alone prevents privilege escalation.
  • Breaking an app with read-only rootfs without mounting its required writable paths.
  • Calling a scan, SBOM or signature interchangeable.
  • Enabling audit flags without mounting the policy/log path into the API server static Pod.
  • Making several control-plane changes before verifying the first one.

Practice order: NetworkPolicy → RBAC/service accounts → restricted Pods/PSA → API/CIS hardening → seccomp/AppArmor → image scanning/signing/admission → audit policy → runtime investigation. Rehearse every task with a positive and negative test; security without evidence is only configuration.

Official sources & freshness

This guide was checked against the official Linux Foundation exam page and CNCF curriculum on 19 July 2026. Exam versions and policies can change; re-check the source page before booking.

← prev: CKAD series map →
© cvam — written in plaintext, served warm