TT Lab
Get started
Learn Learning paths Courses

CKS — Kubernetes Security Specialist

Designing an Audit Policy

Continue in TT Lab

Goal

You build an audit.k8s.io/v1 audit policy file one rule at a time, checking for yourself what rule order and level choice keep and what they throw away.

Why it matters

The first question of incident response is always "when, who, and what was done," and in Kubernetes the only data that can answer it is the API server audit log. If you record everything, costs explode, and if you record sloppily, there is nothing when you actually need it. So an audit policy is a document that decides not "what to record" but "what to throw away."

You experience the two most common mistakes yourself in this lab. First, rules are evaluated from the top and only the first match is applied, so an exclusion rule (level: None) has no effect if it is lower down. Second, if you apply RequestResponse to Secrets, the secret values go as they are into the audit log file. Audit log collection systems usually have broader access permissions than the application, so it ends up spreading what you meant to protect.

In this environment, you can't actually turn on the audit log (you can't reattach a policy file to the kwok control plane). Grading looks only at the contents and order of the policy file. What the CKS exam grades is, in the end, this file too. Runtime investigation with Falco rules and crictl is covered in this module's reading and quiz.

Steps

  1. Create /root/cks-audit-runtime/audit-policy.yaml. It has apiVersion: audit.k8s.io/v1 and kind: Policy, and the very last rule in rules is a catch-all rule with no conditions and level: Metadata.
  2. Put omitStages at the top level of the same file and include RequestReceived.
  3. Add a rule to rules that records Secrets and ConfigMaps at level: Metadata. It targets secrets and configmaps in the core group. No rule in the file may specify Request or RequestResponse for secrets.
  4. At the very top of rules, put a rule that excludes get requests for secrets in the kube-system namespace with level: None. This rule must be positioned before the rule made in step 3.
  5. Add a rule to rules that records the verbs escalate, bind, and impersonate on RBAC resources (roles, rolebindings, clusterroles, and clusterrolebindings in the rbac.authorization.k8s.io group) at level: RequestResponse.
  6. Add a rule to rules that records create, update, patch, and delete on pods in the core group at level: Request.
  7. In /root/cks-audit-runtime/apiserver-audit-flags.txt, write the flags to attach to the API server, one per line. The five are --audit-policy-file=/etc/kubernetes/audit-policy.yaml, --audit-log-path=/var/log/kubernetes/audit.log, --audit-log-maxage=30, --audit-log-maxbackup=10, and --audit-log-maxsize=100.

Notes

The audit policy skeleton and the catch-all rule

Create /root/cks-audit-runtime/audit-policy.yaml. It has apiVersion: audit.k8s.io/v1 and kind: Policy, and the very last rule in rules is a catch-all rule with no conditions and level: Metadata.

The policy is a Policy resource of audit.k8s.io/v1. A catch-all rule to take requests that match nothing must be at the very bottom.

Remove the noisy stage

Put omitStages at the top level of the same file and include RequestReceived.

A single request produces events at several stages. The event at the moment the request is received is mostly useless. If you specify it as a top-level field, it applies to everything.

Secrets only up to metadata

Add a rule to rules that records Secrets and ConfigMaps at level: Metadata. It targets secrets and configmaps in the core group. No rule in the file may specify Request or RequestResponse for secrets.

If you apply a level of Request or above to Secrets, the secret values go as they are into the audit log file. No rule may specify Request or above for secrets.

Exclude kube-system noise

At the very top of rules, put a rule that excludes get requests for secrets in the kube-system namespace with level: None. This rule must be positioned before the rule made in step 3.

Rules are evaluated from the top and only the first match is applied. If the exclusion rule is lower down, the upper rule catches it first.

Record every privilege escalation attempt

Add a rule to rules that records the verbs escalate, bind, and impersonate on RBAC resources (roles, rolebindings, clusterroles, and clusterrolebindings in the rbac.authorization.k8s.io group) at level: RequestResponse.

RBAC resources are in the rbac.authorization.k8s.io group, not the core group. List all three dangerous verbs in verbs.

Pod changes up to the request body

Add a rule to rules that records create, update, patch, and delete on pods in the core group at level: Request.

Leave out reads and pick only the mutating verbs. If you keep the request body, you can reconstruct which manifest was deployed after a compromise.

Putting it together: document the audit log backend flags

In /root/cks-audit-runtime/apiserver-audit-flags.txt, write the flags to attach to the API server, one per line. The five are --audit-policy-file=/etc/kubernetes/audit-policy.yaml, --audit-log-path=/var/log/kubernetes/audit.log, --audit-log-maxage=30, --audit-log-maxbackup=10, and --audit-log-maxsize=100.

You must write all three: the policy file location, the log output location, and the rotation policy. Without rotation settings the disk fills up, and when the disk fills up the API server stops.