What does it mean if a Linux container (LXC container) is called "unprivileged"?
Unprivileged LXC containers are the ones making use of user namespaces (userns). 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.
- that a range of subordinate UIDs and GIDs is defined for the host user (
- ... and that this range is mapped in the container configuration (
lxc.id_map = ...)
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.
root you have to define the subordinate IDs first. Unlike users created via
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):
lxc.id_map = u 0 100000 100000
lxc.id_map = u 0 200000 100000
lxc.id_map = u 0 300000 100000
NB: as per a comment recent versions call this
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
$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.
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