Docker — Linux security technologies (cGroups)

Fsegredo
4 min readAug 31, 2023

--

In the latest article, we discussed the Linux kernel feature namespace and its different types of isolation. Today, we will explore cGroups.

CGroups

Control Groups(cGroups), are a Linux kernel feature that allow you to allocate and manage system resources among processes.

They provide a means to restrict, account for, and isolate the utilization of resources (such as CPU, memory, disk I/O, and network) of a group of processes, facilitating effective resource management and preventing resource exhaustion and denial-of-service attacks (DoS).

As we’ve seen before, containers are isolated from each other, but the OS resources are still shared between them.

Resources share

You are probably familiar with the docker flags — memory and — cpu when creating or updating a container. This is what cgroups does, limits the amount of resources that the container can use (by default has no limits, which can be a challenge, we’ll look into it later)

We are going to deploy two web servers, one with memory limits and one without, and then compare them.

docker run -itd --name withlimit --memory=314572800 httpd
docker run -itd --name nolimit httpd

Inspecting the container and looking into the memory value for each container

docker inspect nolimit -f "{{.HostConfig.Memory}}"
docker inspect withlimit -f "{{.HostConfig.Memory}}"
No memory limit set
Limit of 300 MB that was defined with — memory

another way to verify this value inside the container:

cat /sys/fs/cgroup/memory/memory.limit_in_bytes
Limit by the -m value we’ve set
No limit, defines a LONG_MAX on a 64 bit platform

The PID of the containers can be used to verify this directly in the host.

Usually the path of the cgroups associated to containers is always the same /sys/fs/cgroup/(type)/docker/containerID but to make sure let’s use proc to tell us the cgroups associated with a PID.

Let’s start by getting the containers PID

#SYNTAX docker inspect --format='{{.State.Pid}}' ContainerName

docker inspect --format='{{.State.Pid}}' withlimit #28352
docker inspect --format='{{.State.Pid}}' no limit #27744
Retrieve container PID

Now that we have the PID of the containers, it’s easy the get the cgroup folder location in the host

#SYNTAX cat /proc/{PID}/cgroup
List of cgroup path in host

Since we are doing a Memory limit test, we’ll only focus on the memory cgroup/folder.

#SYNTAX cd/sys/fs/cgroup/memory/docker/ContainerID
cd /sys/fs/cgroup/memory/docker/702677...
list of group

In this case the docker flag — memoryequals the folder memory.limit_in_bytes.

For the container without limit we’ll get a LONG_MAX/PAGE_SIZE in a 64-bit platform that basically says unlimited resource.

Memory with no limit

Doing the same for the container with a memory limit, we’ll get the value we defined while creating the container

Memory with limit

This is only one of the resources that can be restricted, as explained in a superficial manner. Additionally, we can restrict the CPU utilization and device access by the container.

Fork bomb is a common DoS attack on Linux systems that involves flooding your system with shallow processes, which depletes the system resources. By default, Linux processes and subsequently containers do not impose any limitations on the number of processes that can be generated.

Image by imperva

cGroups can be used to limit this by adding the flag pids-limit to your docker run command.

Let’s see how this works.

The easiest way to simulate this is to use a Bash script, which is an infinite loop that repeatedly launches new copies of itself. This will eventually crash your system by consuming CPU time and saturating the systems process table.

We’re only going to show the result with the pid limitating set (Be ready for a crash and to reboot your system inc ase you try it without the pid limit).

docker run -it --name pidlimit --pids-limit 10 ubuntu bash

We’re running a ubuntu container with a bash process and the limit of processes 10 and run the following:

:(){ :|: & };:

Explanation of the script

Pid limit result

The container will reach the maximum of pids defined and will start throwing erros, but the host will remain responsive, preventing DoS

If this post was helpful, please click the clap 👏 button below a few times👇

--

--

Fsegredo

DevOps || Terraform || Ansible || Docker || Kubernetes || .Net || CNCF