opencontainers / runc

CLI tool for spawning and running containers according to the OCI specification
https://www.opencontainers.org/
Apache License 2.0
11.8k stars 2.1k forks source link

User namespace mappings not working as expected #3191

Open nathanblair opened 3 years ago

nathanblair commented 3 years ago

The spec here shows that the config.json uidMappings and gidMappings should forward {u,g}ids from the host into the container runtime.

Its very possible I'm misunderstanding intended behavior here but I'm not able to map a user ID from the host into an existing user ID in the container using runc.

I'm more convinced this is a bug as I'm able to run the exact same config.json file with virtually the same arguments to crun and it works as expected.

I've been pouring over issues and a lot sound tangentially related but all seem like they may be trying to accomplish something slightly different than my case.

I would like to try to set up as minimally reproducible environment as possible, but I'm not sure the most effective way to do that. Open to suggestions!

Some more info about my environment (happy to provide more as necessary):

Tools

$ crun --version
crun version 1.0
commit: 139dc6971e2f1d931af520188763e984d6cdfbf8
spec: 1.0.0
+SELINUX +APPARMOR +CAP +SECCOMP +EBPF +YAJL
$ runc --version
runc version 1.0.2
commit: 52b36a2dd837e8462de8e01458bf02cf9eea47dd
spec: 1.0.2-dev
go: go1.16.7
libseccomp: 2.5.1

Relevant Output

$ runc run -b my-container-path/ my-container
ERRO[0000] User namespaces enabled, but no user mapping found.
$ crun run -b my-container-path/ my-container
/ $ exit

^^^ Note the above showing the $ character for prompt; I've not included it but confirmed id reports back with app(1000) et cetera.

Host

Container

Relevant lines from config.json


"user": {
    "uid": 1000,
    "gid": 1000
},

...

"uidMappings": [
    {
        "containerID": 1000,
        "hostID": 1000,
        "size": 1
    }
],
"gidMappings": [
    {
        "containerID": 1000,
        "hostID": 1000,
        "size": 1
    }
],
nathanblair commented 3 years ago

I get a different error setting the {u,g}idMappings to forward hostID 1000 to containerID 0:

$ runc run -b my-container/ my-container
WARN[0000] unable to get oom kill count                  error="no directory specified for memory.oom_control"
ERRO[0000] container_linux.go:380: starting container process caused: setup user: cannot set uid to unmapped user in user namespace

I'm also less-sure the ability of crun here is desired, as I've discovered for either of the mapping cases, the entire filesystem in the container runtime is owned by the app user (uid 1000).

What I'm aiming for is run the container under the app user but the file system still restricted and owned by the root user. So it behaves like a privileged/rooted container even though I'm running it through a rootless setup.

nathanblair commented 3 years ago

After some trial and error and lots of guessing I have managed to get permissions set correctly with the following configuration:

"uidMappings": [
  {
    "containerID": 1000,
    "hostID": 10000,
    "size": 1
  },
  {
    "containerID": 0,
    "hostID": 1000,
    "size": 1
  }
],
"gidMappings": [
  {
    "containerID": 1000,
    "hostID": 10000,
    "size": 1
  },
  {
    "containerID": 0,
    "hostID": 1000,
    "size": 1
  }
],

I think I'm getting close to finally understand the mapping going on. I have my sub{g,u}id files set to $MY_USER_NAME:10000:65536, with my actual host ID being 1000. The filesystem (unpacked) on the host is owned by my host user (1000), so when the unpacked rootfs is mounted in, it appears to map the 1000->0 id correctly and then recognizes the id owner of 0 is root ✔️

At the same time, my sub id user (10000) appears to be correctly mapped to the user that exists in the container system (1000), as I can open up the container and run a shell directly as that (1000) user.

I wanted to keep this open though as I am still a little perplexed by this difference in behavior between crun and runc. After looking into [youki](https://github.com/containers/youki) and seeing some of their progress, I wonder if this is because there's something left unimplemented on either runc or crun?