It’s not, it can actually be accomplished by using subuid (subordinate user id’s) & subgid (subordinate group id’s) built into the linux kernel.
So why do we need this?
Well, it lets us isolate namespaces inside of containers.
Basically switching the root users id (UID:0) inside of the container to UID:****** on the host, thereby making sure that if a user (hacker) escapes the container they only gain unprivileged access to the host.
Ipso facto securing your hosts integrity. (presuming that you’ve configured it according to all security guidelines)
I wrote a script to make calculations of new subuid & subgid’s easier.
# one less than 2 to the 16th power, which is the highest number that can be represented by an unsigned 16-bit binary number.
# FILE exists and has a size greater than zero
U_FROM=$(tail -1 /etc/subuid | cut -f2 -d:)
U_TO=$(tail -1 /etc/subuid | cut -f3 -d:)
U_NEW_FROM=$(($U_FROM+$U_TO))
U_NEW_TO=$(($U_NEW_FROM+$INCREMENT_BY))
G_FROM=$(tail -1 /etc/subgid | cut -f2 -d:)
G_TO=$(tail -1 /etc/subgid | cut -f3 -d:)
G_NEW_FROM=$(($G_FROM+$G_TO))
G_NEW_TO=$(($G_NEW_FROM+$INCREMENT_BY))
# Run to add SubUID & SubGID for new client (/etc/sub?id):
usermod --add-sub-uids ${U_NEW_FROM}-${U_NEW_TO} --add-sub-gids ${G_NEW_FROM}-${G_NEW_TO} root
# Save to: /etc/lxc/client-default.conf
lxc.include = /etc/lxc/default.conf
lxc.id_map = u 0 ${U_NEW_FROM} 65536
lxc.id_map = g 0 ${G_NEW_FROM} 65536
lxc-create -n new_container_name -t download --config /etc/lxc/client-default.conf -- --no-validate
#!/bin/bash
# one less than 2 to the 16th power, which is the highest number that can be represented by an unsigned 16-bit binary number.
INCREMENT_BY=65535
# FILE exists and has a size greater than zero
if [[ -s /etc/subuid ]]
then
U_FROM=$(tail -1 /etc/subuid | cut -f2 -d:)
U_TO=$(tail -1 /etc/subuid | cut -f3 -d:)
U_NEW_FROM=$(($U_FROM+$U_TO))
U_NEW_TO=$(($U_NEW_FROM+$INCREMENT_BY))
else
U_NEW_FROM=100000
U_NEW_TO=165535
fi
if [[ -s /etc/subgid ]]
then
G_FROM=$(tail -1 /etc/subgid | cut -f2 -d:)
G_TO=$(tail -1 /etc/subgid | cut -f3 -d:)
G_NEW_FROM=$(($G_FROM+$G_TO))
G_NEW_TO=$(($G_NEW_FROM+$INCREMENT_BY))
else
G_NEW_FROM=100000
G_NEW_TO=165535
fi
cat <<EOF
# Run to add SubUID & SubGID for new client (/etc/sub?id):
usermod --add-sub-uids ${U_NEW_FROM}-${U_NEW_TO} --add-sub-gids ${G_NEW_FROM}-${G_NEW_TO} root
# Save to: /etc/lxc/client-default.conf
lxc.include = /etc/lxc/default.conf
lxc.id_map = u 0 ${U_NEW_FROM} 65536
lxc.id_map = g 0 ${G_NEW_FROM} 65536
# Create new container:
lxc-create -n new_container_name -t download --config /etc/lxc/client-default.conf -- --no-validate
EOF
#!/bin/bash
# one less than 2 to the 16th power, which is the highest number that can be represented by an unsigned 16-bit binary number.
INCREMENT_BY=65535
# FILE exists and has a size greater than zero
if [[ -s /etc/subuid ]]
then
U_FROM=$(tail -1 /etc/subuid | cut -f2 -d:)
U_TO=$(tail -1 /etc/subuid | cut -f3 -d:)
U_NEW_FROM=$(($U_FROM+$U_TO))
U_NEW_TO=$(($U_NEW_FROM+$INCREMENT_BY))
else
U_NEW_FROM=100000
U_NEW_TO=165535
fi
if [[ -s /etc/subgid ]]
then
G_FROM=$(tail -1 /etc/subgid | cut -f2 -d:)
G_TO=$(tail -1 /etc/subgid | cut -f3 -d:)
G_NEW_FROM=$(($G_FROM+$G_TO))
G_NEW_TO=$(($G_NEW_FROM+$INCREMENT_BY))
else
G_NEW_FROM=100000
G_NEW_TO=165535
fi
cat <<EOF
# Run to add SubUID & SubGID for new client (/etc/sub?id):
usermod --add-sub-uids ${U_NEW_FROM}-${U_NEW_TO} --add-sub-gids ${G_NEW_FROM}-${G_NEW_TO} root
# Save to: /etc/lxc/client-default.conf
lxc.include = /etc/lxc/default.conf
lxc.id_map = u 0 ${U_NEW_FROM} 65536
lxc.id_map = g 0 ${G_NEW_FROM} 65536
# Create new container:
lxc-create -n new_container_name -t download --config /etc/lxc/client-default.conf -- --no-validate
EOF
The script doesn’t execute anything, it only outputs suggestions for you to use. It’s kind of tricky to get these numbers right by hand.
# Run to add SubUID & SubGID for new client
usermod --add-sub-uids 1935008-2000543 --add-sub-gids 1935008-2000543 root
# Save: /etc/lxc/client-default.conf
lxc.include = /etc/lxc/default.conf
lxc.id_map = u 0 1935008 65536
lxc.id_map = g 0 1935008 65536
# Create new container
lxc-create -n new_container_name -t download --config /etc/lxc/client-default.conf -- --no-validate
So what about migration?
Switching SubUID and SubGID on a container filesystem requires running chown while shifting to the appropriate values.
[[ $# < 3 ]] && echo "$0 <container_name> <new_root_uid> <new_root_gid>" && exit 1
export SHIFT_FROM_UID=$(grep id_map /var/lib/lxc/${C}/config | grep 'u 0' | awk '{print $5}')
export SHIFT_FROM_GID=$(grep id_map /var/lib/lxc/${C}/config | grep 'g 0' | awk '{print $5}')
[[ -z "$SHIFT_FROM_UID" ]] && export SHIFT_FROM_UID=0
[[ -z "$SHIFT_FROM_GID" ]] && export SHIFT_FROM_GID=0
echo "# Shifting user and group from id ${SHIFT_FROM_UID}:${SHIFT_FROM_GID} to ${SHIFT_TO_UID}:${SHIFT_TO_GID}"
FILE_UID=$(stat -c '%u' $@)
FILE_GID=$(stat -c '%g' $@)
echo "chmod $(( $FILE_UID - $SHIFT_FROM_UID + $SHIFT_TO_UID )):$(( $FILE_GID - $SHIFT_FROM_GID + $SHIFT_TO_GID)) $@"
find /var/lib/lxc/$C/rootfs -exec bash -c 'splitit "$0"' {} \;
#!/bin/bash
[[ $# < 3 ]] && echo "$0 <container_name> <new_root_uid> <new_root_gid>" && exit 1
export C="$1"
export SHIFT_TO_UID="$2"
export SHIFT_TO_GID="$3"
export SHIFT_FROM_UID=$(grep id_map /var/lib/lxc/${C}/config | grep 'u 0' | awk '{print $5}')
export SHIFT_FROM_GID=$(grep id_map /var/lib/lxc/${C}/config | grep 'g 0' | awk '{print $5}')
[[ -z "$SHIFT_FROM_UID" ]] && export SHIFT_FROM_UID=0
[[ -z "$SHIFT_FROM_GID" ]] && export SHIFT_FROM_GID=0
echo "# Shifting user and group from id ${SHIFT_FROM_UID}:${SHIFT_FROM_GID} to ${SHIFT_TO_UID}:${SHIFT_TO_GID}"
function splitit() {
FILE_UID=$(stat -c '%u' $@)
FILE_GID=$(stat -c '%g' $@)
echo "chmod $(( $FILE_UID - $SHIFT_FROM_UID + $SHIFT_TO_UID )):$(( $FILE_GID - $SHIFT_FROM_GID + $SHIFT_TO_GID)) $@"
}
export -f splitit
find /var/lib/lxc/$C/rootfs -exec bash -c 'splitit "$0"' {} \;
#!/bin/bash
[[ $# < 3 ]] && echo "$0 <container_name> <new_root_uid> <new_root_gid>" && exit 1
export C="$1"
export SHIFT_TO_UID="$2"
export SHIFT_TO_GID="$3"
export SHIFT_FROM_UID=$(grep id_map /var/lib/lxc/${C}/config | grep 'u 0' | awk '{print $5}')
export SHIFT_FROM_GID=$(grep id_map /var/lib/lxc/${C}/config | grep 'g 0' | awk '{print $5}')
[[ -z "$SHIFT_FROM_UID" ]] && export SHIFT_FROM_UID=0
[[ -z "$SHIFT_FROM_GID" ]] && export SHIFT_FROM_GID=0
echo "# Shifting user and group from id ${SHIFT_FROM_UID}:${SHIFT_FROM_GID} to ${SHIFT_TO_UID}:${SHIFT_TO_GID}"
function splitit() {
FILE_UID=$(stat -c '%u' $@)
FILE_GID=$(stat -c '%g' $@)
echo "chmod $(( $FILE_UID - $SHIFT_FROM_UID + $SHIFT_TO_UID )):$(( $FILE_GID - $SHIFT_FROM_GID + $SHIFT_TO_GID)) $@"
}
export -f splitit
find /var/lib/lxc/$C/rootfs -exec bash -c 'splitit "$0"' {} \;