I was just doing something very similar, moving KVM VMs into unprivileged LXC.
I was using system containers for this (so they can be started automatically on boot), but with mapped UID/GIDs (user namespaces).
- edit /etc/subuid,subgid (I mapped uid/gids 10M-100M to root and use 100K per container)
- for first container, use u/gids 10000000-10099999 in /var/lib/lxc/CTNAME/config
- mount the container storage on /var/lib/lxc/CTNAME/rootfs (or do nothing if you don't use separate volume/dataset/whatever per container)
- chown 10000000:10000000 /var/lib/lxc/CTNAME/rootfs
- setfacl -m u:10000000:x /var/lib/lxc (or simply chmod o+x /var/lib/lxc)
- lxc-usernsexec -m b:0:10000000:100000 -- /bin/bash
Now you're in the first container user namespace. Everything is the same, but your process thinks it's uid is 0, when in fact in the host namespace it's uid 10000000. Check /proc/self/uid_map to see whether your uid is mapped or not. You will notice you can no longer read from /root and it seems to be owned by nobody/nogroup.
While in the user namespace, I rsync from the original host.
Outside the user namespace, you will see that the files in /var/lib/lxc/CTNAME/rootfs are now owned not by the expected (same) uids as the origin installation, but rather 10000000+remote_uid. This is what you want.
That's it. When you have your data sync'ed, remove everything from container's /etc/fstab so it won't try to mount things, and it should start. There might be other things to change, check what the LXC template for the containerised distro does. You can definitely remove the kernel, grub, ntp and any hardware-probing packages in the container (you don't even have to run it, you can chroot to the container from the user namespace)
If you don't have a running remote VM, you can also mount the original VM storage in the host namespace and rsync/SSH back in to localhost. The effect will be the same.
If you (as it seems) simply want to change your privileged container to unprivileged, you might as well just add the uid/gid mapping, add a mapping as above to your container config and then do something along the lines of:
for i in `seq 0 65535`; do
find /var/lib/lxc/CTNAME/rootfs -uid $i -exec chown $((10000000+i)) \{\} \;
find /var/lib/lxc/CTNAME/rootfs -gid $i -exec chgrp $((10000000+i)) \{\} \;
done
That should be all that needs doing, now you should be able to run the container unprivileged. This example above is extremely inefficient, uidshift will probably do a better job at this (but I haven't used it yet).
HTH.
Best Answer
I know now how to do this. If you can't follow this explanation, please ask back, but also make sure you have read up on userns in the readings I am giving at the bottom
Preliminary assumptions
I'll stick with the following assumptions, extended from what I have from your question:
user1
and auser2
, if an information isn't specific to one, we'll useuserX
$container
user1
anduser2
will be given in the notation known from Bash as~user1
and~user2
.user1
and 200000..265536 foruser2
just for brevity$container
will be rendered as$rootfs
, regardless of where it will end up (~userX/.local/share/lxc/$container/rootfs
)~userX/.local/share/lxc/$container/config
Moving the container
There are two relevant pieces of data that govern the
userns
containers:$container
/etc/sub{uid,gid}
for the user account (manipulated viausermod --{add,del}-sub-{uid,gid}s
) andlxc.id_map
in the$container
configuration (~userX/.local/share/lxc/$container/config
) respectivelyuserX
has 65536 subordinate GIDs and UIDs, it might be possible to assign 5000 to 65 different containers, but I haven't tested that hypothesis.So the gist is really that you need to make sure that the file/folder owner and group for the container match the configuration, which in turn has to be a valid subset of the host subordinate GIDs/UIDs assigned to
user1
anduser2
respectively.If you're using Bash, for example, you can use
$((expression))
for arithmetic expressions andlet
to assign arithmetic expressions to variables. This is mighty useful if you know a base value (100000 and 200000 respectively) and the GID/UID for the "inside" users.The main points are:
CAP_CHOWN
or superuser rights are requiredHere's a script that will probably need some more honing (example: migration from root-created container to unprivileged), but it works for me for the purpose:
In addition to the license terms of the StackExchange network, I am putting this into the public domain. So reuse and modify for whatever purpose, but it comes without any warranty and I must not be held liable for its use or abuse.
UsageIt assumes
find
,sort
,uniq
,awk
(mawk
andgawk
should work),id
,bash
,chown
,chmod
and so on to be available and to understand all the command line switches it is using. For Bashreadonly
andlet
and arithmetic expressions are assumed to be understood. Forfind
is assumes+
is a valid terminator for the-exec
action.This list is probably not complete.
Backups
Yes, you can make backups and restore them elsewhere, as long as you also adjust the file owner and group accordingly.
However, assuming you use something like
tar
, there's a caveat:tar
will ignore sockets, so$rootfs/dev/log
will pose an issue - others may also create a similar issue.Resources:
subuid(5)
subgid(5)
newuidmap(1)
newgidmap(1)
user_namespaces(7)