Trouble with idmaps in restricted Incus container

I’m trying to mount parts of my home directory on the underlying host into an Incus container. The container is restricted in a confined project. Therefore, I want to use an idmap to map my uid/gid inside the container to my uid/gid on the underlying host.

Unfortunately, I’m running into errors that I don’t fully understand. Not sure, if I’m doing something wrong, or if it’s a glitch in Incus itself? Here’s the gist (see tl;rd further down for more info):

  • Project restriction config, where 40001 is the uid/gid of my user michael on the host:
    restricted: "true"
    restricted.devices.disk: allow
    restricted.devices.disk.paths: /home/michael
    restricted.idmap.gid: "40001"
    restricted.idmap.uid: "40001"
    
  • Idmap config of the container in my restricted project:
    raw.idmap: both 40001 40001
    
  • Disk config of the container:
    devices:
      host-bind-tofu-aws:
        path: /mnt/meeque/tofu/aws
        shift: "false"
        source: /home/michael/*****/opentofu/aws
        type: disk
    
  • Error message in container logs, when I try to start the container:
    lxc user-40001_container-aws-controller 20241008090532.702 ERROR    conf - ../src/lxc/conf.c:lxc_map_ids:3704 - newuidmap failed to write mapping "newuidmap: uid range [40001-40002) -> [40001-40002) not allowed": newuidmap 643068 0 1000000 40001 40001 40001 1 40002 1040002 999959998
    
    The container state remains stopped.

Any ideas what might be wrong here?

Workarounds that I’ve tried:

  • Omit the idmap:
    The container comes up fine. I use OpenTofu and Ansible to provision the same user (michael, 40001) inside the container. When I ls the mounted files, it shows uid/gid as nobody. Obviously this is expected, but it will not allow me to work with the mounted files as desired.

  • Use shift property on the disk device:
    When starting the container, I get the following error message:

    Failed to start device "host-bind-tofu-aws": The `shift` property cannot be used with a restricted source path
    

    Seems to be a feature. Not sure, why it’s necessary?

  • Use shift property without source path restrictions in the project config:
    restricted.devices.disk.paths=''
    The shift property works now. I get the desired behavior inside the container.
    However, on the underlying host, this would give my user michael the same privileges as root (without going through sudo or similar). E.g. my user could create a new Incus container, bind mount / into it, and manipulate arbitrary host config files (e.g. /etc/shadow) from inside the container.

Disclaimer: I’m fairly new to Incus, and I have never used lxc directly.

tl;dr:

Here’s the details, some of it redacted with *****:

Environment:

$ cat /etc/issue
Ubuntu 24.04.1
$ uname -a
Linux d*****t 6.8.0-45-generic #45-Ubuntu SMP PREEMPT_DYNAMIC Fri Aug 30 12:02:04 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
$ incus --version
6.0.0

Relevant configuration:

$ cat /etc/subuid
michael:165536:65536
common:231072:65536
root:1000000:1000000000
$ cat /etc/subgid
michael:165536:65536
common:231072:65536
root:1000000:1000000000
$ sudo incus admin init --dump
config:
  images.auto_update_interval: "0"
networks:
- config:
    ipv4.address: 192.168.66.1/24
    ipv4.firewall: "false"
    ipv4.nat: "true"
    ipv6.address: none
  description: ""
  name: incusbr0
  type: bridge
  project: default
storage_pools:
- config:
    source: /var/lib/incus/storage-pools/meeque-desktop
  description: General storage pool for Incus instances on desktop hosts.
  name: meeque-desktop
  driver: dir
profiles:
- config: {}
  description: Default profile
  devices:
    eth0:
      name: eth0
      network: incusbr0
      type: nic
    root:
      path: /
      pool: meeque-desktop
      type: disk
  name: default
projects:
- config:
    features.images: "true"
    features.networks: "true"
    features.networks.zones: "true"
    features.profiles: "true"
    features.storage.buckets: "true"
    features.storage.volumes: "true"
  description: Default Incus project
  name: default
- config:
    features.images: "true"
    features.networks: "false"
    features.networks.zones: "true"
    features.profiles: "true"
    features.storage.buckets: "true"
    features.storage.volumes: "false"
    restricted: "true"
    restricted.containers.nesting: block
    restricted.devices.disk: allow
    restricted.devices.disk.paths: /home/michael
    restricted.devices.gpu: block
    restricted.devices.nic: allow
    restricted.idmap.gid: "40001"
    restricted.idmap.uid: "40001"
    restricted.networks.access: incusbr0
  description: User restricted project for "michael" (40001)
  name: user-40001
$ incus config show container-aws-controller
architecture: x86_64
config:
  boot.autostart: "true"
  cloud-init.user-data: |
    #!/bin/sh
    *****
  image.architecture: amd64
  image.description: Ubuntu noble amd64 (20241007_07:42)
  image.os: Ubuntu
  image.release: noble
  image.requirements.cgroup: v2
  image.serial: "20241007_07:42"
  image.type: squashfs
  image.variant: cloud
  limits.cpu: "1"
  limits.memory: 1GiB
  raw.idmap: both 40001 40001
  volatile.base_image: 40bc***121d
  volatile.cloud-init.instance-id: 8048*****e6aa
  volatile.eth0.host_name: veth7*****6
  volatile.eth0.hwaddr: 00:*****:e8
  volatile.eth0.name: eth0
  volatile.idmap.base: "0"
  volatile.idmap.current: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":40001},{"Isuid":true,"Isgid":true,"Hostid":40001,"Nsid":40001,"Maprange":1},{"Isuid":true,"Isgid":false,"Hostid":1040002,"Nsid":40002,"Maprange":999959998},{"Isuid":false,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":40001},{"Isuid":false,"Isgid":true,"Hostid":1040002,"Nsid":40002,"Maprange":999959998}]'
  volatile.idmap.next: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":40001},{"Isuid":true,"Isgid":true,"Hostid":40001,"Nsid":40001,"Maprange":1},{"Isuid":true,"Isgid":false,"Hostid":1040002,"Nsid":40002,"Maprange":999959998},{"Isuid":false,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":40001},{"Isuid":false,"Isgid":true,"Hostid":1040002,"Nsid":40002,"Maprange":999959998}]'
  volatile.last_state.idmap: '[]'
  volatile.last_state.power: STOPPED
  volatile.last_state.ready: "false"
  volatile.uuid: a904*****8f143
  volatile.uuid.generation: a904*****8f143
devices:
  eth0:
    ipv4.address: 192.168.66.32
    network: incusbr0
    type: nic
  host-bind-tofu-aws:
    path: /mnt/meeque/tofu/aws
    shift: "false"
    source: /home/michael/*****/opentofu/aws
    type: disk
  root:
    path: /
    pool: meeque-desktop
    type: disk
ephemeral: false
profiles:
- default
stateful: false
description: ""

Commands that I’ve run:

$ incus start container-aws-controller
Error: Failed to run: /usr/libexec/incus/incusd forkstart user-40001_container-aws-controller /var/lib/incus/containers /run/incus/user-40001_container-aws-controller/lxc.conf: exit status 1
Try `incus info --show-log container-aws-controller` for more info
Name: container-aws-controller
Status: STOPPED
Type: container
Architecture: x86_64
Created: 2024/10/08 10:59 CEST
Last Used: 2024/10/08 11:05 CEST

Log:

lxc user-40001_container-aws-controller 20241008090532.702 ERROR    conf - ../src/lxc/conf.c:lxc_map_ids:3704 - newuidmap failed to write mapping "newuidmap: uid range [40001-40002) -> [40001-40002) not allowed": newuidmap 643068 0 1000000 40001 40001 40001 1 40002 1040002 999959998
lxc user-40001_container-aws-controller 20241008090532.702 ERROR    start - ../src/lxc/start.c:lxc_spawn:1788 - Failed to set up id mapping.
lxc user-40001_container-aws-controller 20241008090532.702 ERROR    lxccontainer - ../src/lxc/lxccontainer.c:wait_on_daemonized_start:878 - Received container state "ABORTING" instead of "RUNNING"
lxc user-40001_container-aws-controller 20241008090532.703 ERROR    start - ../src/lxc/start.c:__lxc_start:2107 - Failed to spawn container "user-40001_container-aws-controller"
lxc user-40001_container-aws-controller 20241008090532.703 WARN     start - ../src/lxc/start.c:lxc_abort:1036 - No such process - Failed to send SIGKILL via pidfd 17 for process 643068
lxc 20241008090532.748 ERROR    af_unix - ../src/lxc/af_unix.c:lxc_abstract_unix_recv_fds_iov:218 - Connection reset by peer - Failed to receive response
lxc 20241008090532.748 ERROR    commands - ../src/lxc/commands.c:lxc_cmd_rsp_recv_fds:128 - Failed to receive file descriptors for command "get_init_pid"

Try installing Incus from Zabbly instead of regular Ubuntu packages. That way, idmap should work as expected.

One more thing:
raw.idmap: both 40001 40001

means:
raw.idmap: both <host user uid and gid are 40001> <container user uid and gid are 40001>

The default user inside container has uid and gid 1000, therefore you probably should use:
raw.idmap: both 40001 1000

1 Like

Thanks for your feedback to my spammy question! I’ll try with a newer Incus version from Zabbly and report back.

Should have tried that earlier, but I wasn’t sure if my expectations were valid. Could not find any related Github issues either.

(Regarding the uid/gid: I do in fact use 40001 both outside and inside the container. A cloud-init script takes care of setting that up. Just like to keep it consistent between my laptop, the Incus Containers/VMs, and some RaspberryPis and EC2 instances.)

We would need to figure out what’s different with the default Debian/Ubuntu packaging that makes it not work with raw.idmap. It’s a recurring issue.

I upgrade to Incus 6.6 and I still get an error. Here is my reproducible example.

$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 24.04 LTS
Release:	24.04
Codename:	noble
$ incus version
Client version: 6.6
Server version: 6.6
$ id
uid=1000(myusername) gid=1000(myusername) ...
$ incus profile show idmap
config:
  raw.idmap: |-
    uid 1000 1000
    gid 1000 1000
description: ""
devices: {}
name: idmap
used_by: []
project: default
$ incus launch images:alpine/edge/cloud mycontainer --ephemeral
Launching mycontainer
$ incus exec mycontainer -- su -l alpine 
mycontainer:~$ id
uid=1000(alpine) gid=1000(alpine) groups=4(adm),10(wheel),1000(alpine)
mycontainer:~$ logout
$ incus delete mycontainer --force
$ incus launch images:alpine/edge/cloud mycontainer --profile default --profile idmap
Launching mycontainer
Error: Failed instance creation: Failed to run: /opt/incus/bin/incusd forkstart mycontainer /var/lib/incus/containers /run/incus/mycontainer/lxc.conf: exit status 1
$ 

and the log,

Log:

lxc mycontainer 20241018133027.456 ERROR    idmap_utils - ../src/lxc/idmap_utils.c:lxc_map_ids:245 - newuidmap failed to write mapping "newuidmap: uid range [1000-1001) -> [1000-1001) not allowed": newuidmap 14840 0 1000000 1000 1000 1000 1 1001 1001001 999998999
lxc mycontainer 20241018133027.456 ERROR    start - ../src/lxc/start.c:lxc_spawn:1795 - Failed to set up id mapping.
lxc mycontainer 20241018133027.456 ERROR    lxccontainer - ../src/lxc/lxccontainer.c:wait_on_daemonized_start:837 - Received container state "ABORTING" instead of "RUNNING"
lxc mycontainer 20241018133027.456 ERROR    start - ../src/lxc/start.c:__lxc_start:2114 - Failed to spawn container "mycontainer"

You’d need to have root:1000:1 in both /etc/subuid and /etc/subgid for this to be allowed, do you have that?

Incus from Ubuntu repo installs uidmap package, where one from Zabbly doesn’t. As @stgraber pointed out before, systems without that package don’t have to have root:1000:1 in both /etc/subuid and /etc/subgid.

I’ve finally retested with latest Incus 6.6 from daily Zabbly myself:

$ dpkg -l incus
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name           Version                      Architecture Description
+++-==============-============================-============-===========================================
ii  incus          1:0~ubuntu24.04~202410210302 amd64        Incus - Container and virtualization daemon

$ incus version
Client version: 6.6
Server version: 6.6

Unfortunately, this has not fixed my problem. My test results are very similar to what @simos has reported, so I’ll not post the details here.

(Notable differences: still using 40001 as uid/gid both inside and outside the container; configured raw.idmap on the instance itself rather than using a profile; used Ubuntu rather than Alpine as container image.)

Some new (to me) observations:

  • The raw.idmap in the config is sufficient to trigger the error. Configuring a disk based on a host directory is not necessary.
  • I tested on a separate host and noticed that no lxc libs or tools are not installed there. Would have expected that Incus requires packages like liblxc-common, lxc, and lxcfs. Looks like the incus package has its own copy of the lxc stuff, because everything works fine as long as I do not use raw.idmap. (Thought this might be relevant, because the errors in the logs mention lxc a lot.)

Thanks for pointing us to the uidmap package, @stgraber! I’ve ensured that it’s installed during my testing with latest Incus from Zabbly.

However I have follow-up questions:

  • You suggested to try with root:1000:1 in /etc/sub?id. Is this entry for root really required?
    Keep in mind that I’m not using Incus as root here. Instead, I’m using a regular user who is member of the incus group, see original post for details. (@simos’ test outputs seem to indicate that he’s doing the same.)

  • On my test host, the uidmap package gives me this (similar to my original post):

    $ cat /etc/sub?id
    michael:165536:65536
    root:1000000:1000000000
    michael:165536:65536
    root:1000000:1000000000
    

    Are you suggesting that I should add root:1000:1 to the existing entries?
    Or, should I replace the existing root entry with it?

First, try to uninstall uidmap package. If that doesn’t help, maybe try adding root:40001:1 in both /etc/subuid and /etc/subgid? Keep the previous entries.

Edit:
You can use those commands from Stéphane’s blog

printf "root:$(id -u):1\n" | sudo tee -a /etc/subuid
printf "root:$(id -g):1\n" | sudo tee -a /etc/subgid
2 Likes

Thank you, @qkiel!

Adding root:40001:1 in the subuid and subgid files has solved the problem on my test host. I’ve just appended it to the existing entries in these files. I have not attempted uninstalling the uidmap package though.

(For anyone with the same problem: You may want to try root:1000:1 instead, if you’re using more conventional uids/gids on your host. Or just replace 1000 with the user id on the host that you want to idmap into the container.)

1 Like

I’ve rolled out @qkiel’s solution to my main host now. Still works like a charm, even though I’m sticking to the outdated Incus 6.0 (from Ubuntu 24.04) for now.

Even after reading Stéphane’s blog, I find all of this very confusing. Since I was working with a user-restricted Incus project, I would have never thought that the subuid/subgid entries for root matter. Guess it makes sense, since Incus itself seems to be running as root on the host.

The fact that the error messages in the logs came from lxc and/or newuidmap didn’t help either. (As said, I’m new to all of this.)

Would it be possible for Incus to print a more helpful error message in such situations?

Or at least improve the docs? Not sure which ones though:

Should I raise a github issue or attempt a PR for this?

1 Like

I am doing something similar mapping a CIFS share mounted on the host into a container. I would have used shift = true however that doesn’t appear to work with a CIFS share. I have made instead an actual mapping from the share UID and GID on the host (110000) with $ incus config set iqBt raw.idmap "both 110000 110000" and I also added root:110000:1 into both /etc/subgid and subuid on the host and that seems to work for the user within the container with uid and gid 110000 or any user added to the users group with gid 110000. However, I’m not really clear what the entries in the subgid and subuid files are for and what they do or indeed how that interracts or might cause problems for the other entries in the file or implications for other containers.

I’ve read the Incus User namespace help and tried to find other documentation for user namespace mapping between host and container but it’s not very clear to me.