moby / buildkit

concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit
https://github.com/moby/moby/issues/34227
Apache License 2.0
7.83k stars 1.09k forks source link

Dockerfile: Mount the root `/proc/` into another directory #5065

Open thernstig opened 1 week ago

thernstig commented 1 week ago

Description

I would like mount the /proc/ directory inside another directory.

First of all, /proc/ is not a regular directory, it's a virtual filesystem; https://docs.kernel.org/filesystems/proc.html.

Some container build scenarios require it accessible from another directory than from the root.

There are some packages that require /proc/ to exist. For example, the SUSE permissions package if using SLES. If installing this package in a non-root location, i.e. some other path than / (root), one can do that with zypper, a package manager for SLES:

zypper --non-interactive --installroot /foo/ install --no-recommends \
    permissions

This seems impossible with Dockerfiles, but work fine when e.g. using something like buildah where I can mount like:

mount -t proc /proc "/foo/proc/"

Without such functionality, it is not possible to use Dockerfiles with options like zypper's --installroot. There are most likely similar options for other package managers.

(broken out from https://github.com/moby/moby/issues/47899)

thaJeztah commented 1 week ago

I'm not sure that is something we can support; mounting requires CAP_SYS_ADMIN; see mount(2)

Appropriate privilege (Linux: the CAP_SYS_ADMIN capability) is required to mount filesystems.

CAP_SYS_ADMIN is not part of the default set of capabilities as it provides many, many capabilities, making it a very unsafe option to provide;

Mounting fails on a container without CAP_SYS_ADMIN;

docker run -it --rm alpine sh -c 'mkdir -p /foo/proc && mount -t proc /proc "/foo/proc/" && echo success'
mount: permission denied (are you root?)

With CAP_SYS_ADMIN, this works;

docker run -it --rm --cap-add CAP_SYS_ADMIN alpine sh -c 'mkdir -p /foo/proc && mount -t proc /proc "/foo/proc/" && echo success'
success

What exactly does the permissions package do, and what are you trying to achieve?

thernstig commented 1 week ago

@thaJeztah I understand that the question "what are you trying to achieve" might be go avoid the XY problem, but if we forget about that for a moment and do consider that we really have requirements to be able to install some packages dependent on /proc/, what would one do?

Just pretend I want to install permissions into a non-root path.

I have found one solution possibly. One could use https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/reference.md#run---security and then something like:

zypper --non-interactive install --no-recommends \
    curl \
    util-linux
mkdir -p /foo/proc/
mount -t proc /proc/ /foo/proc/
zypper --non-interactive --installroot /foo/ install --no-recommends --auto-agree-with-licenses \
    gawk \
    hostname \
    iproute2 \
    rpm \
    util-linux \
    which \
    sles-release

util-linux installs the mount command, which requires privileges.

Naturally I would want to achieve this inside a container without privileges, hence this request.

thernstig commented 1 week ago

The package util-linux installs permissions.

thaJeztah commented 1 week ago

My question was also to understand what the permissions package expects to do once the image is built, and run. If it requires CAP_SYS_ADMIN to run the image, then the image limited in portability.

In either case, as this is related to containers started during docker build, it's probably best to move this ticket to the BuildKit repository, as BuildKit is the runtime to create containers during build.

cyphar commented 1 week ago

I suspect this is basically the same issue as https://bugzilla.suse.com/show_bug.cgi?id=1219736? permissions uses chkstat which uses /proc to double-check paths in /proc/self/fd/... to handle checking symlink resolutions.

I would recommend leaving a comment in that bug to let folks know that it's an issue actual customers are hitting (though in your case, my suggestions to use fsopen or mount a temporary procfs won't work because you don't have CAP_SYS_ADMIN.)

thernstig commented 1 week ago

@thaJeztah I do not know what the permissions package expects to do during runtime. All I know is that it fails to install in a Dockerfile in the scenario described. @cyphar stepped in and explained why luckily.

@cyphar I believe you are right. The failure for us looks like this:

24.75 (50/50) Installing: util-linux-2.37.4-150500.9.11.1.x86_64 [....
25.77 Warning: running kernel does not support fscaps
25.77 ERROR: /proc is not available - unable to fix policy violations.
25.77 ERROR: not all operations were successful.
25.77 /usr/bin/wall should be root:tty 2755. (wrong permissions 0755)
25.77 /usr/bin/write should be root:tty 2755. (wrong permissions 0755)
25.77 Warning: running kernel does not support fscaps
25.79 done]
25.79 Running post-transaction scripts [...done]
------
Dockerfile:24
...
...

Do you know if there is any solution to this that is sensible?

With buildah one can do mount -t proc /proc "/foo/proc/". If one could do a similar mount in Dockerfiles e.g. something like RUN --mount=type=proc,from=busybox:1.35.0,source=/proc/,target=/proc/foo/ (where busybox:1.35.0 could be left out to specify the same Dockerfile as being built?) it would solve it. But I have no idea if that is feasible. And it would need to be implemented in BuildKit.

I feel waiting for a fix for https://bugzilla.suse.com/show_bug.cgi?id=1219736 might only solve that case partially, maybe there are other cases/packages that need /proc/. So fixing both that bug and a new feature for Dockerfiles might be appropriate?