Subordinate GIDs/UIDs with LXC and userns for unprivileged user

lxcshadowuserns

When using userns (via LXC in my case), you assign a range of subordinate GIDs and UIDs to an unprivileged user. See for resources: subuid(5), subgid(5), newuidmap(1), newgidmap(1), user_namespaces(7).

That range can then be used and will via be mapped to the system account.

Let's assume we have a (host) system account john with a UID (and GID) of 1000. The assigned range of GIDs and UIDs is 100000..165536.

So an entry exists in /etc/subgid and /etc/subuid respectively:

john:100000:65536

Files that inside the unprivileged container are owned by the "inside" john will now be owned by 101000 on the host and those owned by the "inside" root will be owned by 100000.

Normally these ranges are not assigned to any name on the host.

Questions:

  1. is it alright to create a user for those respective UIDs/GIDs on the host in order to have a more meaningful output for ls and friends?
  2. is there a way to make those files/folder accessible to the host user who "owns" the userns, i.e. john in our case? And if so, is the only sensible method to create a group shared between those valid users inside the subordinate range and and the userns "owner" and set the permissions accordingly? Well, or ACLs, obviously.

Best Answer

  1. Is it alright to create a user for those respective UIDs/GIDs on the host in order to have a more meaningful output for ls and friends?

Yes it is alright. However you must ensure that such user has no right over anything in the host system:

  • Disabled access or password,
  • No usable login shell,
  • No writeable home directory.

Be also sure to not create any duplicate in your user names.

Here is a sample script, taking the guest's /etc/passwd and /etc/group files to create the corresponding users in the host system. All names are prefixed with the container name, and all IDs are increased using the given value to match container's UIDs:

#! /bin/sh

# Path to guest's `/etc' directory.
guest_etc=/var/lib/lxc/mycontainer/rootfs/etc
# Guest's name, used as login prefix and inside GECOS field.
guest_name=mycontainer
# Increment to be applied to UIDs and GIDs (= range start).
uid_incr=100000
gid_incr=$uid_incr

guest_passwd=${guest_etc}/passwd
guest_group=${guest_etc}/group

exec <$guest_group
while IFS=":" read name pass gid null; do
    gid_new=$( expr $gid + $gid_incr )
    if ! getent group $gid_new >/dev/null; then
        addgroup --system --gid $gid_new "${guest_name}_${name}"
    fi  
done

exec <$guest_passwd
while IFS=":" read login pass uid gid gecos null; do
    uid_new=$( expr $uid + $uid_incr )
    gid_new=$( expr $gid + $gid_incr )
    if ! getent passwd $uid_new >/dev/null; then
        adduser --system --home /nonexistent --no-create-home \
            --shell /bin/nologin --uid $uid_new --gid $gid_new \
            --gecos "\"$guest_name container user (${gecos})\"" \
            "${guest_name}_${login}"
    fi  
done

The warnings regarding the inaccessible home directory are normal and expected: this is the actual purpose of /nonexistent to not exist.

  1. is there a way to make those files/folder accessible to the host user who "owns" the userns, i.e. john in our case? And if so, is the only sensible method to create a group shared between those valid users inside the subordinate range and and the userns "owner" and set the permissions accordingly? Well, or ACLs, obviously.

This should really worth a separate question IMO.

Since the container's content is owned by different UIDs than the container owner UID, then it is not accessible to him. I can imagine an exception to this rule for subusers, but there is currently none I am aware of (I've created a related question a few time ago, but no answer yet).

The files /etc/subuid and /etc/subgid are currently only used by newuidmap(1) to allow or deny the switch from one UID/GID to another of a given process. It does not give the range owner any other right.

Therefore, the solution to such issue should be designed on a case-per-case basis. Beware however with you ACL idea: let's say you put some ACLs on the container's files to allow your host's UID 1000 to read them, this means that the container's user with container's UID 1000 will also have the same level of privilege...