Docker Basics | Linux Capabilities

One of the most fundamental basics about Linux is understanding the concept of the root user. We run programs either with “root-permissions” or without root permissions. But it does not necessarily have to be one or the other. We can use capabilities to make this a spectrum and break down root permissions into several distinct pieces. Capabilities are essential to secure containers.

Security in Linux is closely related to the root user. Our normal mode of operation is to work with our personal accounts and as soon as we have to do some administrative stuff we use privilege escalation with sudo. Sudo allows us to control who can get root privileges and which commands we are allowed to run. Another way to allow users root privileges for individual programs is using the SUID bit. We should be careful with that as shown here (http://www.it-automation.com/2021/05/26/how-linux-helps-to-understand-god.html).

A few years ago when I was working as systems administrator one of my colleagues had the habit to open up dozens of terminals with root shells on all the servers he had to work on. That was a very efficient wasy to quickly jump to where he needed to go. But virtually everyone working as a systems administrator has had those kind of experiences when running some command in the wrong shell. The same happened to him as he accidentially deleted a production database. And you may guess it, nobody had ever thought about a backup. This situation could have caused bancruptcy to the company. Fortunately he had a dump of the database lying around that he made a couple of hours ago.

We have to understand that security reduces our efficency. Jumping around root shells may be very efficient but on the other hand it can be very dangerous. On the other hand we could run all our servers in runlevel 0. That would be very secure but not efficient at all. We always need to have something in between and that is where capabilities are really useful. Capabilties allow us to splut up root privileges into several distinct pieces. For an exhaustive list of capabilities see

man 7 capabilities

A prominent example of capabilities is the ping command. Check out the man page of the ping command

man 8 ping

In the security section it says

ping requires CAP_NET_RAW capability to be executed 

You may notice that you can use ping with your normal user even though that user does not have the permission to create an ICMP echo socket. The traditional way of solving that was to set the SUID bit for the ping command (which is owned by root). The problem with that approach is that the whole process now has much more privileges it needs to have. If someone exchanged the ping command with a malicious script we are in trouble.

A more secure way is to apply the least privilege principle and allow only those privileges that it has to have to its job. Let’s check if there are any capabilities set for the ping command.

getcap $(which ping)

On a debian based system this reveals that it has the CAP_NET_RAW capability and the execution bit for everyone. On the other hand it does not have the SUID bit set anymore (at least on debian). It can now run with our normal user account rather than root.

ps u -C ping

Securing the ping command is just some basic example of how capabilities work. As those settings are default we don’t have to care much about them. But when it comes to containers we have to understand what is going on.

Containers rely on namespaces for isolation and capabilities for security. A root user within a privileged container is still treated as a root user to the system. The system does not know that he is doing stuff “inside” a container. The system does not even know what a container is. Assume that the sys filesystem is mounted inside the container. We probably don’t want a root user inside a container to fiddle around with that.

There are two ways we can work with capabilities, either blacklisting or whitelisting. Blacklisting means that we assume the container has all capabilities and we drop those we do not want. On the other hand we can use a whitelisting approach which means we only grant those privileges that are necessary for the applications inside the container.

In both cases our configuration is somewhere in between “no capabilities (similar to what your personal user can do) or “all capabilities (which is similar to what root can do”).

Contact