moby: Can't bind to privileged ports as non-root

The simplest way to reproduce this is:

$ docker run --rm -u 1000 php:apache
...
(13)Permission denied: AH00072: make_sock: could not bind to address [::]:80
(13)Permission denied: AH00072: make_sock: could not bind to address 0.0.0.0:80
...

So, that led me to try this, but with the same result:

$ docker run --rm -u 1000 --cap-add NET_BIND_SERVICE php:apache
...
(13)Permission denied: AH00072: make_sock: could not bind to address [::]:80
(13)Permission denied: AH00072: make_sock: could not bind to address 0.0.0.0:80
...

IMO, it seems reasonable to allow non-root to bind to privileged ports inside the container, especially since they have a private net namespace, so I was actually surprised this wasn’t already taken care of. I’m also confused as to why the --cap-add didn’t work, but maybe that’s because it adds the cap to the whitelist of things to not remove, not necessarily adds it if it isn’t there? I’m grasping at straws here.

About this issue

  • Original URL
  • State: closed
  • Created 10 years ago
  • Reactions: 3
  • Comments: 44 (39 by maintainers)

Commits related to this issue

Most upvoted comments

Just an fyi, for people that don’t want to deal with CAP_NET_BIND_SERVICE but would like to bind low ports; as of kernel 4.11, there is a sysctl that you can set in the network namesace will allow you to bind low ports[1]. If you are using a user namespace and you don’t have privileges in the network namespace, you will have to set it on the network namespace before hand, but for everyone else you can actually set it as part of docker run:

docker run -it --sysctl net.ipv4.ip_unprivileged_port_start=0 hello

[1] http://elixir.free-electrons.com/linux/v4.11.8/source/Documentation/networking/ip-sysctl.txt#L832

Is there any actual risk to set --sysctl net.ipv4.ip_unprivileged_port_start=0 on a container when that container is attached only to bridge networks (or actually, any network except host)? After all, even if a process opens an extra low port from inside the container, it wont be accessible unless the port is actually exposed and mapped to an external port, from the host. And the possibility that a port that is expected to be legitimately opened be hijacked by an illegitimate process, is not greater with this config (relative to what it is now), since the illegitimate process would have to start before the legitimate process opens its port, so very early in the container launch sequence, at which time, the process would be running as root anyway in the current approach…

What I mean by this is that setting net.ipv4.ip_unprivileged_port_start to 0 by default (that is, unless the container is attached directly to a network of type host) would appears to be a possible and reasonable solution, and most likely more secure than the status quo. Of course, this is arguably a patch, and yes this could be simply be highlighted in documentation. However, from the large number of outside tickets pointing to this one, it seems to be a very common issue, and it appears that many people, if not most, ends up lowering their security (by running their container as root) because they failed to find documentation on how to fix the issue by themselves.

Seems like this can be closed 👼

Definitely not here - those things make life hard. 😄

Ok, opened a new PR for runc https://github.com/opencontainers/runc/pull/1286 and will open an updated one here soon.