Skip to content

feat: add k8s info in events with container id#194

Open
hanshal101 wants to merge 4 commits into
bombinisecurity:mainfrom
hanshal101:hanshal101/add-k8s-info
Open

feat: add k8s info in events with container id#194
hanshal101 wants to merge 4 commits into
bombinisecurity:mainfrom
hanshal101:hanshal101/add-k8s-info

Conversation

@hanshal101
Copy link
Copy Markdown

Description

Add Kubernetes pod information to process events
Enhanced process events with pod context by mapping container IDs to Kubernetes pod metadata (name, namespace, service account, node).

Details

The events looks something like this:

{
  "type": "ProcessExec",
  "process": {
    "start_time": "2026-01-27T13:26:44.733Z",
    "cloned": false,
    "pid": 264375,
    "tid": 264375,
    "ppid": 242089,
    "uid": 0,
    "euid": 0,
    "gid": 0,
    "egid": 0,
    "auid": 4294967295,
    "cap_inheritable": "",
    "cap_permitted": "CAP_CHOWN | CAP_DAC_OVERRIDE | CAP_FOWNER | CAP_FSETID | CAP_KILL | CAP_SETGID | CAP_SETUID | CAP_SETPCAP | CAP_NET_BIND_SERVICE | CAP_NET_RAW | CAP_SYS_CHROOT | CAP_MKNOD | CAP_AUDIT_WRITE | CAP_SETFCAP",
    "cap_effective": "CAP_CHOWN | CAP_DAC_OVERRIDE | CAP_FOWNER | CAP_FSETID | CAP_KILL | CAP_SETGID | CAP_SETUID | CAP_SETPCAP | CAP_NET_BIND_SERVICE | CAP_NET_RAW | CAP_SYS_CHROOT | CAP_MKNOD | CAP_AUDIT_WRITE | CAP_SETFCAP",
    "secureexec": "",
    "filename": "apk",
    "binary_path": "/sbin/apk",
    "args": "update",
    "container_id": "d370bc00d2adbf95b16374a5a2b0a5a359cd8a7190312a45bd4b776d923dd2d7",
    "pod": {
      "name": "alpine-critical",
      "namespace": "default",
      "service_account": "default",
      "node_name": "lol"
    }
  },
  "parent": {
    "start_time": "2026-01-27T12:40:13.370Z",
    "cloned": false,
    "pid": 242089,
    "tid": 242089,
    "ppid": 7227,
    "uid": 0,
    "euid": 0,
    "gid": 0,
    "egid": 0,
    "auid": 4294967295,
    "cap_inheritable": "",
    "cap_permitted": "CAP_CHOWN | CAP_DAC_OVERRIDE | CAP_FOWNER | CAP_FSETID | CAP_KILL | CAP_SETGID | CAP_SETUID | CAP_SETPCAP | CAP_NET_BIND_SERVICE | CAP_NET_RAW | CAP_SYS_CHROOT | CAP_MKNOD | CAP_AUDIT_WRITE | CAP_SETFCAP",
    "cap_effective": "CAP_CHOWN | CAP_DAC_OVERRIDE | CAP_FOWNER | CAP_FSETID | CAP_KILL | CAP_SETGID | CAP_SETUID | CAP_SETPCAP | CAP_NET_BIND_SERVICE | CAP_NET_RAW | CAP_SYS_CHROOT | CAP_MKNOD | CAP_AUDIT_WRITE | CAP_SETFCAP",
    "secureexec": "",
    "filename": "busybox",
    "binary_path": "/bin/busybox",
    "args": ""
  },
  "timestamp": "2026-01-27T13:26:44.733Z"
}

Improvements

Well i feel this is not the best way to do it, rather we have another methods like informers which we can use to watch the k8s client.

@hanshal101 hanshal101 force-pushed the hanshal101/add-k8s-info branch from be9bda5 to 30f0378 Compare January 27, 2026 14:53
Signed-off-by: hanshal101 <hanshalmehta10@gmail.com>
@hanshal101 hanshal101 force-pushed the hanshal101/add-k8s-info branch from 30f0378 to 2de20c2 Compare January 27, 2026 14:55
@hanshal101
Copy link
Copy Markdown
Author

Also if you're testing it you should run something like this, I was facing some issues previously here.

   sudo KUBECONFIG={you-kubeconfig-path} ./target/release/bombini --bpf-objs ./target/bpfel-unknown-none/release --config-dir ./config

Signed-off-by: hanshal101 <hanshalmehta10@gmail.com>
@hanshal101
Copy link
Copy Markdown
Author

Also here I am not sure whether I should push the vmlinux.rs since it looked like I have pushed with the latest version.

Signed-off-by: hanshal101 <hanshalmehta10@gmail.com>
@anfedotoff
Copy link
Copy Markdown
Member

Also here I am not sure whether I should push the vmlinux.rs since it looked like I have pushed with the latest version.

Please, do not push it. We need it to be regenerated in-place because of CO-RE support lack

@hanshal101
Copy link
Copy Markdown
Author

Also here I am not sure whether I should push the vmlinux.rs since it looked like I have pushed with the latest version.

Please, do not push it. We need it to be regenerated in-place because of CO-RE support lack

Yeah Cool

Comment thread bombini-common/src/k8s.rs

#[derive(Clone, Debug, Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
pub struct PodInfo {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this to transmuter::process module. bombini-common has definitions for types that are commonly used in bpf and user side. I think, we need no changes in common crate at all

// Minimal container id length. It could be truncated in ebpf.
if container.len() >= 31 {
container[..31].to_string()
if container.len() >= 10 {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we need this check?
Maybe we can check that this is a hex string? Please have a look here.

impl Process {
/// Constructs High level event representation from low eBPF
pub fn new(proc: &ProcInfo) -> Self {
pub fn new(proc: &ProcInfo, k8s_info: &K8sInfo) -> Self {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, it's better to pass something like Option<&Pod> here

Comment thread bombini/src/k8s_info.rs
@@ -0,0 +1,151 @@
use log;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread bombini/src/k8s_info.rs
#[derive(Clone)]
pub struct K8sInfo {
pods: Arc<RwLock<HashMap<String, PodInfo>>>,
k8s_available: Arc<std::sync::atomic::AtomicBool>,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's name PodInfoCache, like we have ProcessCache. I think, we don't need to have k8s_available flag. We can hold Option, here . At initialization step we can check if k8s is available.

Comment thread bombini/src/k8s_info.rs
log::error!("failed to list pods: {}", e);
}
}
time::sleep(Duration::from_secs(60)).await;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a configurable parameter.

Comment thread bombini/src/k8s_info.rs
async fn watch_pods(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let client = Client::try_default().await?;
let pods: Api<Pod> = Api::all(client);
let lp = ListParams::default();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to get pods, that are related to our node only.

Comment thread bombini/src/k8s_info.rs

for pod in pod_list {
if let Some(status) = pod.status {
if let Some(container_statuses) = status.container_statuses {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get only "living" containers

Comment thread bombini/src/k8s_info.rs

#[derive(Clone)]
pub struct K8sInfo {
pods: Arc<RwLock<HashMap<String, PodInfo>>>,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to think about another, concurent map here https://crates.io/crates/dashmap and move Arc to value: Arc to avoid copies.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants