ユーザー間で権限のないLXCコンテナの移行

ユーザー間で権限のないLXCコンテナの移行

LXCホストとして機能するUbuntu 14.04サーバーがインストールされています。 user1とuser2という2人のユーザーがいます。

user1は、ディレクトリ(/ home / user1 / .local / ...内部)をバックアップストアとして使用する権限のないLXCコンテナを所有しています。

user2のコンテナの完全なコピーを作成するには?このファイルには、100000から100000+の範囲のマップされた所有者があり、その所有者はuser1にバインドされているためコピーできません。

また、これは基本的に同じ質問だと思います。後で他のコンピュータやユーザーから復元できるように、user1のLXCコンテナをどのように安全にバックアップしますか?

答え1

私は今何をすべきかを知っています。この説明がわからない場合は、返信を送信して下部にユーザーに提供した内容も必ずお読みください。

予備仮説

あなたの質問から拡張された次の仮定に固執します。

  1. user1ホストにはaとaがありますuser2。情報が特定の情報に限定されない場合は使用します。userX
  2. コンテナの名前は、レンダリングする変数によって指定されます。$container
  3. user1とのホームフォルダは、user2Bashでsumという表記で提供されています。~user1~user2
  4. 簡潔にするために、依存UIDとGIDの範囲が100000..165536user1と200000..265536であるとします。user2
  5. ルートFSフォルダは、終了位置に関係なくとして$containerレンダリングされます()。$rootfs~userX/.local/share/lxc/$container/rootfs
  6. コンテナ構成のデフォルト値は次のとおりです。~userX/.local/share/lxc/$container/config

コンテナの移動

コンテナの管理に関連する2つのデータがありますuserns

  1. フォルダを構成するファイル/フォルダの所有者とグループ$container
  2. /etc/sub{uid,gid}スレーブUIDとGIDは、ユーザーアカウント(タスクを介してusermod --{add,del}-sub-{uid,gid}s)と設定() lxc.id_mapの2つの場所に割り当てられます。$container~userX/.local/share/lxc/$container/config
    • コンテナ構成では、コンテナごとに異なる範囲を定義することが可能かどうかはわかりません。たとえば、ホストユーザーがuserX65536の依存GIDとUIDを持っている場合、5000〜65の異なるコンテナを割り当てることは可能ですが、その仮定をテストしませんでした。
    • しかし、確かなことは、この設定がサブネームスペースの有効なGIDおよびUID範囲であるLXCと通信することです。

したがって、重要なのは、コンテナのファイル/フォルダの所有者とグループが設定と一致することを確認する必要があります。これは、それぞれにuser1割り当てられたホストスレーブGID / UIDの有効なサブセットでなければならないことですuser2

たとえば、Bashを使用している場合は、$((expression))算術式に使用し、let算術式を変数に割り当てることができます。これは、「内部」ユーザーのデフォルト値(それぞれ100000と200000)とGID / UIDを知っている場合に便利です。

主な点は次のとおりです。

  1. これは可能です
  2. どちらか能力CAP_CHOWNまたはスーパーユーザー権限が必要です。

これはより多くの改善が必要なスクリプトです(たとえば、ルート生成コンテナから権限のないコンテナへの移行)が、次の目的で機能します。

#!/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 : "\$1 ~/$USERFROM/ {print \$2}" /etc/subgid)
readonly UIDBASEFROM=$(awk -F : "\$1 ~/$USERFROM/ {print \$2}" /etc/subuid)
readonly GIDSIZEFROM=$(awk -F : "\$1 ~/$USERFROM/ {print \$3}" /etc/subgid)
readonly UIDSIZEFROM=$(awk -F : "\$1 ~/$USERFROM/ {print \$3}" /etc/subuid)
readonly GIDBASETO=$(awk -F : "\$1 ~/$USERTO/ {print \$2}" /etc/subgid)
readonly UIDBASETO=$(awk -F : "\$1 ~/$USERTO/ {print \$2}" /etc/subuid)
readonly GIDSIZETO=$(awk -F : "\$1 ~/$USERTO/ {print \$3}" /etc/subgid)
readonly UIDSIZETO=$(awk -F : "\$1 ~/$USERTO/ {print \$3}" /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; }

StackExchange Networkのライセンス条件に加えてパブリックドメインに入れます。したがって、いかなる目的でも再使用および修正することができますが、保証は提供されず、使用または誤用について責任を負いません。

使用法
SYNTAX: lxc-reassign-userns.sh <from-user> <to-user> <container-name>

find、、、、、、sortなどuniqが利用可能awkで動作しなければならないとmawk仮定し、使用中のすべてのコマンドラインスイッチを理解します。 Bash の合計と算術式の場合、理解が想定されます。 For isは、演算の有効な終端者と見なされます。gawkidbashchownchmodreadonlyletfind+-exec

このリストは完全ではないかもしれません。

サポート

はい、それに応じてファイルの所有者とグループを調整している限り、他の場所からバックアップして復元できます。

しかし、似たようなものを使用すると仮定するとtar注意が必要です。tarソケットが無視され、$rootfs/dev/log問題が発生します。他の人も同様の問題に遭遇する可能性があります。

リソース:

答え2

fuidshiftこの目的のために作られました。 LXDの一部だそうです。

http://manpages.ubuntu.com/manpages/xenial/man1/fuidshift.1.html

答え3

編集する: 流体送達最良の方法です。 Ubuntuでは、LXDはDEBパッケージからスナップに変換するため、流体送達もはや出荷がなく、これは起こりません。あなたはコンパイルする必要があります流体送達自分で。

ただし、これは簡単に実行できます(ソースコードのダウンロードとコンパイルはほとんど自動的に行われます)。https://github.com/lxc/lxc/issues/3186

-

LXCコンテナを含むディレクトリをuser1からuser2にコピーし、次のPythonコードを使用してUIDとGIDを移動します。

#!/usr/bin/python3

import os
import sys

uidmap_start = 100000
uidmap_size = 65536

gidmap_start = 100000
gidmap_size = 65536


def changeUidGidRecursive(path):
  changeUidGid(path)
  if os.path.isdir(path) and not os.path.islink(path):
    for filename in os.listdir(path):
      sub_path = os.path.join(path, filename)
      changeUidGidRecursive(sub_path)

def changeUidGid(path):
  stat_info = os.lstat(path)
  uid = stat_info.st_uid
  gid = stat_info.st_gid
  new_uid = uid + uidmap_start
  new_gid = gid + gidmap_start
  if (new_uid > uidmap_end):
    print("Info: New UID %d for \"%s\" would be out of range. Not changing UID." % (new_uid, path))
    new_uid = uid
  if (new_gid > gidmap_end):
    print("Info: New GID %d for \"%s\" would be out of range. Not changing GID." % (new_gid, path))
    new_gid = gid
  if (new_uid != uid or new_gid != gid):
    mode = stat_info.st_mode
    os.chown(path, new_uid, new_gid, follow_symlinks=False)
    new_mode = os.lstat(path).st_mode
    # If necessary, restore old mode
    if (new_mode != mode):
      os.chmod(path, mode)

if __name__ == '__main__':
  uidmap_end = uidmap_start + uidmap_size
  gidmap_end = gidmap_start + gidmap_size

  base_path = ''
  if len(sys.argv) > 1:
    base_path = sys.argv[1]
  else:
    print("Usage: %s <path>" % (sys.argv[0]))
    sys.exit(1)

  if not os.path.exists(base_path):
    print("Error: Path \"%s\" does not exist" % (base_path))
    print("Exiting")
    sys.exit(1)
  changeUidGidRecursive(base_path)
  sys.exit(0)

お客様は適応し、uidmap_start必要に応じて適応する必要gidmap_sizeがあります。uidmap_sizegidmap_size

私はこのPythonコードを使用して、権限のあるLXCコンテナを権限のないコンテナに移行します。 Pythonコードはシェルスクリプトよりも速く実行されます。

関連情報