EKS audit logs, when analyzed correctly, can reveal subtle but critical security threats by showing you the exact API calls made within your cluster, letting you spot anomalies that standard security tools might miss.
Let’s watch this in action. Imagine a scenario where an attacker gains access to a service account with broad permissions. They might try to escalate their privileges or exfiltrate data. Here’s how audit logs would show that:
First, we need to ensure audit logging is enabled in EKS. This is done at the cluster creation or update stage. If it’s not, you’ll see no audit logs. Assuming it’s enabled, logs are sent to CloudWatch Logs.
Let’s say we’re looking for unauthorized pod creation. An attacker might try to deploy a malicious pod to gain a foothold. We’d be searching for POST requests to /api/v1/namespaces/*/pods.
Here’s a snippet of what a suspicious log entry might look like in CloudWatch Logs:
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "metadata",
"auditID": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
"stage": "RequestReceived",
"requestSchema": "v1",
"requestURI": "/api/v1/namespaces/default/pods",
"verb": "POST",
"user": {
"username": "system:serviceaccount:default:my-compromised-sa",
"uid": "f1e2d3c4-b5a6-7890-1234-567890fedcba",
"groups": [
"system:serviceaccounts",
"system:serviceaccounts:default",
"system:authenticated"
]
},
"sourceIPs": [
"10.0.1.25"
],
"userAgent": "kubectl/v1.28.1 (linux/amd64) kubernetes/f82e97f",
"objectRef": {
"resource": "pods",
"namespace": "default",
"name": "malicious-shell"
},
"responseStatus": {
"metadata": {},
"code": 201
},
"requestObject": {
"kind": "Pod",
"apiVersion": "v1",
// ... full pod spec ...
},
"requestTimestamp": "2023-10-27T10:30:00Z",
"durationSeconds": 0.05,
"annotations": {
"authentication.kubernetes.io/pod": "kube-system/kube-apiserver-ip-10-0-1-10.ec2.internal",
"authorization.kubernetes.io/decision": "allow",
"authorization.kubernetes.io/grantedPermissions": "create,pods,default"
}
}
The key elements here are:
verb: "POST": An attempt to create a resource.requestURI: "/api/v1/namespaces/default/pods": Specifically targeting pod creation in thedefaultnamespace.user.username: "system:serviceaccount:default:my-compromised-sa": The identity making the request. If this is an unexpected service account, especially one with broad permissions, it’s a red flag.objectRef.name: "malicious-shell": The name of the object being created. A suspicious name is another indicator.annotations.authorization.kubernetes.io/grantedPermissions: "create,pods,default": Confirms the authorization for this action.
To build a mental model, think of the audit log as a flight recorder for your Kubernetes API server. Every interaction, from a kubectl get pods command to a controller creating a Deployment, is logged. The stage field tells you where in the request lifecycle the log was generated (e.g., RequestReceived, ResponseStarted, ResponseComplete). The user field is crucial for identifying who performed the action, and sourceIPs shows where it originated.
A powerful technique is to set up CloudWatch Metric Filters based on these logs. For instance, you could create a filter that counts events where user.username is NOT system:kube-controller-manager, system:kube-scheduler, or known administrative users, and verb is POST or PUT on critical resources like pods or secrets. This filter could then trigger an SNS notification or an alarming metric.
The most surprising thing most people don’t realize is that audit logs capture all API interactions, not just those that result in a success or failure. This means you can analyze the intent behind actions, even if they were ultimately blocked by authorization policies. For example, an attacker might repeatedly try to list secrets in a namespace they shouldn’t have access to. While these attempts would be denied, the audit logs will show a pattern of probing and reconnaissance that is highly suspicious.
The next logical step is to correlate these API activities with network flow logs to understand what resources these suspicious pods or API calls are interacting with.