7

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.

2
  • 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.
    – Cyclic3
    Oct 10, 2021 at 15:28
  • 1
    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. Oct 12, 2021 at 15:21

5 Answers 5

7

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).

1
  • 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. Oct 10, 2021 at 11:19
10

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.

1
  • 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. Oct 10, 2021 at 11:18
5

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.

8
  • 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. Oct 7, 2021 at 15:02
  • 1
    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: serverfault.com/a/388334/30946 Oct 7, 2021 at 15:09
  • 2
    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
    Oct 8, 2021 at 2:45
  • 3
    @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
    – Matt
    Oct 8, 2021 at 2:47
  • 1
    Also note that you could forward the docker port to a privileged port. Oct 8, 2021 at 19:36
3

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.

4
  • 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.
    – Matt
    Oct 8, 2021 at 5:25
  • 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. Oct 10, 2021 at 11:22
  • Thanks Koterpillar for mentioning the security implications of giving users docker access. Oct 10, 2021 at 11:23
  • Since a UNIX socket is a file, try mounting it to the container. Oct 11, 2021 at 0:10
1

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.

3
  • 1
    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. Oct 10, 2021 at 11:24
  • 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!
    – Mr.Budris
    Oct 19, 2021 at 15:56
  • 1
    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) Oct 20, 2021 at 16:33

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .