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?)
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:
man 7 capabilities
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With