Запуск програми всередині Docker як некорневого користувача


77

Після вчорашніх новин про Shocker здається, що програми всередині контейнера Docker не слід запускати як root. Я спробував оновити свій, Dockerfileщоб створити користувача програми, однак зміна дозволів на файли програми (поки ще є root), схоже, не працює. Я здогадуюсь, це тому, що якийсь дозвіл LXC не надається кореневому користувачеві?

Ось мій файл Docker:

# Node.js app Docker file

FROM dockerfile/nodejs
MAINTAINER Thom Nichols "thom@thomnichols.org"

RUN useradd -ms /bin/bash node

ADD . /data
# This next line doesn't seem to have any effect:
RUN chown -R node /data 

ENV HOME /home/node
USER node

RUN cd /data && npm install

EXPOSE 8888

WORKDIR /data

CMD ["npm", "start"]

Досить просто, але коли я ls -lвсе все ще належить root:

[ node@ed7ae33e76e1:/data {docker-nonroot-user} ]$ ls -l /data
total 64K
-rw-r--r--  1 root root  383 Jun 18 20:32 Dockerfile
-rw-r--r--  1 root root  862 Jun 18 16:23 Gruntfile.js
-rw-r--r--  1 root root 1.2K Jun 18 15:48 README.md
drwxr-xr-x  4 root root 4.0K May 30 14:24 assets/
-rw-r--r--  1 root root  416 Jun  3 14:22 bower.json
-rw-r--r--  1 root root  930 May 30 01:50 config.js
drwxr-xr-x  4 root root 4.0K Jun 18 16:08 lib/
drwxr-xr-x 42 root root 4.0K Jun 18 16:04 node_modules/
-rw-r--r--  1 root root 2.0K Jun 18 16:04 package.json
-rw-r--r--  1 root root  118 May 30 18:35 server.js
drwxr-xr-x  3 root root 4.0K May 30 02:17 static/
drwxr-xr-x  3 root root 4.0K Jun 18 20:13 test/
drwxr-xr-x  3 root root 4.0K Jun  3 17:38 views/

Мій оновлений докер-файл чудово працює завдяки роз’ясненню @ creak того, як працюють томи. Після chownредагування початкових файлів npm installзапускається як некорневий користувач. І завдяки postinstallгачку, npm запускається, bower install && grunt assetsякий дбає про інші кроки встановлення та уникає будь-яких необхідних npm install -gінструментів cli вузла, таких як bower, grunt або coffeescript.


Просто цікаво, ви впевнені, що nodeкористувач створюється?
Я

@am так, користувач однозначно створений. Я, коли я бігаю docker run -it myimage /bin/bashі запускаю, whoamiя ввійшов в систему, nodeщо саме те, що я очікував.
thom_nic

Відповіді:


16

Це трохи хитро, це насправді завдяки зображенню, з якого ви починаєте.

Якщо ви подивитесь на джерело , то помітите, що /data/це том. Отже, все, що ви робите у програмі, Dockerfileбуде відкинуто та замінено під час виконання об'ємом, який потім змонтується.

Ви можете харчуватися під час виконання, змінивши CMD на щось подібне CMD chown -R node /data && npm start.


Цікаво! Я здогадуюсь, що я / не повністю перебираю концепцію гучності (я почну читати), ані різницю між часом виконання та часом побудови.
thom_nic

3
На жаль, це CMD chown...не буде працювати, оскільки це буде запущено, оскільки nodeкористувач, який obv не має дозволу змінювати дозволи файлів, що належать root. Я починаю гадати, чи нормально це, якщо вихідний код не можна записувати під час виконання, поки програма має доступ до місця для запису, наприклад для журналів та файлів, скомпільованих під час виконання. Чи можна створити том, який не належить root під час виконання?
thom_nic

Не те, що я знаю. Альтернативою було б не використовувати вузол USER, зберегти root і запустити npm з su node -c "npm start". Але, залежно від ваших потреб, нормально запускати лише для читання, поки у вас є доступ до записуваного каталогу.
скрип

1
Тож я збираюся прийняти це як правильну відповідь, тому що ви мали на увазі, що ця проблема виглядає /dataяк том. Якщо я змінив цей каталог на що-небудь інше, /opt/foobarабо /home/node/app, тоді він chownчудово працює як частина збірки. Також я підтвердив, що chown-ing тома в запущеному контейнері також, здається, працює. Я думаю, що найпростішим рішенням є не використовувати том для джерел додатків. Я оновив свій отриманий файл Docker тут: gist.github.com/thom-nic/5e561e800cbc0f71555c
thom_nic

26

Перевірте цю публікацію: http://www.yegor256.com/2014/08/29/docker-non-root.html У rultor.com ми запускаємо всі збірки у своїх власних контейнерах Docker. І кожен раз перед тим, як запускати скрипти всередині контейнера, ми переходимо до некорневого користувача. Ось як:

adduser --disabled-password --gecos '' r
adduser r sudo
echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
su -m r -c /home/r/script.sh

r користувач, якого ми використовуємо.


1
Можливо, вам доведеться явно створити домашній каталог користувача за допомогою:adduser -m --disabled-password --gecos '' r
bonh

У системах на базі Red Hat, таких як Fedora та CentOS, потрібно робити це по-іншому.
gbraad

18

Оновлення 28.09.2015

Я помітив, що цей пост привертає трохи уваги. Порада всім, хто потенційно зацікавлений зробити щось подібне. Я спробував би використовувати Python або іншу мову як обгортку для виконання скриптів. Виконуючи власні скрипти bash, у мене виникали проблеми при спробі передати різні аргументи своїм контейнерам. Зокрема, були проблеми з інтерпретацією / екрануванням символів "і" за допомогою оболонки.


Мені потрібно було змінити користувача з трохи іншої причини.

Я створив образ докера, що містить повнофункціональну установку ImageMagick та Ffmpeg, бажаючи, щоб я міг перетворити зображення / відео в моїй хост-ОС. Моя проблема полягала в тому, що це інструменти командного рядка, тому трохи складніше виконати їх через докер, а потім повернути результати назад в основну ОС. Мені вдалося дозволити це, встановивши докерний том. Здавалося, це працювало нормально, за винятком того, що вихід зображення / відео виходив як власник root (тобто користувачеві, в якому запущений контейнер докера), а не користувачеві, який виконав команду.

Я подивився на підхід, який @ François Zaninotto згадав у своїй відповіді (повний сценарій make ви можете переглянути тут ). Це було справді круто, але я віддав перевагу варіанту створення скрипта оболонки bash, який потім зареєстрував би на своєму шляху. Я взяв деякі концепції з підходу Makefile (зокрема створення користувача / групи), а потім створив сценарій оболонки.

Ось приклад мого сценарію оболонки dockermagick :

#!/bin/bash

### VARIABLES

DOCKER_IMAGE='acleancoder/imagemagick-full:latest'
CONTAINER_USERNAME='dummy'
CONTAINER_GROUPNAME='dummy'
HOMEDIR='/home/'$CONTAINER_USERNAME
GROUP_ID=$(id -g)
USER_ID=$(id -u)

### FUNCTIONS

create_user_cmd()
{
  echo \
    groupadd -f -g $GROUP_ID $CONTAINER_GROUPNAME '&&' \
    useradd -u $USER_ID -g $CONTAINER_GROUPNAME $CONTAINER_USERNAME '&&' \
    mkdir --parent $HOMEDIR '&&' \
    chown -R $CONTAINER_USERNAME:$CONTAINER_GROUPNAME $HOMEDIR
}

execute_as_cmd()
{
  echo \
    sudo -u $CONTAINER_USERNAME HOME=$HOMEDIR
}

full_container_cmd()
{
  echo "'$(create_user_cmd) && $(execute_as_cmd) $@'"
}

### MAIN

eval docker run \
    --rm=true \
    -a stdout \
    -v $(pwd):$HOMEDIR \
    -w $HOMEDIR \
    $DOCKER_IMAGE \
    /bin/bash -ci $(full_container_cmd $@)

Цей сценарій прив'язаний до зображення "acleancoder / imagemagick-full", але це можна змінити, редагуючи змінну у верхній частині сценарію.

В основному він робить це:

  • Створіть ідентифікатор користувача та групу в контейнері, щоб відповідати користувачеві, який виконує сценарій із хост-ОС .
  • Встановлює поточний робочий каталог приймаючої ОС (використовуючи томи докера) у домашній каталог для користувача, якого ми створюємо у виконаному контейнері докера .
  • Встановлює каталог tmp як робочий каталог контейнера .
  • Передає будь-які аргументи, які передаються сценарію, які потім виконуються за допомогою ' / bin / bash ' виконуваного контейнера докера .

Тепер я можу запускати команди ImageMagick / Ffmpeg проти файлів на моїй хост-ОС. Наприклад, скажімо, що я хочу перетворити зображення MyImage.jpeg у файл PNG , тепер я можу зробити наступне:

$ cd ~/MyImages
$ ls
  MyImage.jpeg
$ dockermagick convert MyImage.jpeg Foo.png
$ ls
  Foo.png MyImage.jpeg

Я також підключився до 'stdout', щоб я міг запустити команду ImageMagick identify, щоб отримати інформацію про зображення на моєму хості, наприклад:

$ dockermagick identify MyImage.jpeg
  MyImage.jpeg JPEG 640x426 640x426+0+0 8-bit DirectClass 78.6KB 0.000u 0:00.000

Існує очевидна небезпека щодо монтування поточного каталогу та дозволу передачі будь-якого довільного визначення команди для виконання. Але є також багато способів зробити сценарій більш безпечним / надійним. Я виконую це в моєму особистому невиробничому особистому оточенні, тому це не викликає у мене найбільшого занепокоєння. Але я настійно рекомендую вам взяти до уваги небезпеки, якщо ви вирішите розширити цей сценарій. Також варто зазначити, що цей сценарій не враховує хост OS X. Файл make, у якого я краду ідеї / концепції, це враховує, тому ви можете розширити цей сценарій для цього.

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

$ cd ~/MyImages
$ ls
  MyImage.jpeg
$ dockermagick convert ~/DifferentDirectory/AnotherImage.jpeg Foo.png
$ ls
  MyImage.jpeg

Найкраще просто перейти до каталогу, що містить зображення, і виконати безпосередньо проти нього. Звичайно, я впевнений, що є способи обійти це обмеження теж, але це стосується мене та моїх поточних потреб.


2
Це дуже акуратна концепція, яка використовує docker як спосіб ізоляції / порту інструментів командного рядка!
thom_nic

Це чудово! Використовуючи його зараз, нехай адаптований до Python та інтегрований у мою власну dockerобгортку.
Гонки легкості на орбіті

(Єдина проблема полягає в тому, що він встановлює певні обмеження для зображень Docker, якими ви можете скористатися; а саме, що вони підтримують усі ці команди як є).
Гонки легкості на орбіті

Радий, що ви пішли з Python, я зробив те саме і був набагато щасливішим зі своїми сценаріями. Не впевнений, що я цілком стежу за вами щодо проблеми обмежень, яку ви порушуєте, але якщо я правильно розумію, то вважаю за доцільне припустити, що вам потрібно буде налаштувати потрібні образи докера за допомогою відповідних інструментів командного рядка, які вам потрібні. Перехресне спілкування запущених
вмістів

Якщо ви отримали "помилку команди sudo не знайдено". Використовувати echo "su $CONTAINER_USERNAME -c "у функції execute_as_cmd ().
arulraj.net

6

Примітка : Я відповідаю тут, тому що, враховуючи загальний заголовок, це запитання з’являється в google, коли ви шукаєте рішення "Запуск програми в Docker як некорневий користувач". Сподіваюся, це допоможе тим, хто опинився тут на мелі.

За допомогою Alpine Linux ви можете створити такого користувача системи:

RUN adduser -D -H -S -s /bin/false -u 1000 myuser

Все, що знаходиться в Dockerfileцьому рядку, виконується за допомогою myuser.

myuser користувач має:

  • пароль не призначений
  • немає домашнього реж
  • немає оболонки для входу
  • немає кореневого доступу.

Це з adduser --help:

-h DIR      Home directory
-g GECOS    GECOS field
-s SHELL    Login shell
-G GRP      Add user to existing group
-S          Create a system user
-D          Don't assign a password
-H          Don't create home directory
-u UID      User id
-k SKEL     Skeleton directory (/etc/skel)

0

Примітка . Ця відповідь дана, оскільки багато людей, які шукають некореневого використання, опиняться тут. Обережно, це не стосується проблеми, яка спричинила проблему, але стосується заголовка та роз’яснення до відповіді, даного @ yegor256, який використовує некореневого користувача всередині контейнера. Ця відповідь пояснює, як це зробити у випадку використання, що не стосується debian / non-ubuntu. Це не стосується проблеми з обсягами.

У системах на базі Red Hat, таких як Fedora та CentOS, це можна зробити наступним чином:

RUN adduser user && \
    echo "user ALL=(root) NOPASSWD:ALL" | tee -a /etc/sudoers.d/user && \
    chmod 0440 /etc/sudoers.d/user

У вашому Dockerfile ви можете запускати команди як цей користувач, виконавши:

RUN su - user -c "echo Hello $HOME"

І команду можна запустити як:

CMD ["su","-","user","-c","/bin/bash"]

Приклад цього можна знайти тут: https://github.com/gbraad/docker-dev/commit/644c51002f4b8e6fe5bb745638542a4c3d908b16


Це не стосується питання ОП, де вони робили хаун на томі, який не стосувався їх остаточного образу. Надсилання виводу echo до труби до трійника у файлі здається дивним, чому б просто не додати за допомогою >>. А надання користувачеві повного доступу sudo до root знищує всі переваги запуску контейнера як некорневого користувача.
BMitch

Це пов’язано з відповіддю, яку дав @ yegor256. Мені не вдалося це пояснити в розділі коментарів ... Я включу це у відповідь на адресу
gbraad

Оновлена ​​інформація: gbraad.nl/blog/non-root-user-inside-a-docker-container.html
gbraad
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.