Kubernetes Audit Logs
Overview
Kubernetes is an open-source container orchestration system for automating software deployment, scaling and managment.
In this documentation, you will learn how to configure, collect and send Kubernetes Audit logs to SEKOIA.IO.
- Supported environment: On Premise / SaaS
Configuration of Kubernetes
Enable the audit logs in kubernetes:
- Audit logs are disabled by default. To enable them, you need to specify an audit file path in your API server configuration :
kube-apiserver
[...]
--audit-log-path=/var/log/kubernetes/apiserver/audit.log
--audit-policy-file=/etc/kubernetes/audit-policies/policy.yaml
-
Create the policy file at /etc/kubernetes/audit-policies/policy.yaml to specify the types of API requests you want to log in your audit logs file. The kubernetes audit policy has different levels:
None
- don't log events that match this rule.Metadata
- log events with metadata (requesting user, timestamp, resource, verb, etc.) but not request or response body.Request
- log events with request metadata and body but not response body. This does not apply for non-resource requests.RequestResponse
- log events with request metadata, request body and response body. This does not apply for non-resource requests.
-
You can use this minimal audit policy file to log all requests at the
Metadata
level:
# Log all requests at the Metadata level.
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata
For more information about Kubernetes audit logs, please visit kubernetes website.
Collect Configuration
- Enable the log collection in your DaemonSet, there are disabled by default:
env:
# (...)
- name: DD_LOGS_ENABLED
value: 'true'
- Mount the audit log directory in a path where the Sekoia Agent collect the log file. For that you need to update your daemonset:
# (...)
volumeMounts:
# (...)
- name: auditdir
mountPath: /var/log/kubernetes/apiserver
# (...)
volumes:
# (...)
- hostPath:
path: /var/log/kubernetes/apiserver
name: auditdir
# (...)
Create the intake
-
Go to the intake page and create a new intake from the format
Kubernetes
. -
Update the Agent configuration:
logfiles:
- filepath: /var/log/kubernetes/apiserver/audit.log # Path to the file to watch
intakekey: {intake key} # Intake key to use to send the events
- Once the configuration file is modified, restart the agent:Once the configuration file is modified, restart the agent.
Raw Events Samples
In this section, you will find examples of raw logs as generated natively by the source. These examples are provided to help integrators understand the data format before ingestion into Sekoia.io. It is crucial for setting up the correct parsing stages and ensuring that all relevant information is captured.
{
"level": "RequestResponse",
"auditID": "91afc40c-f1ef-4956-b85a-7e12d09511e9",
"stage": "ResponseComplete",
"requestURI": "/api/v1/namespaces/test/pods/test-1669140000-zp58r/exec?command=sh&container=test&stdin=true&stdout=true&tty=true",
"verb": "create",
"user": {
"username": "user@mail.com",
"groups": [
"system:authenticated"
]
},
"sourceIPs": [
"192.168.0.1"
],
"userAgent": "kubectl/v1.24.2 (linux/amd64) kubernetes/f66044f",
"objectRef": {
"resource": "pods",
"namespace": "test",
"name": "test-1669140000-zp58r",
"apiVersion": "v1",
"subresource": "exec"
},
"responseStatus": {
"metadata": {},
"code": 101
},
"requestReceivedTimestamp": "2022-11-23T14:36:45.243457Z",
"stageTimestamp": "2022-11-23T14:36:53.531481Z",
"annotations": {
"authorization.k8s.io/decision": "allow",
"authorization.k8s.io/reason": "RBAC: allowed by ClusterRoleBinding test-role-binding of ClusterRole test-admin to Group system:authenticated"
}
}
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "Request",
"auditID": "bdeb089c-5d70-4776-b6af-88e739fb0dd5",
"stage": "ResponseComplete",
"requestURI": "/api/v1/namespaces/support/pods?limit=500",
"verb": "list",
"user": {
"username": "system:serviceaccount:pinniped-concierge:pinniped-concierge-impersonation-proxy",
"uid": "6258bd11-9713-442b-bbed-2587a76975d9",
"groups": [
"system:serviceaccounts",
"system:serviceaccounts:pinniped-concierge",
"system:authenticated"
],
"extra": {
"authentication.kubernetes.io/credential-id": [
"JTI=581d10f3-b521-480f-aa42-bcd6a70df8ea"
]
}
},
"impersonatedUser": {
"username": "john.doe@example.org",
"groups": [
"admin",
"system:authenticated"
]
},
"sourceIPs": [
"1.1.1.1",
"2.2.2.2"
],
"userAgent": "kubectl/v1.29.2 (linux/amd64) kubernetes/4b8e819",
"objectRef": {
"resource": "pods",
"namespace": "support",
"apiVersion": "v1"
},
"responseStatus": {
"metadata": {},
"code": 200
},
"requestReceivedTimestamp": "2025-01-23T14:56:02.374424Z",
"stageTimestamp": "2025-01-23T14:56:02.400865Z",
"annotations": {
"authorization.k8s.io/decision": "allow",
"authorization.k8s.io/reason": "RBAC: allowed by ClusterRoleBinding \"pinniped-admin-role-binding\" of ClusterRole \"cluster-admin\" to Group \"admin\""
}
}
{
"level": "RequestResponse",
"auditID": "bbd6d83f-4b6d-4a3d-b3cd-840a0691c19f",
"stage": "ResponseComplete",
"requestURI": "/apis/apps/v1/namespaces/test/deployments/test/scale",
"verb": "patch",
"user": {
"username": "user@mail.com",
"groups": [
"system:authenticated"
]
},
"sourceIPs": [
"192.168.0.1"
],
"userAgent": "kubectl/v1.20.2 (linux/amd64) kubernetes/faecb19",
"objectRef": {
"resource": "deployments",
"namespace": "test",
"apiGroup": "apps",
"apiVersion": "v1",
"subresource": "scale"
},
"responseStatus": {
"metadata": {},
"code": 200
},
"requestObject": {
"spec": {
"replicas": 3
}
},
"responseObject": {
"kind": "Scale",
"apiVersion": "autoscaling/v1",
"metadata": {
"name": "test",
"namespace": "test",
"selfLink": "/apis/apps/v1/namespaces/test/deployments/test/scale",
"uid": "7e649fbd-ca1b-4e30-b763-1b52527c774b",
"resourceVersion": "1368503426",
"creationTimestamp": "2020-01-24T17:04:30Z"
},
"spec": {
"replicas": 3
},
"status": {
"replicas": 2,
"selector": "test=test"
}
},
"requestReceivedTimestamp": "2022-11-23T13:10:04.499444Z",
"stageTimestamp": "2022-11-23T13:10:04.514995Z",
"annotations": {
"authorization.k8s.io/decision": "allow",
"authorization.k8s.io/reason": "RBAC: allowed by ClusterRoleBinding \"test-role-binding\" of ClusterRole \"test-admin\" to Group \"system:authenticated\""
}
}
Event Categories
The following table lists the data source offered by this integration.
Data Source | Description |
---|---|
Application logs |
Audit logs of Kubernetes clusters |
Transformed Events Samples after Ingestion
This section demonstrates how the raw logs will be transformed by our parsers. It shows the extracted fields that will be available for use in the built-in detection rules and hunting activities in the events page. Understanding these transformations is essential for analysts to create effective detection mechanisms with custom detection rules and to leverage the full potential of the collected data.
{
"message": "{\"level\": \"RequestResponse\",\"auditID\": \"91afc40c-f1ef-4956-b85a-7e12d09511e9\",\"stage\": \"ResponseComplete\",\"requestURI\":\"/api/v1/namespaces/test/pods/test-1669140000-zp58r/exec?command=sh&container=test&stdin=true&stdout=true&tty=true\",\"verb\": \"create\",\"user\": {\"username\": \"user@mail.com\",\"groups\": [\"system:authenticated\"]},\"sourceIPs\": [\"192.168.0.1\"],\"userAgent\": \"kubectl/v1.24.2 (linux/amd64) kubernetes/f66044f\",\"objectRef\": {\"resource\": \"pods\",\"namespace\": \"test\",\"name\": \"test-1669140000-zp58r\",\"apiVersion\": \"v1\",\"subresource\": \"exec\"},\"responseStatus\": {\"metadata\": {},\"code\": 101},\"requestReceivedTimestamp\": \"2022-11-23T14:36:45.243457Z\",\"stageTimestamp\": \"2022-11-23T14:36:53.531481Z\",\"annotations\": {\"authorization.k8s.io/decision\": \"allow\",\"authorization.k8s.io/reason\": \"RBAC: allowed by ClusterRoleBinding test-role-binding of ClusterRole test-admin to Group system:authenticated\"}}",
"event": {
"action": "create",
"code": "91afc40c-f1ef-4956-b85a-7e12d09511e9",
"outcome": "allow",
"start": "2022-11-23T14:36:45.243457Z"
},
"action": {
"outcome": "allow"
},
"http": {
"response": {
"status_code": 101
}
},
"kubernetes": {
"namespace": "test",
"object": {
"name": "test-1669140000-zp58r"
},
"rbacreason": "RBAC: allowed by ClusterRoleBinding test-role-binding of ClusterRole test-admin to Group system:authenticated",
"resource": "pods",
"subresource": "exec"
},
"related": {
"ip": [
"192.168.0.1"
],
"user": [
"user@mail.com"
]
},
"source": {
"address": "192.168.0.1",
"ip": "192.168.0.1"
},
"url": {
"path": "/api/v1/namespaces/test/pods/test-1669140000-zp58r/exec?command=sh&container=test&stdin=true&stdout=true&tty=true"
},
"user": {
"name": "user@mail.com",
"roles": [
"system:authenticated"
]
},
"user_agent": {
"device": {
"name": "Other"
},
"name": "Other",
"original": "kubectl/v1.24.2 (linux/amd64) kubernetes/f66044f",
"os": {
"name": "Linux"
}
}
}
{
"message": "{\"kind\":\"Event\",\"apiVersion\":\"audit.k8s.io/v1\",\"level\":\"Request\",\"auditID\":\"bdeb089c-5d70-4776-b6af-88e739fb0dd5\",\"stage\":\"ResponseComplete\",\"requestURI\":\"/api/v1/namespaces/support/pods?limit=500\",\"verb\":\"list\",\"user\":{\"username\":\"system:serviceaccount:pinniped-concierge:pinniped-concierge-impersonation-proxy\",\"uid\":\"6258bd11-9713-442b-bbed-2587a76975d9\",\"groups\":[\"system:serviceaccounts\",\"system:serviceaccounts:pinniped-concierge\",\"system:authenticated\"],\"extra\":{\"authentication.kubernetes.io/credential-id\":[\"JTI=581d10f3-b521-480f-aa42-bcd6a70df8ea\"]}},\"impersonatedUser\":{\"username\":\"john.doe@example.org\",\"groups\":[\"admin\",\"system:authenticated\"]},\"sourceIPs\":[\"1.1.1.1\",\"2.2.2.2\"],\"userAgent\":\"kubectl/v1.29.2 (linux/amd64) kubernetes/4b8e819\",\"objectRef\":{\"resource\":\"pods\",\"namespace\":\"support\",\"apiVersion\":\"v1\"},\"responseStatus\":{\"metadata\":{},\"code\":200},\"requestReceivedTimestamp\":\"2025-01-23T14:56:02.374424Z\",\"stageTimestamp\":\"2025-01-23T14:56:02.400865Z\",\"annotations\":{\"authorization.k8s.io/decision\":\"allow\",\"authorization.k8s.io/reason\":\"RBAC: allowed by ClusterRoleBinding \\\"pinniped-admin-role-binding\\\" of ClusterRole \\\"cluster-admin\\\" to Group \\\"admin\\\"\"}}\n",
"event": {
"action": "list",
"code": "bdeb089c-5d70-4776-b6af-88e739fb0dd5",
"outcome": "allow",
"start": "2025-01-23T14:56:02.374424Z"
},
"action": {
"outcome": "allow"
},
"http": {
"response": {
"status_code": 200
}
},
"kubernetes": {
"namespace": "support",
"rbacreason": "RBAC: allowed by ClusterRoleBinding \"pinniped-admin-role-binding\" of ClusterRole \"cluster-admin\" to Group \"admin\"",
"resource": "pods"
},
"related": {
"ip": [
"1.1.1.1"
],
"user": [
"john.doe@example.org"
]
},
"source": {
"address": "1.1.1.1",
"ip": "1.1.1.1"
},
"url": {
"path": "/api/v1/namespaces/support/pods?limit=500"
},
"user": {
"id": "6258bd11-9713-442b-bbed-2587a76975d9",
"name": "john.doe@example.org",
"roles": [
"admin",
"system:authenticated"
]
},
"user_agent": {
"device": {
"name": "Other"
},
"name": "Other",
"original": "kubectl/v1.29.2 (linux/amd64) kubernetes/4b8e819",
"os": {
"name": "Linux"
}
}
}
{
"message": "{\"level\":\"RequestResponse\",\"auditID\":\"bbd6d83f-4b6d-4a3d-b3cd-840a0691c19f\",\"stage\":\"ResponseComplete\",\"requestURI\":\"/apis/apps/v1/namespaces/test/deployments/test/scale\",\"verb\":\"patch\",\"user\":{\"username\":\"user@mail.com\",\"groups\":[\"system:authenticated\"]},\"sourceIPs\":[\"192.168.0.1\"],\"userAgent\":\"kubectl/v1.20.2 (linux/amd64) kubernetes/faecb19\",\"objectRef\":{\"resource\":\"deployments\",\"namespace\":\"test\",\"apiGroup\":\"apps\",\"apiVersion\":\"v1\",\"subresource\":\"scale\"},\"responseStatus\":{\"metadata\":{},\"code\":200},\"requestObject\":{\"spec\":{\"replicas\":3}},\"responseObject\":{\"kind\":\"Scale\",\"apiVersion\":\"autoscaling/v1\",\"metadata\":{\"name\":\"test\",\"namespace\":\"test\",\"selfLink\":\"/apis/apps/v1/namespaces/test/deployments/test/scale\",\"uid\":\"7e649fbd-ca1b-4e30-b763-1b52527c774b\",\"resourceVersion\":\"1368503426\",\"creationTimestamp\":\"2020-01-24T17:04:30Z\"},\"spec\":{\"replicas\":3},\"status\":{\"replicas\":2,\"selector\":\"test=test\"}},\"requestReceivedTimestamp\":\"2022-11-23T13:10:04.499444Z\",\"stageTimestamp\":\"2022-11-23T13:10:04.514995Z\",\"annotations\":{\"authorization.k8s.io/decision\":\"allow\",\"authorization.k8s.io/reason\":\"RBAC: allowed by ClusterRoleBinding \\\"test-role-binding\\\" of ClusterRole \\\"test-admin\\\" to Group \\\"system:authenticated\\\"\"}}",
"event": {
"action": "patch",
"code": "bbd6d83f-4b6d-4a3d-b3cd-840a0691c19f",
"outcome": "allow",
"start": "2022-11-23T13:10:04.499444Z"
},
"action": {
"outcome": "allow"
},
"http": {
"response": {
"status_code": 200
}
},
"kubernetes": {
"namespace": "test",
"object": {
"name": "test"
},
"rbacreason": "RBAC: allowed by ClusterRoleBinding \"test-role-binding\" of ClusterRole \"test-admin\" to Group \"system:authenticated\"",
"resource": "deployments",
"subresource": "scale"
},
"related": {
"ip": [
"192.168.0.1"
],
"user": [
"user@mail.com"
]
},
"source": {
"address": "192.168.0.1",
"ip": "192.168.0.1"
},
"url": {
"path": "/apis/apps/v1/namespaces/test/deployments/test/scale"
},
"user": {
"name": "user@mail.com",
"roles": [
"system:authenticated"
]
},
"user_agent": {
"device": {
"name": "Other"
},
"name": "Other",
"original": "kubectl/v1.20.2 (linux/amd64) kubernetes/faecb19",
"os": {
"name": "Linux"
}
}
}
Extracted Fields
The following table lists the fields that are extracted, normalized under the ECS format, analyzed and indexed by the parser. It should be noted that infered fields are not listed.
Name | Type | Description |
---|---|---|
event.action |
keyword |
The action captured by the event. |
event.code |
keyword |
Identification code for this event. |
event.start |
date |
event.start contains the date when the event started or when the activity was first observed. |
http.response.status_code |
long |
HTTP response status code. |
kubernetes.namespace |
keyword |
kubernetes.namespace |
kubernetes.object.name |
keyword |
kubernetes.object.name |
kubernetes.rbacreason |
keyword |
kubernetes.rbacreason |
kubernetes.resource |
keyword |
kubernetes.resource |
kubernetes.subresource |
keyword |
kubernetes.subresource |
source.ip |
ip |
IP address of the source. |
url.path |
wildcard |
Path of the request, such as "/search". |
user.id |
keyword |
Unique identifier of the user. |
user.name |
keyword |
Short name or login of the user. |
user.roles |
keyword |
Array of user roles at the time of the event. |
user_agent.original |
keyword |
Unparsed user_agent string. |
For more information on the Intake Format, please find the code of the Parser, Smart Descriptions, and Supported Events here.
Support
If you need assistance with this integration, please contact our support team at support.sekoia.io.