Skip to content

Fix permission errors for mounts in rootless docker #3446

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

matthewhughes934
Copy link
Contributor

@matthewhughes934 matthewhughes934 commented Apr 13, 2025

By running containers in a rootless docker context as root. This is because user and group IDs are remapped in the user namespaces uses by rootless docker, and it's unlikely that the current user ID will map to the same ID under this remap (see docs[1] for some more details). Specifically, it means ownership of mounted volumes will not be for the current user and trying to write can result in permission errors.

This change borrows heavily from an existing PR[2].

The output format of docker system info I don't think is documented/guaranteed anywhere, but it should corresponding to the format of a /info API request to Docker[3]

The added test hopes to avoid regressions in this behaviour, but since tests aren't run in a rootless docker context on the PR checks (and I couldn't find an easy way to make it the case) there's still a risk of regressions sneaking in.

Link: https://docs.docker.com/engine/security/rootless/ [1]
Link: #1484 [2]
Link: https://docs.docker.com/reference/api/engine/version/v1.48/#tag/System/operation/SystemAuth [3]

resolves #1243

@matthewhughes934 matthewhughes934 force-pushed the fix-docker-rootless-permission-mounts branch 2 times, most recently from 26b203c to 399f2f0 Compare April 13, 2025 19:03
),
)
def test_docker_user_rootless_docker(info_ret, expect_root):
docker._is_rootless_docker.cache_clear()
Copy link
Contributor Author

@matthewhughes934 matthewhughes934 Apr 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 maybe we should clear this before and after the test run: otherwise we risk polluting following tests with whatever value we last injected (and not the real value it reads from docker)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

usually a better approach is something like this:

@pytest.fixture(autouse=True)
def _avoid_cache():
    with mock.patch.object(docker, '_is_rootless_docker', docker._is_rootless_docker.__wrapped__):
        yield

this bypasses the cache for the duration of the test

@matthewhughes934 matthewhughes934 marked this pull request as ready for review April 13, 2025 19:10
Comment on lines 107 to 115
retcode, out, _ = cmd_output_b(
'docker', 'system', 'info', '--format', '{{ json .SecurityOptions }}',
)
# some failures are to be expected, e.g. for 'podman' aliased as 'docker'
if retcode != 0:
return False

info = json.loads(out)
return any(opt == 'name=rootless' for opt in info)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't seem to work for podman :(

$ readlink -f $(which docker)
/usr/bin/podman
$ docker system  info --format '{{ json .SecurityOptions }}'
Error: template: info:1:8: executing "info" at <.SecurityOptions>: can't evaluate field SecurityOptions in type *define.Info

Copy link
Contributor Author

@matthewhughes934 matthewhughes934 Apr 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't seem to work for podman :(

$ readlink -f $(which docker)
/usr/bin/podman
$ docker system  info --format '{{ json .SecurityOptions }}'
Error: template: info:1:8: executing "info" at <.SecurityOptions>: can't evaluate field SecurityOptions in type *define.Info

It looks like the invocation we need for podman is: podman system info --format '{{ json .Host.Security.Rootless }}', I guess we could either:

  • Run the docker command and on failure try the podman one, or
  • Run a separate command to figure out if docker invokes docker or podman and then run the corresponding command (ignoring any other container engines for now)

Trying to find a suitable command:

  • Naively I just want to run docker --version and search the output for "podman"
  • Or use the entire JSON output from docker system info
    • If .host exists: check ["host"]["Security"]["Rootless"], else
    • Check in ["SecurityOptions"]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parsing the entire info response seemed the most robust: 9bc412d

Comment on lines 78 to 81
if expect_root:
assert docker.get_docker_user() == ()
else:
assert docker.get_docker_user() != ()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't write logic in tests -- these are two separate disparate behaviours and should be tested separately

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't write logic in tests -- these are two separate disparate behaviours and should be tested separately

909c165 also included your cache suggestion from above

@asottile asottile force-pushed the fix-docker-rootless-permission-mounts branch from 3b3d042 to 026db3a Compare May 23, 2025 20:54
Copy link
Member

@asottile asottile left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By running containers in a rootless docker context as root. This is
because user and group IDs are remapped in the user namespaces uses by
rootless docker, and it's unlikely that the current user ID will map to
the same ID under this remap (see docs[1] for some more details).
Specifically, it means ownership of mounted volumes will not be for the
current user and trying to write can result in permission errors.

This change borrows heavily from an existing PR[2].

The output format of `docker system info` I don't think is
documented/guaranteed anywhere, but it should corresponding to the
format of a `/info` API request to Docker[3]

The added test _hopes_ to avoid regressions in this behaviour, but since
tests aren't run in a rootless docker context on the PR checks (and I
couldn't find an easy way to make it the case) there's still a risk of
regressions sneaking in.

Link: https://docs.docker.com/engine/security/rootless/ [1]
Link: pre-commit#1484 [2]
Link: https://docs.docker.com/reference/api/engine/version/v1.48/#tag/System/operation/SystemAuth [3]
Co-authored-by: Kurt von Laven <Kurt-von-Laven@users.noreply.github.com>
Co-authored-by: Fabrice Flore-Thébault <ffloreth@redhat.com>
@asottile asottile force-pushed the fix-docker-rootless-permission-mounts branch from 026db3a to 466f6c4 Compare May 23, 2025 21:01
@asottile asottile enabled auto-merge May 23, 2025 21:01
@asottile asottile merged commit 8a4af02 into pre-commit:main May 23, 2025
46 of 48 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Permission issue with rootless containers
2 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy