elastic / go-sysinfo

go-sysinfo is a library for collecting system information.
Apache License 2.0
353 stars 87 forks source link

`containerized` detection isn't reliable #225

Open dliappis opened 3 months ago

dliappis commented 3 months ago

The logic for detecting whether go-sysinfo in running inside a container isn't always correct. The code section is: https://github.com/elastic/go-sysinfo/blob/6057d34798d93384013c2e8f8e3bd0b00c599912/providers/linux/container.go#L48-L52

and we can see that e.g. on a Linux host with cgroupsv2 we have:

[root@164502a64991 /]# cat /proc/1/cgroup 
0::/

which isn't covered by the above code.

We aren't the only ones who've noticed this discrepancy, as we can see in the linked stack overflow article.

The truth is that detecting containerization isn't very straightforward. For example Puppet's facter seems to only detect docker but not e.g. when running in podman. Issues have also been reported with Chef's Ohai (example) that seem to be resolved. A succinct comment with the possible strategies can be found in https://github.com/benfred/py-spy/issues/614.

Ohai's implementation seems to be the most complete, so we could get some ideas from https://github.com/chef/ohai/blob/d63ae8e8af713c44d040f5583aac84cd3d79f9af/lib/ohai/plugins/linux/virtualization.rb#L180-L217

dliappis commented 3 months ago

My understanding is that the above code affects at least this part of x-pack/auditbeat

fearful-symmetry commented 2 months ago

Came here to file this exact issue; this won't work on a lot of newer docker versions as well, as they generally will use a private cgroup namespace:

docker run -it ubuntu:latest /bin/bash
root@484005f6da5f:/# cat /proc/1/cgroup
0::/
git-blame commented 1 month ago

As mentioned, there is docker information in /proc/self/mountinfo. Notably, the container ids or hashes. There is a secondary problem which is that some docker containers do not have "/etc/machine-id", "/var/lib/dbus/machine-id", or "/var/db/dbus/machine-id". So the machine-id is also empty.

This code snippet can use mountinfo to get the docker's version of machineid. It can also be re-purposed to indicate if we are in a docker container:

func DockerMachineId(defaultId string) (machineId string) {
    machineId = defaultId
    // Get docker info
    file, err := os.Open("/proc/self/mountinfo")
    if err != nil {
        return
    }
    defer file.Close()

    r, err := regexp.Compile("docker/containers/([0-9a-f]+)")
    if err != nil {
        return
    }

    scan := bufio.NewScanner(file)
    var match []string
    for scan.Scan() {
        match = r.FindStringSubmatch(scan.Text())
        if match == nil || len(match) < 2 {
            continue
        }
        machineId = match[1]
        break
    }
    return
}