Kubernetes audit logs are the control-plane telemetry for container orchestration — they record every API call to the kube-apiserver. In a Kubernetes environment, the API server is the single chokepoint for all cluster operations, making it the highest-value telemetry source.
Kubernetes Audit Log Structure
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "RequestResponse",
"auditID": "3da92f8d-8f31-4497-b6c2-54ff16948f7a",
"stage": "ResponseComplete",
"requestURI": "/api/v1/namespaces/production/pods/webapi-7d9b8c-xk2np/exec",
"verb": "create",
"user": {
"username": "attacker@victim.com",
"uid": "12345678-abcd-...",
"groups": ["system:authenticated"],
"extra": {}
},
"impersonatedUser": null,
"sourceIPs": ["203.0.113.55"],
"userAgent": "kubectl/v1.28.0 (linux/amd64) kubernetes/abc123",
"objectRef": {
"resource": "pods",
"namespace": "production",
"name": "webapi-7d9b8c-xk2np",
"apiVersion": "v1",
"subresource": "exec"
},
"responseStatus": {
"code": 101
},
"requestObject": {
"stdin": true,
"stdout": true,
"tty": true,
"container": "webapi",
"command": ["/bin/bash"]
},
"timestamp": "2024-03-15T09:23:14.882Z"
}
Key fields for detection
| Field | Detection use |
|---|---|
verb | What type of operation — exec, create, delete |
user.username | Who made the request |
user.groups | Group membership (system:masters = cluster-admin) |
sourceIPs | Where the request came from |
objectRef.resource | What type of resource (pods, secrets, configmaps) |
objectRef.namespace | Which namespace |
objectRef.name | Which specific resource |
objectRef.subresource | exec, log, portforward — high-interest operations |
responseStatus.code | 200/201=success, 401=unauth, 403=denied, 404=not found |
requestObject | What was requested (command in exec, spec in create) |
High-Priority Detection Patterns
1. Interactive Shell Execution (exec)
{
"verb": "create",
"objectRef": {"resource": "pods", "subresource": "exec"},
"requestObject": {"command": ["/bin/bash"], "tty": true}
}
kubectl exec -it <pod> -- /bin/bash generates this. In production, there is almost no legitimate reason to exec an interactive shell into a running pod — operations should be automated, not interactive. This is a critical alert.
2. Secret Access
{
"verb": "get",
"objectRef": {"resource": "secrets", "namespace": "production", "name": "aws-credentials"},
"user": {"username": "system:serviceaccount:default:compromised-sa"}
}
A service account in the default namespace reading a secret named aws-credentials in the production namespace — cross-namespace secret access is unusual and warrants investigation.
3. ClusterRoleBinding Creation (Privilege Escalation)
{
"verb": "create",
"objectRef": {"resource": "clusterrolebindings"},
"requestObject": {
"metadata": {"name": "backdoor-admin"},
"roleRef": {"name": "cluster-admin"},
"subjects": [{"kind": "User", "name": "attacker@victim.com"}]
}
}
Creating a ClusterRoleBinding that grants cluster-admin to an external user is the Kubernetes equivalent of adding someone to the Domain Admins group. Immediate alert.
Configuring an Audit Policy
Without a policy, Kubernetes logs nothing. A production-grade minimal policy:
# /etc/kubernetes/audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# Don't log reads to health endpoints
- level: None
nonResourceURLs: ["/healthz", "/readyz", "/livez"]
# Don't log kube-system service account activity (too noisy)
- level: None
userGroups: ["system:nodes"]
verbs: ["get", "list", "watch"]
# Log ALL exec and portforward at full detail
- level: RequestResponse
resources:
- group: ""
resources: ["pods/exec", "pods/portforward", "pods/log"]
# Log secret access metadata (not content)
- level: Metadata
resources:
- group: ""
resources: ["secrets", "configmaps"]
# Log all other writes
- level: Metadata
verbs: ["create", "update", "patch", "delete"]
# Don't log read-only operations on non-sensitive resources
- level: None
verbs: ["get", "list", "watch"]
Kubernetes Auditing— Kubernetes Docs
Falco Default Rules— CNCF Falco