21

What does it mean if a Linux container (LXC container) is called "unprivileged"?

2 Answers 2

21

Unprivileged LXC containers are the ones making use of user namespaces (). I.e. of a kernel feature that allows to map a range of UIDs on the host into a namespace inside of which a user with UID 0 can exist again.

Contrary to my initial perception of unprivileged LXC containers for a while, this does not mean that the container has to be owned by an unprivileged host user. That is only one possibility.

Relevant is:

  1. that a range of subordinate UIDs and GIDs is defined for the host user (usermod [-v|-w|--add-sub-uids|--add-sub-gids])
  2. ... and that this range is mapped in the container configuration (lxc.id_map = ...)

So even root can own unprivileged containers, since the effective UIDs of container processes on the host will end up inside the range defined by the mapping.

However, for root you have to define the subordinate IDs first. Unlike users created via adduser, root will not have a range of subordinate IDs defined by default.

Also keep in mind that the full range you give is at your disposal, so you could have 3 containers with the following configuration lines (only UID mapping shown):

  1. lxc.id_map = u 0 100000 100000
  2. lxc.id_map = u 0 200000 100000
  3. lxc.id_map = u 0 300000 100000

NB: as per a comment recent versions call this lxc.idmap!

assuming that root owns the subordinate UIDs between 100000 and 400000. All documentation I found suggests to use 65536 subordinate IDs per container, some use 100000 to make it more human-readbable, though.

In other words: You don't have to assign the same range to each container.

With over 4 billion (~ 2^32) possible subordinate IDs that means you can be generous when dealing the subordinate ranges to your host users.

Unprivileged container owned and run by root

To rub that in again. An unprivileged LXC guest does not require to be run by an unprivileged user on the host.

Configuring your container with a subordinate UID/GID mapping like this:

lxc.id_map = u 0 100000 100000
lxc.id_map = g 0 100000 100000

where the user root on the host owns that given subordinate ID range, will allow you to confine guests even better.

However, there is one important additional advantage in such a scenario (and yes, I have verified that it works): you can auto-start your container at system startup.

Usually when scouring the web for information about LXC you will be told that it is not possible to autostart an unprivileged LXC guest. However, that is only true by default for those containers which are not in the system-wide storage for containers (usually something like /var/lib/lxc). If they are (which usually means they were created by root and are started by root), it's a whole different story.

lxc.start.auto = 1

will do the job quite nicely, once you put it into your container config.

Getting permissions and configuration right

I struggled with this myself a bit, so I'm adding a section here.

In addition to the configuration snippet included via lxc.include which usually goes by the name /usr/share/lxc/config/$distro.common.conf (where $distro is the name of a distro), you should check if there is also a /usr/share/lxc/config/$distro.userns.conf on your system and include that as well. E.g.:

lxc.include = /usr/share/lxc/config/ubuntu.common.conf
lxc.include = /usr/share/lxc/config/ubuntu.userns.conf

Furthermore add the subordinate ID mappings:

lxc.id_map = u 0 100000 65535
lxc.id_map = g 0 100000 65535

which means that the host UID 100000 is root inside the user namespace of the LXC guest.

Now make sure that the permissions are correct. If the name of your guest would be stored in the environment variable $lxcguest you'd run the following:

# Directory for the container
chown root:root $(lxc-config lxc.lxcpath)/$lxcguest
chmod ug=rwX,o=rX $(lxc-config lxc.lxcpath)/$lxcguest
# Container config
chown root:root $(lxc-config lxc.lxcpath)/$lxcguest/config
chmod u=rw,go=r $(lxc-config lxc.lxcpath)/$lxcguest/config
# Container rootfs
chown 100000:100000 $(lxc-config lxc.lxcpath)/$lxcguest/rootfs
chmod u=rwX,go=rX $(lxc-config lxc.lxcpath)/$lxcguest/rootfs

This should allow you to run the container after your first attempt may have given some permission-related errors.

4
  • 4
    Good answer - but lxc is not a necessity for this kind of thing. You can create a namespace container of any kind using the util-linux tool unshare. You can enter said container using the util-linux tool nsenter. The latter tool also allows you to add running processes to an already created container from without it. The namespace support is implemented in-kernel.
    – mikeserv
    Jan 2, 2015 at 14:04
  • 4
    @mikeserv: you mean you don't need LXC to make use of userns? I knew that. I also know Docker now has its own library making use of these facilities. But how would you containerize a whole system without the help of facilities offered by LXC? And why would you do it? I mean to contain a single application and combined with chroot this can help, but LXC combines various of the name spaces (UTS, mount etc ...) to containerize the whole system. Jan 2, 2015 at 15:54
  • 2
    Well... As i said, unshare already does this admirably for any/all of the various namespaces - and will even get you a separate, private /proc mount with a single cli-switch. If your single application is init and your chroot is initramfs then you get a whole container in seconds flat.
    – mikeserv
    Jan 12, 2015 at 8:06
  • 1
    Note that in recent LXC the key is called lxc.idmap
    – am70
    Jan 8, 2021 at 11:01
1

To followup on 0xC0000022L, whose solution worked fine for me, I wrote a increase-uid-gid.pl perl script to automatize the necessary ownership changes required so files within the LXC containers are properly mapped.

Without it, with this proposed setup, a file within LXC container rootfs belonging to 0/root on the main host will, within the LXC container itself, be mapped to 65534/nobody. To be mapped to 0/root within the LXC container, they must belong 100000 on the host.

This is described here https://yeupou.wordpress.com/2017/06/23/setting-up-lxc-containers-with-mapped-giduid/ and the script can be directly obtained on gitlab https://gitlab.com/yeupou/stalag13/blob/master/usr/local/bin/increase-uid-gid.pl

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .