'Allow non-root user of container to execute binaries that need capabilities

I need to run a container as non-root user by default. However a specific process inside this container needs to execute a binary that needs cap_net_admin capabilities (e.g: ip command).

I tried running the container with '--privileged' flag, assigning file capability cap_net_admin to 'ip' binary, as well as changing the group to the user's group. This did not work. What is the correct way to get this working?

# cat Dockerfile
FROM  ubuntu:21.04
RUN apt-get update
RUN apt-get install -f -y iproute2
RUN chgrp nogroup /bin/ip
RUN chmod g+x /bin/ip
RUN setcap 'cap_net_admin+epi' /bin/ip
USER nobody


# docker build .
Successfully built be565bc8f52d

# docker run --rm --user nobody  --privileged -it be565bc8f52d /bin/bash
nobody@9834cfaa833f:/$ getcap /bin/ip
/bin/ip cap_net_admin=eip
nobody@9834cfaa833f:/$ ls -lhrt /bin/ip
-rwxr-xr-x 1 root nogroup 626K Mar 17  2021 /bin/ip
nobody@9834cfaa833f:/$ groups nobody
nobody : nogroup
nobody@9834cfaa833f:/$  cat proc/self/status | grep Cap
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
nobody@9834cfaa833f:/$ ip link add dummy0 type dummy
RTNETLINK answers: Operation not permitted

Note: With older docker version, this was working with setcap and privileged flag. Probably it stopped working due to the fix for this CVE.

# docker --version
Docker version 20.10.14, build a224086


Solution 1:[1]

Elaborating on my comment to the question, I think this is a problem with the ip code's attempt to suppress Ambient capabilities except in one specific command line case.

I've suggested a fix in this bug report: https://github.com/shemminger/iproute2/issues/62 (which appears to have been deleted, since this was not how iproute2 wants to receive bug reports). I was directed to try again with this email thread, so we can see how that report turns out.

I did develop a partial workaround you might want to try:

    $ sudo setcap cap_net_admin=ie ./ip
    $ sudo capsh --inh=cap_net_admin --user=`whoami` --
    $ ./ip ...

This works by using inheritable file capabilities instead of the permitted ones you were relying on. The ip code seems to prefer inheritable capabilities over permitted ones.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1