Docker та --userns-remap, як керувати дозволами на обсяг для обміну даними між хостом та контейнером?


96

У docker файли, створені всередині контейнерів, мають непередбачуване право власності під час перевірки їх із хосту. Власником файлів на томі за замовчуванням є root (uid 0), але як тільки некореневі облікові записи користувачів беруть участь у контейнері та записують у файлову систему, власники стають більш-менш випадковими з точки зору хоста.

Проблема полягає в тому, що вам потрібно отримати доступ до даних обсягу з хосту, використовуючи той самий обліковий запис користувача, який викликає команди докера.

Типовими обхідними шляхами є

  • примушування користувацьких ідентифікаторів під час створення в Dockerfiles (не переносні)
  • передача UID користувача хоста docker runкоманді як змінної середовища, а потім запуск деяких chownкоманд на томах у сценарії точки входу.

Обидва ці рішення можуть дати певний контроль над фактичними дозволами поза контейнером.

Я очікував, що простори імен користувачів стануть остаточним рішенням цієї проблеми. Я провів кілька тестів із нещодавно випущеною версією 1.10 та --userns-remap, встановленими на моєму робочому столі. Однак я не впевнений, що це може полегшити власність файлів на змонтовані томи, боюся, що насправді це може бути навпаки.

Припустимо, я запускаю цей базовий контейнер

docker run -ti -v /data debian:jessie /bin/bash
echo 'hello' > /data/test.txt
exit

А потім перевірити вміст від хоста:

ls -lh /var/lib/docker/100000.100000/volumes/<some-id>/_data/

-rw-r--r-- 1 100000 100000 6 Feb  8 19:43 test.txt

Цей номер '100000' є суб-UID мого хост-користувача, але оскільки він не відповідає UID мого користувача, я все ще не можу редагувати test.txt без привілеїв. Здається, цей підкористувач не має ніякого споріднення з моїм фактичним звичайним користувачем поза докером. Це не відображено назад.

Рішення, згадані раніше в цій публікації, які полягали у вирівнюванні UID між хостом і контейнером, більше не працюють через UID->sub-UID відображення, яке відбувається у просторі імен.

Тоді, чи є спосіб запустити docker з увімкненим простором імен користувачів (для поліпшення безпеки), водночас надаючи можливість хост-користувачеві, який запускає docker, володіти файлами, створеними на томах?


Я думаю, що якщо ви збираєтеся спільно використовувати томи між хостом і контейнером, простори імен користувачів не будуть частиною рішення. Ваш другий варіант ("передача UID користувача хоста команді docker run як змінної середовища, а потім запуск деяких команд chown на томах у сценарії точки входу"), мабуть, найкраще рішення.
larsks

4
Сам Docker, здається, не заохочує використовувати томи для запису, змонтовані на хості. Оскільки я не використовую хмарну службу і використовую лише власні довірені образи, мені зараз цікаво, чи варто вигравати безпеку користувача NS варто пожертвувати такою зручністю.
Стефан К.

@ StéphaneC. Ви знайшли кращий підхід, можливо?
Вісімдесят вісім

4
На жаль, ні, невикористання простору імен користувачів та передача UID з хосту все ще є моїм варіантом вибору. Я сподіваюся, що в майбутньому буде належний спосіб скласти карту користувачів. Я сумніваюся, але все ж я тримаю очі відкритими.
Стефан К.

Відповіді:


46

Якщо ви можете заздалегідь попередньо розставити користувачів та групи, тоді можна призначити UID та GID таким конкретним чином, щоб користувачі хостів відповідали користувачам з простором імен всередині контейнерів.

Ось приклад (Ubuntu 14.04, Docker 1.10):

  1. Створіть декількох користувачів із фіксованими числовими ідентифікаторами:

    useradd -u 5000 ns1
    
    groupadd -g 500000 ns1-root
    groupadd -g 501000 ns1-user1
    
    useradd -u 500000 -g ns1-root ns1-root
    useradd -u 501000 -g ns1-user1 ns1-user1 -m
    
  2. Редагуйте вручну автоматично згенеровані підпорядковані діапазони ідентифікаторів /etc/subuidі /etc/subgidфайлів:

    ns1:500000:65536
    

    (зауважте, що немає записів щодо ns1-rootта ns1-user1через MAX_UIDі MAX_GIDобмеження в /etc/login.defs)

  3. Увімкнути простори імен користувачів у /etc/default/docker:

    DOCKER_OPTS="--userns-remap=ns1"
    

    Перезапустіть демон service docker restart, переконайтесь, що /var/lib/docker/500000.500000каталог створений.

    Тепер всередині контейнерів у вас є rootі user1, і на хості - ns1-rootі ns1-user1з відповідними ідентифікаторами

    ОНОВЛЕННЯ: щоб гарантувати, що некореневі користувачі мають фіксовані ідентифікатори в контейнерах (наприклад, user1 1000: 1000), створюйте їх явно під час побудови зображення.

Пробна поїздка:

  1. Підготуйте каталог томів

    mkdir /vol1
    chown ns1-root:ns1-root /vol1
    
  2. Спробуйте з контейнера

    docker run --rm -ti -v /vol1:/vol1 busybox sh
    echo "Hello from container" > /vol1/file
    exit
    
  3. Спробуйте від господаря

    passwd ns1-root
    login ns1-root
    cat /vol1/file
    echo "can write" >> /vol1/file
    

Не портативний і схожий на хакерство, але працює.


3
Дуже цікаво і заслуговує на +1. Але вам все одно потрібно переконатися, що користувачу1 на вашому зображенні присвоєно UID 1000. В іншому випадку ви не можете бути впевнені, що він отримає UID 501000 на хості. До речі, ми абсолютно впевнені, що формула завжди subUID lower bound + UID in imageтака, якщо ми запускаємо багато різних зображень з користувачем, ідентифікатор якого встановлений на 1000?
Стефан К.

@ StéphaneC. Гарна думка! Додано примітку про виправлення ідентифікаторів усередині зображень. Що стосується формули, я буду експериментувати далі зі своїми власними зображеннями і
оновлю

1
Якщо ви влаштовуєте користувачів та групи вручну в хості та в контейнерах, чи дійсно вам потрібна функція "простір імен користувачів"?
Трістан

1
Створений вами простір імен відокремлює користувачів хостів від користувачів контейнерів, але вам може знадобитися кілька просторів імен для контейнерів, особливо коли офіційні зображення (як-от mysql) створюють користувача без явного uid. Як ви маєте справу з кількома просторами імен, коли параметр --userns-remap очікує лише одного?
Трістан

2
@amartynov Чи можу я запитати, чому ви зробили труднощі із зазначенням UID (5000) для вашого користувача "ns1"? Оскільки це ім'я (не UID), на яке ви посилаєтесь у файлах subuid та subgid, здається, що це не має значення, який UID отримує цей користувач. Мені не вистачає якихось стосунків, як може свідчити подібність між 5000 і 500000?
Веселий

2

Одним з обхідних шляхів є динамічне присвоєння користувацькому ідентифікатору часу побудови відповідно до хосту.

Приклад Dockerfile:

FROM ubuntu
# Defines argument which can be passed during build time.
ARG UID=1000
# Create a user with given UID.
RUN useradd -d /home/ubuntu -ms /bin/bash -g root -G sudo -u $UID ubuntu
# Switch to ubuntu user by default.
USER ubuntu
# Check the current uid of the user.
RUN id
# ...

Потім будуйте як:

docker build --build-arg UID=$UID -t mycontainer .

і запустити як:

docker run mycontainer

Якщо у вас є контейнер, створіть контейнер-обгортку з наступним Dockerfile:

FROM someexistingcontainer
ARG UID=1000
USER root
# This assumes you've the existing user ubuntu.
RUN usermod -u $UID ubuntu
USER ubuntu

Це можна обернути docker-compose.ymlтаким чином:

version: '3.4'
services:
  myservice:
    command: id
    image: myservice
    build:
      context: .
    volumes:
    - /data:/data:rw

Потім побудуйте та запустіть як:

docker-compose build --build-arg UID=$UID myservice; docker-compose run myservice

1
Я не хотів би виглядати недружньо, але це насправді одне з обхідних шляхів, перерахованих у вихідному питанні, але не рішення і не пов’язане з просторами імен користувачів.
Стефан К.

@ StéphaneC. Чи можете ви прокоментувати це питання? stackoverflow.com/questions/60274418 / ...
overexchange

-1

Ви можете уникнути проблем з дозволом за допомогою docker cpкоманди .

Право власності встановлюється для користувача та основної групи в пункті призначення. Наприклад, файли, скопійовані в контейнер, створюються за UID:GIDдопомогою кореневого користувача. Файли, скопійовані на локальну машину, створюються за UID:GIDдопомогою користувача, який викликав docker cpкоманду.

Ось ваш приклад, переключений на використання docker cp:

$ docker run -ti -v /data debian:jessie /bin/bash
root@e33bb735a70f:/# echo 'hello' > /data/test.txt
root@e33bb735a70f:/# exit
exit
$ docker volume ls
DRIVER              VOLUME NAME
local               f073d0e001fb8a95ad8d919a5680e72b21a457f62a40d671b63c62ae0827bf93
$ sudo ls -l /var/lib/docker/100000.100000/volumes/f073d0e001fb8a95ad8d919a5680e72b21a457f62a40d671b63c62ae0827bf93/_data
total 4
-rw-r--r-- 1 100000 100000 6 Oct  6 10:34 test.txt
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS                          PORTS               NAMES
e33bb735a70f        debian:jessie       "/bin/bash"         About a minute ago   Exited (0) About a minute ago                       determined_hypatia
$ docker cp determined_hypatia:/data/test.txt .
$ ls -l test.txt 
-rw-r--r-- 1 don don 6 Oct  6 10:34 test.txt
$ cat test.txt
hello
$ 

Однак, якщо ви просто хочете прочитати файли з контейнера, названий том вам не потрібен. Цей приклад використовує іменований контейнер замість іменованого тому:

$ docker run -ti --name sandbox1 debian:jessie /bin/bash
root@93d098233cf3:/# echo 'howdy' > /tmp/test.txt
root@93d098233cf3:/# exit
exit
$ docker cp sandbox1:/tmp/test.txt .
$ ls -l test.txt
-rw-r--r-- 1 don don 6 Oct  6 10:52 test.txt
$ cat test.txt
howdy
$ 

Я вважаю названі томи корисними, коли хочу скопіювати файли в контейнер, як описано в цьому питанні .


Але docker cpпередбачає дублювання даних. Більше того, згідно з документом, при копіюванні даних у контейнер він встановлює ідентифікатори власності відповідно до кореневого користувача, який часто не є обліковим записом, що запускає контейнерну програму. Я не бачу, як це вирішує нашу проблему.
Стефан К.

Ви маєте рацію, @ Stéphane, це передбачає дублювання даних. Однак копіювання файлів дозволяє призначити різні права власності та дозволи на хості та в контейнері. docker cpнадає вам повний контроль над правом власності на файл, коли ви передаєте архів tar в контейнер або з нього. Ви можете налаштувати право власності та дозволи кожного запису у файлі tar під час потокової передачі, таким чином, ви не обмежуєтесь кореневим користувачем.
Дон Кіркбі,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.