Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] new(libsinsp): extract pod_uid from cgroups #1377

Closed
wants to merge 3 commits into from

Conversation

Andreagit97
Copy link
Member

What type of PR is this?

/kind feature

Any specific area of the project related to this PR?

/area libsinsp

Does this PR require a change in the driver versions?

No

What this PR does / why we need it:

This PR allows us to extract the pod_uid directly from the cgroups paths obtained from our drivers (kmod/bpf).

Which issue(s) this PR fixes:

This is necessary to unblock falcosecurity/falco#2973

Special notes for your reviewer:

Does this PR introduce a user-facing change?:

NONE

@poiana
Copy link
Contributor

poiana commented Oct 3, 2023

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: Andreagit97

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@@ -200,11 +200,10 @@ endif()
set_sinsp_target_properties(sinsp)

target_link_libraries(sinsp
PUBLIC scap
PUBLIC scap "${RE2_LIB}"
Copy link
Contributor

Choose a reason for hiding this comment

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

This is needed so that unit-test-libsinsp is able to correctly link re2 since it is now needed.

// If `this->cgroups()` is not empty we should have at least the first element
// An example of `this->cgroups()[0].second` layout is:
// /kubelet.slice/kubelet-kubepods.slice/kubelet-kubepods-pod1b011081_6e8e_4839_b225_4685eae5fd59.slice/cri-containerd-2f92446a3fbfd0b7a73457b45e96c75a25c5e44e7b1bcec165712b906551c261.scope
if(!re2::RE2::PartialMatch(this->cgroups()[0].second, pattern, &m_pod_uid))
Copy link
Contributor

@Molter73 Molter73 Oct 3, 2023

Choose a reason for hiding this comment

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

Are we sure we want to add a regex match in the hot path for processes? What type of performance hit do we expect from this? Would you mind providing an easy way to disable this check at runtime just in case? Maybe since it looks like heavily related to k8s, could we move it somewhere in the k8s specific code?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point! Let's say the alternative would be to loop over some prefixes like in the container engine

bool match_one_container_id(const std::string &cgroup, const std::string &prefix, const std::string &suffix, std::string &container_id)
but not sure this would be more efficient 🤔

I'm ok with disabling it at runtime, but not sure what is the best way to disable it (cmake?some flags provided to sinsp?) Any ideas?

Copy link
Contributor

Choose a reason for hiding this comment

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

Couldn't this be done by a container engine thread as an async event? Just thinking out loud.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this needs to be in the process hot path at all, at least thinking from my use case, we have a separate process that gets this information from the kube api, so this are just compute cycles being wasted. Since it's for k8s, I insist it might be better placed somewhere closer to the k8s specific code, but I'm not familiar enough with that code to suggest where to place it.

As for how to enable it at runtime, a simple bool m_pod_uid_enabled flag and a setter alongside the set_pod_uid definition is more than enough IMO, set_pod_uid would just check that flag before doing anything else and return if it's set to false.

Copy link
Contributor

Choose a reason for hiding this comment

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

👋 happy to help as I have been sifting through the container engine on multiple occasions.

First, yes plz no additional regexes on the hot path.

A few pointers:

I usually use crictl to spin up test pods as that allows for easy testing of both containerd and crio. Example inspection outputs of both the pod / sandbox or the container show that if it's a sandbox the container id is the same as the pod / sandbox id.

INSPECT POD / SANDBOX

sudo crictl pods
sudo crictl inspectp 95120af54b0d1


crio

 "io.kubernetes.cri-o.SandboxID": "95120af54b0d102cc259e906f9aea0423ea7a5dd87ae458567f93cd453b944b1",
 "io.kubernetes.cri-o.ContainerID": "95120af54b0d102cc259e906f9aea0423ea7a5dd87ae458567f93cd453b944b1",

containerd

"status": {
    "id": "c28089bf708270613d27c409a4aaa5679537e8cbe54993ee3749038811cc8d97",

"io.kubernetes.cri.container-type": "sandbox",
"io.kubernetes.cri.sandbox-id": "c28089bf708270613d27c409a4aaa5679537e8cbe54993ee3749038811cc8d97",


INSPECT CONTAINER

sudo crictl ps
sudo crictl inspect 84d2897a399b0

crio 

"io.kubernetes.cri-o.SandboxID": "95120af54b0d102cc259e906f9aea0423ea7a5dd87ae458567f93cd453b944b1",
"io.kubernetes.cri-o.ContainerID": "84d2897a399b0026499e93f490f47304818eb77868b23634f397a50bcedadb77",

String search for m_is_pod_sandbox in the code base and I think that will direct you to the relevant code blocks to make minor adjustments. Basically perhaps it's just about returning the existing container id already extracted from the current cgroups parsing logic if it's a sandbox (without needing the API call against the container runtime socket to know if it's a sandbox or container). And since I haven't looked myself I don't know what all needs to be adjusted to get this, just suspecting it could be easier and less intrusive in the container engine code base (echoing @FedeDP and @Molter73 feedback).

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this is much heavier than lots of things already happening in the main thread after all. I see the use case and it makes sense IMO.
I'd only enable this behavior (ie: the regex match) when either the k8s client is enabled or the new plugin is enabled, so that people that don't use it don't pay the (small) extra cost.

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't think this needs to be in the process hot path at all, at least thinking from my use case, we have a separate process that gets this information from the kube api, so this are just compute cycles being wasted

@Molter73 Just for curiosity, how do you associate the pod_uid extracted from the kube API to a sinsp thread?

Copy link
Contributor

@Molter73 Molter73 Oct 4, 2023

Choose a reason for hiding this comment

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

I don't think this needs to be in the process hot path at all, at least thinking from my use case, we have a separate process that gets this information from the kube api, so this are just compute cycles being wasted. Since it's for k8s, I insist it might be better placed somewhere closer to the k8s specific code, but I'm not familiar enough with that code to suggest where to place it.

Hi @Molter73 , we are writing a plugin to handle the kubernetes metadata. But we need to associate a process/thread with those metadata. The best is to leverage the pod UID and extract it from the cgroup path. The cgroup path is already there, just need to extract the pod UID substring from it. We can consider moving the extraction of the pod UID to the plugin code but performances would be impacted too much since the extraction would be done each time we need to associate a syscall to its k8s metadata. Keep in mind that plugin logic would block all the processing on the sinsp side.

Well, that's all fine, but we can still probably move it to the container engine. Even if most of the heavy lifting by container engines is done asynchronously, getting the container ID is done in line by the resolve members, so by making the check there you can limit the search to engines that actually make sense and you could potentially use the already matched container ID in some cases as @incertum suggests. At the very least, if it's going to be a costly operation, an enable flag for adopters to opt out would be appreciated.

I don't think this needs to be in the process hot path at all, at least thinking from my use case, we have a separate process that gets this information from the kube api, so this are just compute cycles being wasted

@Molter73 Just for curiosity, how do you associate the pod_uid extracted from the kube API to a sinsp thread?

Have to admit I'm not 100% sure how this process works, it's a completely separate process from the one I usually work on, but basically we inform data about the process and the container ID it belongs to and the other process does its thing to get information about the resource the container belongs to from the API. I'd have to dig deeper to understand it better, but at that point the data is no longer a sinsp_thread.

Copy link
Contributor

Choose a reason for hiding this comment

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

@alacuku thanks for adding more context around why you would want this outside the container engine. It was not clear to me before you shared this additional context. I was wondering why we actually cannot use the container engine API calls to get the sandbox id like we currently do as the id itself has not too much value without the pod name anyways. But now I see the use case. Just double checking: The new k8s client definitely and absolutely would only work with the sandbox id and we couldn't pivot from container id to sandbox id like we for example do today with the container runtime API calls?

Yes the tree would need to be formed - it would still be more effective in the container engine portions, but as you explained the ultimate goal would be to bypass the container engine.

Question:

How urgent is this patch now? Are we planning the k8s client refactor for Falco 0.37? What are the performance improvement hopes compared to extracting the most critical information from the container runtime socket today? Are we just planning to replace the mechanisms of getting the k8s fields we support today or are we planning to extend capabilities?

For example, would support for extracting info from for example https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#mutatingadmissionwebhook be possible with the new framework down the road? That would get me definitely "hooked" and in favor.

Copy link
Contributor

Choose a reason for hiding this comment

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

@Andreagit97 and @alacuku re to what was mentioned above Omar opened a new issue falcosecurity/falco#2895. It would propose adding some similar (not necessarily regex), but string checks on the hot path.

@Andreagit97 you mentioned you wanted to explore more options, curious to hear more. I liked to hear that the refactor could potentially be more performant and more reliable than the current container engine. In that case we could also win in terms of using the k8s client to already gather container image and other fields we currently only fetch from the container runtime socket.

Andreagit97 and others added 3 commits October 3, 2023 17:40
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
Co-authored-by: Aldo Lacuku <aldo@lacuku.eu>
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>
Signed-off-by: Andrea Terzolo <andreaterzolo3@gmail.com>

#pragma once

#define RGX_POD "(pod[a-z0-9]{8}[-_][a-z0-9]{4}[-_][a-z0-9]{4}[-_][a-z0-9]{4}[-_][a-z0-9]{12})"
Copy link
Contributor

Choose a reason for hiding this comment

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

Why can't this live closer to the set_pod_uid definition in threadinfo.h? A full header file for a single define seems overkill.

@Andreagit97 Andreagit97 changed the title new(libsinsp): extract pod_uid from cgroups [WIP] new(libsinsp): extract pod_uid from cgroups Oct 6, 2023
@Andreagit97 Andreagit97 modified the milestones: 0.14.0, TBD Oct 6, 2023
@Andreagit97 Andreagit97 marked this pull request as draft October 6, 2023 14:12
@Andreagit97
Copy link
Member Author

We will evaluate other possible solutions

@Andreagit97
Copy link
Member Author

this is now integrated into the new plugin, we can close this

@Andreagit97 Andreagit97 closed this Nov 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants