Score:7

Give non root users permission to use one port

jp flag

I host a lab server where I am root (and a regular user).

The domain name is example.org and I give each member a subdomain, for example bob.example.org for Bob and anna.example.org for user Anna. I think you get the deal. :) The subdomains are reversed proxied using nginx to a specific port.

My question is, is there any way that I can give permission to non root users to start docker containers on their specific range of ports. For example Anna is given range 1300-1350 where port 1300 is bound to anna.example.org and the other ones are in reserve.

The system runs Debian 11 Bullseye and the latest Docker version.

Cyclic3 avatar
br flag
I would be *very* careful about giving non-root users access to docker. It is as simple as `docker run -v /:/pwn -it cyclic3/pwn` to get complete r/w access to the entire filesystem, and adding the `--privileged` is almost functionally identical from being root on that machine. I have seen this go wrong so many times, including in a CTF run by a large cyber company where it was intentional for a single challenge, but ended up exposing all the machines used for that category. It can be done securely, but I think it's really important to stress just how far south this can go.
Oscar Andersson avatar
jp flag
Awesome comment about the CTF anecdote. I sometimes compete in those myself. Sounds like a fun competition that one! :) Anyway, I've decided to isolate the user completely using different containers without any access to the host except for some open ports. Thanks for your time.
Score:9
td flag
bob

AFAIK Linux only has the concept privileged ports versus unprivileged ports.

The Linux kernel tuning parameter net.ipv4.ip_unprivileged_port_start defines which ports are privileged. All ports between 0 and net.ipv4.ip_unprivileged_port_start are privileged.

Privileged ports can only used by processes either started by the root user or with root privileges or by processes that are assigned the capability CAP_NET_BIND_SERVICE with for example sudo setcap cap_net_bind_service=ep /path/bin/application

All other ports are unprivileged and can be used by any user, as longs the ports are not already in use.

I don't know of any alternative method to allow specific users to use particular ports.

Oscar Andersson avatar
jp flag
Thanks @bob! I'm thinking of giving each user a docker container with Debian 11 where they can roam freely, I then bind port 80 and 22 to a subdomain of my main domain. What do you think about that? Maybe it adds a layer of security.
Score:6
in flag

First of all, only trusted users should be allowed to control your Docker daemon

The docker daemon runs as root by default on a Debian Bullseye installation. Adding a user to the docker group gives that user psuedo root access due to having control of the docker daemon having that amount of access. Every user in the docker group will have complete control of the host and others containers and can run a container that --publishes any port.

There are a few options to providing security to users docker access.

  1. Rootless docker
  2. sudo
  3. API

1. Rootless docker

A rootless docker setup would enable each user to run a docker deamon. For ports lower than 1024 it would need to abide by the unprivileged ports information bob provided as each user will "own" their own deamon. Docker also provides related guidance. This wouldn't stop Anna from taking Bobs port.

2. sudo

The simplest method to allow users to run docker commands is to provide a root controlled script via sudo that is either static, or controls the user input for optional arguments:

#!/bin/bash
docker run --detach --publish 1300:1300 anna/app-image
anna    ALL=(root) NOPASSWD: /usr/local/bin/start-anna-image

If you want users to be able to add their own options you need to be very careful about controlling their input as it's vert easy to

3. Authorization plugin or API for Docker

As Docker doesn't provide any authorization layer on the daemon you need to add something to control user access.

Docker provides an in built authorization plugin framework to enable this. Some examples are opa-docker-authz and casbin-authz-plugin

You could give the users access to a form of proxy API that provides the authentication and authorization over what is passed on to the Docker REST API. There are docker libraries for most programming languages. Kubernetes+RBAC is an example of an API that sits in front of the Docker daemon and controls access (just a very big/complex one that does a lot more).

Oscar Andersson avatar
jp flag
Thanks @matt, really! You brought up some good points, I've now tried alternative 1 and 2. I feel like rootless docker is a bit too complicated for me and the sudo rulesets requires too much time for me. What do you think about giving each users their own container which they simply SSH into. The users scope does not even cover the host. What are the security benefits of this in your opinion? Thanks.
Score:5
cn flag

As long as the ports are unprivileged, non-root users can bind to any port (over 1024). They can start the containers with:

docker run --expose 1300-1350  <image-name>

It is first come first served. If two programs are trying to bind to the same port, only the first one to bind will succeed.

For privileged ports (less than 1024), you need either root or CAP_NET_BIND_SERVICE capability. See man capabilities for details.

Oscar Andersson avatar
jp flag
Thanks Micea! Can I add a non root user to the docker user group and not let them interfere with privileged ports and other containers? So that Anna cant view, edit or remove Bob's containers.
cn flag
Containers started by one user will be managed only by that user. You can limit the port ranges on which the containers (or any applicaiton) can bind via SELinux or AppArmor: https://serverfault.com/a/388334/30946
Matt avatar
in flag
If the docker daemon is running as `root`, then it doesn't matter what user is running the `docker` commands. The users essentially have root access via the daemon which does the work.
Matt avatar
in flag
@OscarAndersson No, any user in the `docker` group, while the docker daemon is running as root, has root access to the machine and can control others containers
Nonny Moose avatar
gb flag
Also note that you could forward the docker port to a privileged port.
Oscar Andersson avatar
jp flag
Thanks @NonnyMoose, that's something i'm doing. :)
Oscar Andersson avatar
jp flag
Thanks @MirceaVutcovici that sounds interesting, I will look into it. :)
Oscar Andersson avatar
jp flag
Yeah @Matt that is a really good point. I'm not too worries about my users deliberately breaking the system, its more that some of them are inexperienced with Linux systems and may open up security holes for hackers. I will take your comments into account.
Score:3
in flag

The subdomains are reversed proxied using nginx to a specific port.

You can proxy the subdomains to Unix sockets.

    proxy_pass http://unix:/var/run/anna.sock:/;

Repeat as needed for each subdomain, and set the permissions on the Unix sockets so that only the users you want can listen there.

Also note that a user who can run Docker containers can mount /etc/passwd into them and gain root, so that has to be protected against separately.

Matt avatar
in flag
Good idea, but similar to your second point, docker could also mount any socket unless you add some other form of control over what a user can run via docker.
Oscar Andersson avatar
jp flag
Koterpillar and @matt, can I bind/publish a unix socket trough docker or should i use ports for this? Read something about it not being fully supported by docker yet.
Oscar Andersson avatar
jp flag
Thanks Koterpillar for mentioning the security implications of giving users docker access.
in flag
Since a UNIX socket is a file, try mounting it to the container.
Score:1
pk flag

Just wanted to add another perspective...certainly more work! But interesting...

Consider running a container orchestrator, such as Kubernetes. Check out KIND (Kubernetes-in-Docker) for an interesting way to run a Kubernetes cluster on a single node with only Docker.

You could then, for example, do something like

  • create a namespace for each user, such as bob-ns and anna-ns.
  • create a service in each namespace, exposing the specified ports
  • provide each user a role that allows them to create pods(groupings of containers) in their namespace, thus allowing them to accept traffic from the given service in their namespace.

If you structure the roles right, the users could concievably be allowed to launch whatever containers they want in their namespace, but would not be permitted to modify the service which defines the ports exposed.

This is simplified for the sake of space, but the primitives that something like k8s provide are excellent for multi-tenant systems like this.

Oscar Andersson avatar
jp flag
Thanks Budris, your post is truly inspirational and a bit experimental if i can say so. I believe its a bit too complicated for me though. Thanks.
Mr.Budris avatar
pk flag
yeah something like kubernetes is probably overkill for your environment, but keep systems like this in mind if your lab grows -- could save you a lot of time (and be an interesting learning experience) for the future. Cheers!
Oscar Andersson avatar
jp flag
Thanks, I'm definitely in for the learning experience. :) (Btw solved my problem with rootless docker, lingering systemd on user-level and regular non-root users on host)
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.