Eu sei agora como fazer isso. Se você não pode seguir esta explicação, por favor, pergunte de volta, mas também certifique-se de ter lido as informações sobre as leituras que estou dando na parte inferior
Pressupostos preliminares
Eu vou ficar com as seguintes suposições, ampliadas do que eu tenho da sua pergunta:
- o host tem
user1
euser2
, se uma informação não for específica de uma, usaremosuserX
- o container será nomeado por uma variável que renderizaremos como
$container
- as pastas base de
user1
euser2
serão fornecidas na notação conhecida do Bash como~user1
e~user2
. - presumiremos que os intervalos subordinados de UID e GID sejam 100000..165536 para
user1
e 200000..265536 parauser2
apenas por brevidade - a pasta FS raiz para
$container
será processada como$rootfs
, independentemente de onde ela será finalizada (~userX/.local/share/lxc/$container/rootfs
) - a configuração do contêiner é, por padrão, em
~userX/.local/share/lxc/$container/config
Mover o contêiner
Existem dois dados relevantes que governam os contêineres userns
:
- proprietário e grupo para os arquivos / pastas das pastas que compõem o
$container
- os UIDs e GIDs subordinados atribuídos em dois locais:
/etc/sub{uid,gid}
para a conta de usuário (manipulado por meio deusermod --{add,del}-sub-{uid,gid}s
) elxc.id_map
na configuração de$container
(~userX/.local/share/lxc/$container/config
) respectivamente- Não sei ao certo se é possível definir intervalos diferentes na configuração do contêiner para cada contêiner. Por exemplo. se o usuário do host
userX
tiver 65536 GIDs e UIDs subordinados, talvez seja possível atribuir 5000 a 65 recipientes diferentes, mas não testei essa hipótese. - é certo, porém, que essa configuração comunica ao LXC quais são os intervalos válidos para GID e UID no namespace filho.
- Não sei ao certo se é possível definir intervalos diferentes na configuração do contêiner para cada contêiner. Por exemplo. se o usuário do host
Portanto, a essência é que você precisa ter certeza de que o proprietário do arquivo / pasta e o grupo do container correspondem à configuração, que por sua vez deve ser um subconjunto válido dos GIDs / UIDs subordinados do host atribuídos a user1
e user2
, respectivamente.
Se você estiver usando o Bash, por exemplo, você pode usar $((expression))
para expressões aritméticas e let
para atribuir expressões aritméticas a variáveis. Isso é muito útil se você souber um valor base (100000 e 200000, respectivamente) e o GID / UID para os usuários "internos".
Os principais pontos são:
- é possível
- ou o recurso
CAP_CHOWN
ou direitos de superusuário são necessários
Aqui está um script que provavelmente precisará de um pouco mais de aperfeiçoamento (exemplo: migração do container criado pela raiz para o sem privilégio), mas funciona para mim com o propósito:
#!/usr/bin/env bash
function syntax
{
echo "SYNTAX: ${0##*/} <from-user> <to-user> <container-name>"
[[ -n "$1" ]] && echo -e "\nERROR: ${1}."
exit 1
}
# Checks
[[ -n "$1" ]] || syntax "<from-user> is not set"
[[ -n "$2" ]] || syntax "<to-user> is not set"
[[ -n "$3" ]] || syntax "<container-name> is not set"
[[ "$UID" -eq "0" ]] || syntax "${0##*/}" "You must be superuser to make use of this script"
# Constants with stuff we need
readonly USERFROM=$1
readonly USERTO=$2
shift; shift
readonly CONTAINER=${1:-*}
LXCLOCAL=".local/share/lxc"
readonly HOMEFROM=$(eval echo ~$USERFROM)
readonly HOMETO=$(eval echo ~$USERTO)
readonly LXCFROM="$HOMEFROM/$LXCLOCAL"
readonly LXCTO="$HOMETO/$LXCLOCAL"
readonly GIDBASEFROM=$(awk -F : "\ ~/$USERFROM/ {print \}" /etc/subgid)
readonly UIDBASEFROM=$(awk -F : "\ ~/$USERFROM/ {print \}" /etc/subuid)
readonly GIDSIZEFROM=$(awk -F : "\ ~/$USERFROM/ {print \}" /etc/subgid)
readonly UIDSIZEFROM=$(awk -F : "\ ~/$USERFROM/ {print \}" /etc/subuid)
readonly GIDBASETO=$(awk -F : "\ ~/$USERTO/ {print \}" /etc/subgid)
readonly UIDBASETO=$(awk -F : "\ ~/$USERTO/ {print \}" /etc/subuid)
readonly GIDSIZETO=$(awk -F : "\ ~/$USERTO/ {print \}" /etc/subgid)
readonly UIDSIZETO=$(awk -F : "\ ~/$USERTO/ {print \}" /etc/subuid)
unset LXCLOCAL
# More checks
[[ -d "$LXCFROM" ]] || syntax "Could not locate '$LXCFROM'. It is not a directory as expected"
[[ -e "$LXCTO" ]] && syntax "Destination '$LXCTO' already exists. However, it must not"
for i in GIDBASEFROM UIDBASEFROM GIDBASETO UIDBASETO; do
(($i > 0)) || syntax "Could not determine base/offset of subordinate UID/GID range"
done
for i in GIDSIZEFROM UIDSIZEFROM GIDSIZETO UIDSIZETO; do
(($i > 0)) || syntax "Could not determine length of subordinate UID/GID range"
done
echo "Going to migrate container: $CONTAINER"
echo -e "\tfrom user $USERFROM ($HOMEFROM): subUID=${UIDBASEFROM}..$((UIDBASEFROM+UIDSIZEFROM)); subGID=${GIDBASEFROM}..$((GIDBASEFROM+GIDSIZEFROM))"
echo -e "\tto user $USERTO ($HOMETO): subUID=${UIDBASETO}..$((UIDBASETO+UIDSIZETO)); subGID=${GIDBASETO}..$((GIDBASETO+GIDSIZETO))"
while read -p "Do you want to continue? (y/N) "; do
case ${REPLY:0:1} in
y|Y)
break;
;;
*)
echo "User asked to abort."
exit 1
;;
esac
done
# Find the UIDs and GIDs in use in the container
readonly SUBGIDSFROM=$(find -H "$LXCFROM" -printf '%G\n'|sort -u)
readonly SUBUIDSFROM=$(find -H "$LXCFROM" -printf '%U\n'|sort -u)
# Change group
for gid in $SUBGIDSFROM; do
let GIDTO=$(id -g "$USERTO")
if ((gid == $(id -g "$USERFROM"))); then
echo "Changing group from $USERFROM ($gid) to $USERTO ($GIDTO)"
find -H "$LXCFROM/$CONTAINER" -gid $gid -exec chgrp $GIDTO {} +
elif ((gid >= GIDBASEFROM )) && ((gid <= GIDBASEFROM+GIDSIZEFROM)); then
let GIDTO=$((gid-GIDBASEFROM+GIDBASETO))
echo "Changing group $gid -> $GIDTO"
find -H "$LXCFROM/$CONTAINER" -gid $gid -exec chgrp $GIDTO {} +
else
echo "ERROR: Some file/folder inside '$LXCFROM/$CONTAINER' has a group not assigned to $USERFROM (assigned subordinate GIDs)."
echo -e "Use:\n\tfind -H '$LXCFROM/$CONTAINER' -gid $gid\nto list those files/folders."
exit 1
fi
done
# Change owner
for uid in $SUBUIDSFROM; do
let UIDTO=$(id -u "$USERTO")
if ((uid == $(id -u "$USERFROM"))); then
echo "Changing owner from $USERFROM ($uid) to $USERTO ($UIDTO)"
find -H "$LXCFROM/$CONTAINER" -uid $uid -exec chown $UIDTO {} +
elif ((uid >= UIDBASEFROM )) && ((uid <= UIDBASEFROM+UIDSIZEFROM)); then
let UIDTO=$((uid-UIDBASEFROM+UIDBASETO))
echo "Changing owner $uid -> $UIDTO"
find -H "$LXCFROM/$CONTAINER" -uid $uid -exec chown $UIDTO {} +
else
echo "ERROR: Some file/folder inside '$LXCFROM/$CONTAINER' has an owner not assigned to $USERFROM (assigned subordinate UIDs)."
echo -e "Use:\n\tfind -H '$LXCFROM/$CONTAINER' -uid $uid\nto list those files/folders."
exit 1
fi
done
mv "$LXCFROM/$CONTAINER" "$LXCTO/" || { echo "ERROR: failed to move to destination: ${LXCTO}/${CONTAINER}."; exit 1; }
Além dos termos de licença da rede do StackExchange, estou colocando isso no domínio público. Portanto, reutilize e modifique para qualquer finalidade, mas ela é fornecida sem garantia e não posso ser responsabilizado por seu uso ou abuso.
UsoSYNTAX: lxc-reassign-userns.sh <from-user> <to-user> <container-name>
Ele assume find
, sort
, uniq
, awk
( mawk
e gawk
devem funcionar), id
, bash
, chown
, chmod
e assim por diante estar disponível e entender todos os switches de linha de comando que está usando. Para Bash readonly
e let
e expressões aritméticas são assumidas como sendo compreendidas. Por find
é assumido +
é um terminador válido para a ação -exec
.
Esta lista provavelmente não está completa.
Backups
Sim, você pode fazer backups e restaurá-los em outro lugar, desde que você também ajuste o proprietário do arquivo e o grupo de acordo.
No entanto, supondo que você use algo como tar
, há uma ressalva: tar
irá ignorar soquetes, então $rootfs/dev/log
irá representar um problema - outros também podem criar um problema semelhante.