This document explains how to interact with the operator. You should have the operator deployed first: to use a local development build please read the DEVELOPMENT document for instructions, otherwise you can fetch the operator from the official docker registry.
Either way, you need to have cert-manager
installed for
secure TLS connections:
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml
To install the operator from the online docker registry, first make
sure your system is supported by reading the
Suppoted Environments
section in the official README, then
simply run:
kubectl apply -f https://raw.githubusercontent.com/San7o/kivebpf/refs/heads/main/dist/install-remote.yaml
Once you have the operator deployed, you can instruct It to log
accesses to files via KivePolicies. An
KivePolicy
is a custom kubernetes resource that contains
information about which file[s] to trace and in which pods. The operator
will parse this policy every time one is added / removed / updated and
It will configure the eBPF program to monitor the right files.
An example KivePolicy
is located in config/samples/kive_v2alpha1_kivepolicy.yaml.
More examples can be found in the same directory. Check out the
reference for APIv1.
apiVersion: kivebpf.san7o.github.io/v1
kind: KivePolicy
metadata:
labels:
app.kubernetes.io/name: kivebpf
finalizers:
- kivepolicy.kivebpf.san7o.github.io/finalizer
name: kive-sample-policy
namespace: kivebpf-system
spec:
alertVersion: v1
traps:
- path: /secret.txt
create: true
mode: 444
matchAny:
- pod: nginx-pod
namespace: default
matchLabels:
security-level: high
metadata:
severity: medium
This sample policy will trace the file /secret.txt
in
the pods with name nginx-pod
in the namespace
default
and with the label
security-level=high
. If the file did not exist in the pod,
It will create It with mode
permissions since
create
is set to true.
You can load it to the kubernetes cluster using the apply command of kubectl:
kubectl apply -f config/samples/kive_v2alpha1_kivepolicy.yaml
The operator will log some information when a policy is created / deleted / updated.
It it now time to test this policy. First, we need to create a pod
that matches the match
fields in the
KivePolicy
. This repository provides an nginx pod in hack/k8s-manifests/sample-nginx-pod.yaml
with the right characteristics, you can load it with kubectl:
kubectl apply -f hack/k8s-manifests/sample-nginx-pod.yaml
After the pod has started, you can try to access the
/secret.txt
file by executing a command inside it:
sudo kubectl exec -it nginx-pod -- cat /secret.txt
You should expect to see some logging information on the standard output of one of the kive pods, like this (prettified):
2025-08-02T16:51:19Z INFO Access Detected
{
"KiveAlert": {
"kive-alert-version": "v1",
"kive-policy-name": "kive-sample-policy",
"timestamp": "2025-08-02T16:51:19Z",
"metadata": {
"path": "/secret.txt",
"inode": 16256084,
"mask": 36,
"kernel-id": "2c147a95-23e5-4f99-a2de-67d5e9fdb502"
},
"pod": {
"name": "nginx-pod",
"namespace": "default",
"container": {
"id": "containerd://0c37512624823392d71e99a12011148db30ba7ea2a74fc7ff8bd5f85bc7b499c",
"name": "nginx"
}
},
"node": {
"name": "kive-worker"
},
"process": {
"pid": 176928,
"tgid": 176928,
"uid": 0,
"gid": 0,
"binary": "cat",
"cwd": ""
}
}
}
Note that only the leader pod in the kernel where the file resides will output the information, so you may need to check the standard output of all the kive pods. This happens because the data is logged in the same node where the eBPF program noticed the access (to understand how the operator works under the hood, read the DESIGN document), we will later see how you can easily gather all the logs in a single place using callbacks.
You may have seen a message like this just above the alert:
Could not read /host/proc/176917/cwd while generating an KiveAlert, this can happen if the process terminated too quickly for the operator to react or the node is running in a container and procfs is not mounted in /host/real/proc
If you setup the cluster correctly, the problem here is that the
cat
process died before the operator could read the
information associated with the process. Those missing informations will
simply be empty values in the output and do not cause the operator to
break. Try to keep the process alive and see that the warning does not
appear and you get additional information such as the current working
directory (cwd) and the arguments to the binary:
sudo kubectl exec -it nginx-pod -- cat /secret.txt -
Support for getting the process information is in the work.
You can ask the operator to use send data to an endpoint by setting
the callback
filed in a trap like this:
apiVersion: kivebpf.san7o.github.io/v1
kind: KivePolicy
metadata:
labels:
app.kubernetes.io/name: kivebpf
finalizers:
- kivepolicy.kivebpf.san7o.github.io/finalizer
name: kive-sample-policy
namespace: kivebpf-system
spec:
alertVersion: v1
traps:
- path: /secret.txt
create: true
mode: 444
callback: "http://callback-service.kivebpf-system.svc.cluster.local:9376/ingest" # HERE
matchAny:
- pod: nginx-pod
namespace: default
matchLabels:
security-level: high
If a callback is set on a trap, then the operator will make an HTTP
POST request to that endpoint with the KiveAlert
as json
data and will stop logging to the standard output.