vegardit/docker-gitea-act-runner

Can't run with no-new-privileges

DennisGaida opened this issue ยท 9 comments

Getting the error message sudo: effective uid is not 0, is /usr/bin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges? on startup when I try to run the container with the no-new-privileges option (--security-opt=no-new-privileges:true). Using the vegardit/gitea-act-runner:latest version obviously, since the other version uses privileged: true.

I try to do this for all containers and maybe this is something that could be taken into account for the DooD-version?

wblew commented

The vegardit/gitea-act-runner image starts by default with the container user being 'act'. However, during startup, it sudo's from act to root, to manage the act user's uid, gid, and ownership and permissions within its /data volume. See this line:

exec sudo -E bash /opt/run_fixids.sh

Given that, it's likely not compatible with docker's no-new-privileges option.

Disclaimer: I am no expert on docker. This is my opinion based on 10 minutes of research into the no-new-privileges option.

That might very well be the culprit but also looks like a hack at first sight (I'm also not a docker expert).

See for example the following blog post on how things should be done instead of usermod/groupmod: https://vsupalov.com/docker-shared-permissions/

I would assume GITEA_RUNNER_GID and GITEA_RUNNER_UID could very well be the group and user the container is running on (and not different from it).

This is actually an unsolved issue in docker world. There are countless blog posts reasoning about it. All existing workarounds/solutions are either hacks and/or have limitations one way or another. This issue has been raised with Docker Inc. 9 years ago and was closed with a rather non-practical solution.

Besides setting uid/gid at container build time or running a container with --user which can majorly confuse the container's OS there is also this tool intended for non-production use https://github.com/boxboat/fixuid

Additionally, for the docker-out-of-docker approach (vegardit/gitea-act-runner:latest), I don't see how this could be handled inside the container without sudo permissions:

docker_group=$(stat -c '%G' /var/run/docker.sock)
if [[ $docker_group == "UNKNOWN" ]]; then
docker_gid=$(stat -c '%g' /var/run/docker.sock)
docker_group="docker$docker_gid"
log INFO "Creating group [$docker_group]..."
addgroup --gid $docker_gid $docker_group
fi
if ! id -nG act | grep -qw "$docker_group"; then
log INFO "Adding user [act] to group [$docker_group]..."
usermod -aG $docker_group act
fi

The container user must be part of the docker group with the same GID as on the host system, otherwise it cannot access the docker socket. Since the GID may be different on each docker host system group membership must be adjusted dynamically inside the container.

As a side note: if you are so concerned about docker security that you require no-new-privileges you should not use the docker-out-of-docker approach at all as the act runner container can basically control the complete host through the docker socket, see https://gitea.com/gitea/act_runner/issues/167 You should only use it on a dedicated docker host that does nothing else than running act jobs and the act jobs should only execute trusted code.

Very insightful. I'm running about ~50 different containers with no-new-privileges just fine, hence I opened this issue. It is not really that I am ultra concerned about docker security - if I was I shouldn't be using docker but podman. For me it is more about consistency and "how others are doing it". I'm also never exposing the docker socket directly, but always using socket-proxy (https://github.com/Tecnativa/docker-socket-proxy) where I at least have some way of controlling what other containers are doing. Supporting TCP sockets would be my next feature request ๐Ÿ˜‰

If I am totally off-track (not being an expert), just close the issue. I just thought something could be done about this.

I also thought about the socket proxy as I am using it for another use case, but I think the ACL isn't fine grain enough. you can either turn a permission globally on or off, which means you still can mess with non-related containers running on the same host through the proxy. it misses the ability to specify filters based on container name patterns or labels so you can allow the runner only create/stop/start job containers.

Very insightful. I'm running about ~50 different containers with no-new-privileges just fine

to be fair, an act runner container is very different from a regular containerized app as it needs access to resources outside of it's container it isn't conceptually meant to access.

act runner container is very different from a regular containerized app

Oh, it very much is. Starting other containers and all.

Just checking the default drone.io docker runner it does run with no-new-privileges: https://github.com/drone-runners/drone-runner-docker but I didn't look deeper into it. Maybe it is just root? gitea's act_runner also runs fine with it (https://gitea.com/gitea/act_runner). Maybe https://gitea.com/gitea/act_runner/issues/170 might be an approach.

I'm not sure that running dockerd within the container is necessary for the DooD container - maybe the docker client would be sufficient and that one also supports TCP sockets or the DOCKER_HOST environment variable. I totally hear you about socket-proxy not being very fine grained (in the end you could run multiple socket proxies with different permissions, but that's not very efficient).

Maybe gitea.com/gitea/act_runner/issues/170 might be an approach.

dind-rootless also needs to be run with --privileged docker-library/docker#291

I'm not sure that running dockerd within the container is necessary for the DooD container

The DooD container does not run dockerd, it is only included in the DinD image.


I now changed the init script in a way that sudo is only executed if a uid/gid actually needs to be changed or the act user cannot read/write the docker socket and the docker group needs to be adjusted. See 19f8e34

Maybe this works in your environment with no-new-privileges.