Application Environment, Configuration and Security
Last verified against its sources on 23 September 2026
Application Environment, Configuration and Security is the largest single domain on the CKAD exam at 25%: externalizing configuration and secrets correctly, constraining what a workload can consume, understanding how a request to the API server is actually decided, and extending Kubernetes itself with custom resources.
Several of this module's facts are the kind that look obvious until an exam question is built around the exception — a Secret that isn't encrypted, an environment variable that doesn't update, a CustomResourceDefinition that does nothing without a controller.
ConfigMaps and Secrets
- Externalize configuration into a ConfigMap and sensitive data into a Secret, then consume each correctly in a Pod.
- Predict whether a running Pod picks up a ConfigMap or Secret change automatically.
A ConfigMap holds non-sensitive configuration; a Secret
holds sensitive data such as passwords or tokens, structured
the same way. Both are consumed the same two ways: as an
environment variable (env[].valueFrom.configMapKeyRef or
secretKeyRef) or as a mounted volume, where each key becomes
a file. Neither storage mechanism is exclusive to
sensitivity level — a Secret is simply the object Kubernetes
treats as sensitive by convention and tooling, not one that's
cryptographically protected on its own.
That last point matters more than it sounds: Secret values are base64-encoded, not encrypted. Base64 is a reversible encoding, not a cipher — anyone with API read access to a Secret can decode it in one command. Genuine protection comes from RBAC controlling who can read the Secret at all, plus, if needed, separately configuring encryption at rest for etcd.
bash
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
volumeMounts:
- name: db-creds
mountPath: /etc/db-credentials
readOnly: true
volumes:
- name: db-creds
secret:
secretName: db-credentialsUpdate behavior differs sharply by consumption method. A ConfigMap or Secret consumed as an environment variable is fixed at container start — changing the object later has no effect until the Pod is restarted. One consumed as a volume mount updates eventually: the kubelet checks freshness on its periodic sync, so the total delay is roughly the sync period plus a cache propagation delay. A container using a ConfigMap or Secret as a subPath volume mount never receives updates at all, regardless of how long you wait.
Setting immutable: true on a ConfigMap or Secret — stable
since Kubernetes v1.21 — locks its data permanently: the flag
itself cannot be reverted, and the data cannot be edited
afterward. The only way to change it is to delete and recreate
the object, and since existing Pods keep their old mount
point, those Pods should be recreated too.
A Secret consumed via an environment variable is updated. Does the running Pod see the new value without a restart?Answer it yourself first, then open this.
No — environment variables are fixed at container start; only volume-mounted (non-subPath) Secrets update in place, and even then only after a delay.
Resource Requests, Limits and Quotas
- Set container resource requests and limits that produce the intended Quality of Service class.
- Apply a ResourceQuota and a LimitRange to constrain a namespace's overall resource usage.
A request is what the scheduler uses to place a Pod — it
only schedules a Pod onto a node with at least that much
spare capacity. A limit is a hard ceiling: CPU usage above
the limit gets throttled, while memory usage above the limit
can get the container killed by the out-of-memory handler.
These two numbers, present or absent per container, decide a
Pod's Quality of Service (QoS) class. Guaranteed requires
every container to set both a CPU and a memory request equal
to its limit. Burstable covers anything that doesn't meet
Guaranteed but sets at least one request or limit somewhere.
BestEffort is a Pod where no container sets any request or
limit at all.
QoS class decides eviction order when a node runs low on
resources: BestEffort Pods are evicted first, then
Burstable, and Guaranteed Pods last.
bash
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "250m"
memory: "256Mi"A ResourceQuota is a namespace-scoped object that caps
total resource consumption — or total object counts, such as
the number of Pods or Services — across everything in that
namespace. A namespace-wide quirk worth knowing: once a
namespace has a ResourceQuota covering compute resources
(CPU or memory), every Pod submitted to that namespace must
specify its own requests and limits, or it is rejected
outright at admission — the quota can't account for a Pod
whose consumption it can't measure.
A LimitRange is a different, complementary namespace-scoped object: it supplies default requests and limits for any container that omits them, and can also enforce per-container minimum and maximum bounds. Where a ResourceQuota caps totals, a LimitRange fills gaps and bounds individual containers.
A container sets a memory request and limit but no CPU request or limit at all. Guaranteed, Burstable, or BestEffort?Answer it yourself first, then open this.
Burstable — it doesn't meet Guaranteed's all-resources-equal rule, but it does have at least one request or limit set.
ServiceAccounts, Authentication, Authorization and SecurityContexts
- Attach a ServiceAccount to a Pod and control whether its token is automatically mounted.
- Apply a SecurityContext that follows least-privilege for a Pod or container.
Every request to the Kubernetes API server passes through three stages in order: authentication (who is making this request), authorization (is that identity allowed to do this — RBAC is the usual mechanism), and admission control (mutating and validating webhooks and built-in controllers that can still modify or reject an already-authorized request). Any stage can stop the request before it reaches etcd.
Every Pod runs as a ServiceAccount — the default one for its namespace if none is specified. How that identity's token reaches the Pod has changed: a long-lived, non-expiring token stored in an auto-created Secret used to be generated for every ServiceAccount automatically; since Kubernetes v1.24, that automatic Secret is no longer created by default. Instead, Pods get a short-lived, audience-bound token delivered through a projected volume — stable behavior since v1.22 — refreshed automatically before it expires.
A securityContext can be set at the Pod level (applies to
every container) or the container level (overrides the Pod
level for that one container, field by field). Useful fields:
runAsUser sets the numeric UID a process runs as;
runAsNonRoot: true doesn't pick a UID for you — it only
refuses to start the container if the UID it would run as
turns out to be root. allowPrivilegeEscalation: false blocks
a process from gaining more privileges than its parent had.
readOnlyRootFilesystem: true mounts the container's root
filesystem read-only. capabilities.drop: ["ALL"], optionally
followed by adding back only the specific Linux capabilities
actually needed, is the least-privilege pattern for
capabilities.
If a Pod never talks to the Kubernetes API at all,
automountServiceAccountToken: false — set on the Pod or its
ServiceAccount — stops a token from being mounted into it in
the first place, removing a credential the Pod has no use for.
A Pod sets runAsUser 1000 at the Pod level; one container overrides it with runAsUser 2000. Which UID does that container run as?Answer it yourself first, then open this.
2000 — a container-level securityContext field overrides the same field set at the Pod level.
Extending Kubernetes with CRDs and Operators
- Register a CustomResourceDefinition and create instances of the custom resource it defines.
- Explain what an Operator adds on top of a plain CRD.
A CustomResourceDefinition (CRD) registers a brand-new
kind of object with the Kubernetes API, under
apiextensions.k8s.io/v1 — the older v1beta1 version
stopped being served as of Kubernetes v1.22, with v1
available since v1.16. Once a CRD is registered, instances of
that kind — custom resources — can be created, read,
updated and deleted with kubectl exactly like any built-in
object, validated against the schema the CRD declares, and
stored in etcd the same way.
On its own, that's all a CRD does: define a schema and a place to store structured data. Nothing watches it, and nothing acts on it — creating a custom resource with no controller behind its CRD just stores data, with no operational effect whatsoever.
bash
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: backupschedules.example.com
spec:
group: example.com
scope: Namespaced
names:
plural: backupschedules
singular: backupschedule
kind: BackupSchedule
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
schedule:
type: stringAn Operator is a custom controller that watches instances
of a CRD and reconciles real state to match what they
declare — a database operator, for example, watching
BackupSchedule objects and actually creating the Jobs,
volumes or external API calls needed to make backups happen
on that schedule. The CRD defines what — the shape of the
data. The operator's controller defines what to do about
it. A CRD without a controller is inert data; the operator
is what turns a custom resource into something that actually
does something in the cluster.
A CRD has no controller watching it. You create an instance of its custom resource. Does anything happen operationally?Answer it yourself first, then open this.
No — it's just stored. A CRD with no controller behind it has no operational effect; creating an instance only writes data.
Sources
- Kubernetes Documentation — ConfigMaps
- Kubernetes Documentation — Secrets
- Kubernetes Documentation — Pod Quality of Service Classes
- Kubernetes Documentation — Resource Quotas
- Kubernetes Documentation — Controlling Access to the Kubernetes API
- Kubernetes Documentation — Configure a Security Context for a Pod or Container
- Kubernetes Documentation — Extend the Kubernetes API with CustomResourceDefinitions
- Kubernetes Documentation — Operator Pattern