CKS · Question #30
CKS Question #30: Real Exam Question with Answer & Explanation
Kubernetes Audit Logging - Exam Explanation Overall Goal Kubernetes audit logs record every request made to the API server - who did what, when, and what the response was. This is critical for security compliance, incident investigation, and regulatory auditing. The API server na
Question
- logs are stored at
/var/log/Kubernetes/logs.txt - log files are retained for 5 days
- at maximum, a number of 10 old audit log files are retained
/etc/Kubernetes/logpolicy/audit-policy.yaml to log:
- Nodes changes at
RequestResponselevel - The request body of
persistentvolumeschanges in the namespacefrontend ConfigMapandSecretchanges in all namespaces at theMetadatalevel
Metadata level. Don't forget to apply the modified policy.Explanation
Kubernetes Audit Logging - Exam Explanation
Overall Goal
Kubernetes audit logs record every request made to the API server - who did what, when, and what the response was. This is critical for security compliance, incident investigation, and regulatory auditing. The API server natively supports writing structured audit logs to disk (the "log backend"), but it's disabled by default. You must both configure the log backend flags and define a policy that controls what gets logged and at what verbosity.
Part 1: Enabling the Log Backend
You configure the API server by editing its static pod manifest, typically at /etc/kubernetes/manifests/kube-apiserver.yaml. Add these flags:
- --audit-log-path=/var/log/kubernetes/logs.txt
- --audit-log-maxage=5
- --audit-log-maxbackup=10
- --audit-policy-file=/etc/kubernetes/logpolicy/audit-policy.yaml
Why each flag matters:
| Flag | Purpose |
|---|---|
--audit-log-path | Activates the log backend; without this, no logs are written at all |
--audit-log-maxage=5 | Deletes log files older than 5 days (retention requirement) |
--audit-log-maxbackup=10 | Caps the number of rotated old log files at 10 |
--audit-policy-file | Points the API server to your policy; without this, audit logging falls back to a default (often nothing useful) |
What goes wrong if skipped: Omitting --audit-log-path means the other flags are silently ignored - the backend simply doesn't activate. Omitting --audit-policy-file means you have no policy, so nothing gets logged even if the backend is on.
Important: Since
kube-apiserveris a static pod, kubelet will automatically restart it when the manifest changes. Watch/var/log/pods/if the API server fails to come back up - a bad policy file or missing volume mount is a common cause.
Part 2: Writing the Audit Policy
The policy file is a list of rules evaluated top-to-bottom; first match wins. Order is critical.
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# Rule 1: Nodes at RequestResponse
- level: RequestResponse
resources:
- group: ""
resources: ["nodes"]
# Rule 2: persistentvolumes changes in namespace 'frontend' - request body only
- level: Request
resources:
- group: ""
resources: ["persistentvolumes"]
namespaces: ["frontend"]
# Rule 3: ConfigMap and Secret in all namespaces at Metadata
- level: Metadata
resources:
- group: ""
resources: ["configmaps", "secrets"]
# Rule 4: Catch-all
- level: Metadata
resources:
- group: "*"
resources: ["*"]
The four audit levels, from least to most verbose:
| Level | What it captures |
|---|---|
None | Drop the event entirely |
Metadata | Who, what resource, when - no body |
Request | Metadata + the request body |
RequestResponse | Request + the response body |
Why each rule is correct:
-
Nodes at
RequestResponse- You need the full picture (what was sent AND what the API server responded), useful for auditing infrastructure changes like node taints or labels. -
persistentvolumesinfrontendatRequest- The question asks for "the request body", which is exactly theRequestlevel. UsingRequestResponsewould over-capture;Metadatawould under-capture. Scoping to thefrontendnamespace focuses the noise. -
ConfigMap and Secret at
Metadata- These contain sensitive data. Logging bodies (Request/RequestResponse) would expose secrets in the audit log itself - a security anti-pattern.Metadatagives you accountability without leaking values. No namespace filter means all namespaces. -
Catch-all at
Metadata- Without this, unmatched requests fall through with no logging. A catch-all ensures completeness for compliance.
What goes wrong if order is reversed: If the catch-all appeared first, every request would match it at Metadata and the more specific rules below would never fire. The configmaps/secrets rule would never reach Metadata (same level, so no harm there), but the nodes rule would never reach RequestResponse. Always put most specific rules first.
Part 3: Applying the Policy
The policy is applied by the --audit-policy-file flag you already set. There's no kubectl apply step - the API server reads it directly from disk. However, you must ensure the file path is mounted into the API server pod via a hostPath volume in the static pod manifest:
volumeMounts:
- mountPath: /etc/kubernetes/logpolicy
name: audit-policy
volumes:
- name: audit-policy
hostPath:
path: /etc/kubernetes/logpolicy
type: DirectoryOrCreate
Likewise, the log output directory needs a mount:
volumeMounts:
- mountPath: /var/log/kubernetes
name: audit-logs
volumes:
- name: audit-logs
hostPath:
path: /var/log/kubernetes
type: DirectoryOrCreate
What goes wrong if skipped: The API server pod can't read the policy file (it sees its own filesystem, not the host's), so it will crash with a startup error. This is the most common mistake on this exam task.
Memory Tip
Think of it as "PFV" - Policy file, Flags on the API server, Volumes mounted. In that order: write the policy first (so you know what you're pointing at), add the flags, verify the volume mounts. If the API server doesn't restart cleanly, check the volume mounts first - that's where 80% of failures hide.
Topics
Community Discussion
No community discussion yet for this question.