Search code examples
linuxdockertcpdump

Running tcpdump inside a Docker container as non-root user


I want to build a Docker image containing tcpdump. That Docker image runs an application that needs to call tcpdump, but it should not run as root all the time, for obvious security reasons. Instead, the non-root user should be able to run tcpdump directly.

Assuming the following Dockerfile:

FROM debian:bullseye

ENV DEBIAN_FRONTEND noninteractive

RUN apt-get update -qq \
  && apt-get install -y \
  libcap2 \
  libcap2-bin \
  tcpdump \
  && apt-get clean -y && apt-get autoremove -y \
  && rm -rf /var/lib/apt/lists/*

RUN addgroup --system --gid 1001 user
RUN adduser --system --uid 1001 user --shell /bin/bash

RUN groupadd pcap && usermod -a -G pcap user \
  && chgrp pcap /usr/bin/tcpdump \
  && chmod 750 /usr/bin/tcpdump \
  && setcap cap_net_raw,cap_net_admin=eip /usr/bin/tcpdump

USER user

ENTRYPOINT ["/usr/bin/tcpdump"]

When I run the image:

docker build -t tcpdump:latest .
docker run --rm -it tcpdump

… it fails with:

exec /usr/bin/tcpdump: operation not permitted

Someone else has raised this issue here but without a response.

What can I do to make this work?


Note that in regular installations it is not recommended to modify the permissions and group ownership of /usr/bin/tcpdump, as that could be overwritten by system package upgrades. However, since the container image is immutable, this does not apply here.


Solution

  • The problem is that the Docker container itself is missing the required capabilities to run tcpdump.

    You can add those capabilities by adding the --privileged option to the docker run command, or, even better, only add the capabilities strictly needed:

    $ docker run --rm --cap-add=NET_ADMIN --cap-add=NET_RAW  -it tcpdump
    tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
    listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
    ^C12:47:29.433403 IP6 :: > ff02::16: HBH ICMP6, multicast listener report v2, 1 group record(s), length 28
    
    1 packet captured
    6 packets received by filter
    0 packets dropped by kernel