Skip to content

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

  1. Go to the intake page and create a new intake from the format Kubernetes.

  2. 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
  1. 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.