How security.idmap.isolated works in detail

We have non-obvious behavior when enable security.idmap.isolated

Our setup with disabled security.idmap.isolated, all containers use default profile and have settings:

  lxc config show ct1 | grep volatile.idmap
  ct1
      volatile.idmap.base: "0"
      volatile.idmap.current: '[{"Isuid":true,"Isgid":false,"Hostid":1148576,"Nsid":0,"Maprange":65536},{"Isuid":false,"Isgid":true,"Hostid":1148576,"Nsid":0,"Maprange":65536}]'
      volatile.idmap.next: '[{"Isuid":true,"Isgid":false,"Hostid":1148576,"Nsid":0,"Maprange":65536},{"Isuid":false,"Isgid":true,"Hostid":1148576,"Nsid":0,"Maprange":65536}]'

  lxc config show ct2 | grep volatile.idmap
  ct2
      volatile.idmap.base: "0"
      volatile.idmap.current: '[{"Isuid":true,"Isgid":false,"Hostid":1148576,"Nsid":0,"Maprange":65536},{"Isuid":false,"Isgid":true,"Hostid":1148576,"Nsid":0,"Maprange":65536}]'
      volatile.idmap.next: '[{"Isuid":true,"Isgid":false,"Hostid":1148576,"Nsid":0,"Maprange":65536},{"Isuid":false,"Isgid":true,"Hostid":1148576,"Nsid":0,"Maprange":65536}]'

System settings from subuid and subgid files

cat /etc/subuid | grep "lxd\|root"
lxd:1148576:65536
root:1148576:65536

cat /etc/subgid | grep "lxd\|root"
lxd:1148576:65536
root:1148576:65536

here we see that all containers use default UID allocation for containers. Root user in container maps to system UID 1148576.

Then we change subuid and subgid files and set maximum ID for root and lxd users to 2000000:

cat /etc/subuid | grep "lxd\|root"
lxd:1148576:2000000
root:1148576:2000000

cat /etc/subgid | grep "lxd\|root"
lxd:1148576:2000000
root:1148576:2000000

Then we restarted LXD service for the changes to take effect. And enable security.idmap.isolated in default profile

lxc profile set security.idmap.isolated true

all containers change their volatile.idmap.base to new values 65536, 131072 and so on, with step of 65536.

lxc config show ct1 | grep volatile.idmap
ct1
    volatile.idmap.base: "65536"
    volatile.idmap.current: '[{"Isuid":true,"Isgid":false,"Hostid":1148576,"Nsid":0,"Maprange":65536},{"Isuid":false,"Isgid":true,"Hostid":1148576,"Nsid":0,"Maprange":65536}]'
    volatile.idmap.next: '[{"Isuid":true,"Isgid":false,"Hostid":65536,"Nsid":0,"Maprange":65536},{"Isuid":false,"Isgid":true,"Hostid":65536,"Nsid":0,"Maprange":65536}]'
lxc config show ct2 | grep volatile.idmap
ct2
    volatile.idmap.base: "131072"
    volatile.idmap.current: '[{"Isuid":true,"Isgid":false,"Hostid":1148576,"Nsid":0,"Maprange":65536},{"Isuid":false,"Isgid":true,"Hostid":1148576,"Nsid":0,"Maprange":65536}]'
    volatile.idmap.next: '[{"Isuid":true,"Isgid":false,"Hostid":131072,"Nsid":0,"Maprange":65536},{"Isuid":false,"Isgid":true,"Hostid":131072,"Nsid":0,"Maprange":65536}]'

After restart this containers not started with error:
newuidmap failed to write mapping "newuidmap: uid range [0-65536) -> [589824-655360) not allowed"

And here are pool of questions:

  1. Is the are any detailed manual about how security.idmap.isolated works and sets?
  2. Why volatile.idmap.base starts from 65536 if minimal ID for lxd or root subuid is 1148576?
  3. Can we set minimal ID from which LXD will start count to 1148576?
  4. Can we change minimal ID step, not use default 65536?
  5. Can we set predictable and static UID for container which not changed during container life cycle?

So first thing to note is that LXD loads the subuid/subgid values from /etc on startup.
If you modified them but didn’t restart LXD, that could be a problem.

I’ve not looked at the internal logic in a while but generally, LXD is supposed to first unused uid/gid from all local instances and use that as the base for the next instance, effectively reserving the next 65536 for that one and so on.

The step size is configurable through security.idmap.size so you can alter that on a per-instance basis or as part of a profile.

The uid/gid map once allocated will not change during the container’s lifetime but you can also cause it to be altered by directly setting security.idmap.base.

Note that it is absolutely possible to have multiple containers share the same idmap range by having them have the same security.idmap.base and security.idmap.size.

1 Like

Thanks a lot for your answer. I re-read the documentation more carefully and found some of the answers to the questions, security.idmap.base and security.idmap.size is the solution that works for me.

About question 2:
In my opinion, using an uid/gid outside the allowed range is not entirely correct. I rechecked the configuration and restarted the server, but LXD still gives uid/gid for new containers starting from 65536 and does not take into account the range that is specified in /etc/subuid