Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which capabilities can I drop in a Docker Nginx container?

I'm running Nginx in a Docker container, and I would like to drop as many Linux capabilities as possible, for security reasons.

Which capabilities can I then drop?

The image is similar to the standard Docker Nginx Alpine image here: https://github.com/nginxinc/docker-nginx/blob/0c7611139f2ce7c5a6b1febbfd5b436c8c7d2d53/mainline/alpine/Dockerfile, which starts Nginx as root, and then runs the worker process as user 'nginx', look:

root@instance-1:/opt/ed# docker-compose exec web bash
bash-4.3# # Now we're inside the container.
bash-4.3# ps aux
PID   USER     TIME   COMMAND
    1 root       0:00 /bin/sh -c /etc/nginx/run-envsubst.sh && nginx
   10 root       0:00 nginx: master process nginx
   11 nginx      0:00 nginx: worker process
   12 nginx      0:00 nginx: cache manager process
   14 root       0:00 bash
   18 root       0:00 ps aux

Listens on ports 80 and 443, + mounts some directories using Docker-Compose's 'volume: ....' directive.

Apparently these are the capabilities Docker grants by default to a container:

s.Process.Capabilities = []string{
    "CAP_CHOWN",
    "CAP_DAC_OVERRIDE",
    "CAP_FSETID",
    "CAP_FOWNER",
    "CAP_MKNOD",
    "CAP_NET_RAW",
    "CAP_SETGID",
    "CAP_SETUID",
    "CAP_SETFCAP",
    "CAP_SETPCAP",
    "CAP_NET_BIND_SERVICE",
    "CAP_SYS_CHROOT",
    "CAP_KILL",
    "CAP_AUDIT_WRITE",
}

from here: https://github.com/docker/docker/blob/master/oci/defaults_linux.go#L62-L77

which I found linked here: https://docs.docker.com/engine/security/security/#linux-kernel-capabilities, and that page says that: "By default Docker drops all capabilities except those needed", which could mean that one doesn't need to drop any capabilities? ...

... However there's this Red Hat blog post about dropping lost of those capabilities — so seems (some of) the default capabilities aren't needed then. Not sure what to believe, and I'm wondering if people know which capabilities can (should) be dropped.

(I could perhaps test myself, but even if I test drop a capability and things seems to work fine for a few hours or days — I might still have dropped the wrong capability? Problems might arise, even later? So seems like safer to both ask-here & test-myself, than to only test myself)

(I'm surprised this hasn't been answered elsewhere already? Don't many people use Nginx in docker, and thus want to drop capabilities?)

like image 628
KajMagnus Avatar asked Apr 18 '17 08:04

KajMagnus


1 Answers

I was wondering the same thing, so I did some research. Be warned that this is not an expert answer.

Short answer: You can drop all privileges if you start nginx as user and use non-privileged ports (>1024). This is described in Nginx in Docker without Root and some additional info can be found in Running Nginx as non root user.

The ajhaydock/nginx nginx image specifically recommends --cap-drop=ALL (although I wouldn't recommend using this image, since it's currently quite large: 700MB).

Longer answer: The required privileges may vary depending on your config and whether you want to start nginx as root.

Let's start with an official docker image and its default configuration. The minimum capabilities are as follows:

docker pull nginx:alpine
docker run -p 8080:80 --cap-drop=all \
    --cap-add=chown --cap-add=dac_override \
    --cap-add=setgid --cap-add=setuid \
    --cap-add=net_bind_service \
    nginx:alpine

You can check that with these commands you will have the welcome page locally on port 8080 and if you remove any of the capabilities the process crashes on startup. (Note, according to Secure Your Containers with this One Weird Trick, needing dac_override means that they are probably doing it wrong..)

Obviously, net_bind_service is only required if listening on privileged ports like 80 and 443. Since we are free to redirect as desired, it can be dropped by simply listening on higher ports instead:

docker cp nginx:/etc/nginx/conf.d/default.conf .
sed -i 's/listen\s*80;/listen 8080;/' default.conf
docker rm nginx
docker run -p 8080:8080 --cap-drop=all \
    --cap-add=chown --cap-add=dac_override \
    --cap-add=setgid --cap-add=setuid \
    -v $(pwd)/default.conf:/etc/nginx/conf.d/default.conf \
    nginx:alpine

Still works.

The other privileges can be dropped as well by running nginx as non-root user. In this case you can't use the user nginx; directive, rather use USER nginx in the Dockerfile. This also prevents you from using privileged ports.

Further resources that might be helpful to others:

  • Secure Your Containers with this One Weird Trick
  • man 7 capabilities
like image 131
coldfix Avatar answered Sep 27 '22 21:09

coldfix