Environment, Configuration & Security
Feed config and secrets into apps, cap resources, control who can do what, and run with least privilege. The heaviest domain.
The full loop: understand → drill the commands → prove it under the clock. Every objective below is taught here and practised in the drills.
1Understand it
ConfigMaps & Secrets
Keep configuration out of your image so the same image runs everywhere. A ConfigMap holds non-sensitive settings; a Secret holds sensitive values. Inject either as environment variables or mounted files.
- Inject via env (envFrom / valueFrom) or as a mounted volume.
- Secrets are only base64-encoded, not encrypted by default, treat as sensitive.
- A mounted ConfigMap updates the file live; env vars need a Pod restart.
Three ways to inject config
envFrom: # all keys → env vars
- configMapRef: { name: app-config }
env:
- name: DB_PASS # one secret key → env var
valueFrom:
secretKeyRef: { name: db, key: password }
volumeMounts: # or mount as files
- name: cfg
mountPath: /etc/configRequests, limits & quotas
A request is the resources a Pod is guaranteed (used by the scheduler to place it); a limit is the ceiling it can't exceed. Over a memory limit gets the container OOMKilled; over a CPU limit just throttles it. ResourceQuotas cap a whole namespace.
- requests drive scheduling; limits cap usage.
- Memory over limit → OOMKilled (exit 137); CPU over limit → throttled.
- ResourceQuota and LimitRange govern a namespace.
Container requests (scheduling) + limits (cap)
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"SecurityContext
A SecurityContext controls how securely a container runs: which user it runs as, whether it can gain extra privileges, and which Linux capabilities it has. Running as non-root and dropping capabilities is the baseline for a hardened app.
- runAsNonRoot / runAsUser set identity.
- allowPrivilegeEscalation: false and readOnlyRootFilesystem: true harden it.
- capabilities.drop: [ALL], then add only what's needed.
Hardened SecurityContext (Pod level + container override)
spec:
securityContext: # applies to all containers
runAsNonRoot: true
runAsUser: 1000
containers:
- name: app
image: myapp
securityContext: # overrides for this container
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities: { drop: ["ALL"] }ServiceAccounts
A ServiceAccount is the identity a Pod uses to talk to the Kubernetes API. By default Pods get the namespace's default account; for least privilege you create a dedicated ServiceAccount and grant it only the permissions (via RBAC) it needs.
- spec.serviceAccountName sets which account a Pod uses.
- Permissions come from RBAC (Roles + bindings), not the account itself.
- Avoid the default account for anything that calls the API.
RBAC, authorization
RBAC decides who can do what. A Role is a set of allowed verbs (get, list, create…) on resources within a namespace; a RoleBinding grants that Role to a user or ServiceAccount. ClusterRole and ClusterRoleBinding do the same cluster-wide.
- Role + RoleBinding = namespaced; ClusterRole + ClusterRoleBinding = cluster-wide.
- Bind Roles to ServiceAccounts so Pods get scoped API access.
- Least privilege: grant only the verbs and resources needed.
Grant a ServiceAccount read access to Pods, then verify
kubectl create role reader --verb=get,list,watch --resource=pods kubectl create rolebinding read-pods \ --role=reader --serviceaccount=dev:app-sa kubectl auth can-i list pods --as=system:serviceaccount:dev:app-sa
Admission control
After a request is authenticated and authorized, admission controllers get the final say, they can validate or even mutate it before it's stored. This is how rules like "every Pod must set resource limits" or "no privileged containers" get enforced. Pod Security Admission (PSA) is the built-in one you'll meet most.
- Runs after authentication + authorization, before the object is saved.
- Two kinds: validating (accept/reject) and mutating (modify defaults).
- Pod Security Admission enforces baseline/restricted profiles per namespace.
Enforce the "restricted" Pod Security profile on a namespace
kubectl label namespace dev \ pod-security.kubernetes.io/enforce=restricted
Custom Resources (awareness)
Kubernetes can be extended with Custom Resource Definitions (CRDs), new object types beyond the built-ins. Operators use these to manage complex apps. For CKAD you mainly recognise them and interact with existing custom resources, not author controllers.
- A CRD defines a new kind; instances are custom resources.
- kubectl get <crd-plural> works just like built-in objects.
- Operators = CRD + a controller that reconciles it.
2 Drill the commands & prove it
Mastery, 0/6 objectives
An objective turns green only when you've solved every drill in it, not just one.
- Create and source ConfigMaps from literals, files, and env-files; inject as env/envFrom.0/5
- Create generic, docker-registry, and tls Secrets imperatively and consume them safely.0/5
- Set resource requests/limits on workloads and define ResourceQuota / LimitRange.0/3
- Define pod and container securityContext: runAsNonRoot, runAsUser, fsGroup, capabilities, readOnlyRootFilesystem, privileged.0/6
- Create ServiceAccounts, attach them to workloads, and test effective permissions with auth can-i --as.0/4
- Author Roles, ClusterRoles and their bindings imperatively with correct subject syntax.0/4
Create a ConfigMap named app-config with two literals: COLOR=blue and SIZE=large.
Drills check the command pattern deterministically, there is often more than one correct form. For full fidelity, pair this with real-cluster reps (the killer.sh simulator is included free with your exam registration).