Докер и защита паролей

162

Недавно я экспериментировал с Docker над созданием некоторых сервисов, с которыми можно поиграться, и одна вещь, которая меня постоянно раздражает, это вставка паролей в Dockerfile. Я разработчик, поэтому хранение паролей в исходном коде похоже на удар по лицу. Должно ли это быть проблемой? Есть ли хорошие соглашения о том, как обрабатывать пароли в Dockerfiles?

anthonator
источник
7
На Github есть открытый вопрос, в котором запрашиваются передовые практики в отношении Docker и секретов, проблема здесь: github.com/docker/docker/issues/13490
Луис Бьянчин

Ответы:

93

Определенно это проблема. Файлы Docker обычно регистрируются в репозиториях и передаются другим людям. Альтернативой является предоставление любых учетных данных (имена пользователей, пароли, токены и т. Д.) В качестве переменных среды во время выполнения . Это возможно с помощью -eаргумента (для отдельных переменных в CLI) или --env-fileаргумента (для нескольких переменных в файле) для docker run. Прочитайте это для использования среды с docker-compose.

Использование --env-file, безусловно, более безопасный вариант, так как это защищает от секретов, отображаемых в psжурналах или в журналах, если таковые используются set -x.

Однако env vars также не особенно безопасны. Они видны через docker inspect, и, следовательно, они доступны любому пользователю, который может запускать dockerкоманды. (Конечно, любой пользователь, имеющий доступ к dockerхосту, также имеет права root ).

Мой предпочтительный шаблон - использовать скрипт-обертку в качестве ENTRYPOINTили CMD. Сценарий-оболочка может сначала импортировать секреты из внешнего местоположения в контейнер во время выполнения, а затем запустить приложение, предоставив секреты. Точная механика этого зависит от вашей среды выполнения. В AWS вы можете использовать комбинацию ролей IAM, службы управления ключами и S3 для хранения зашифрованных секретов в корзине S3. Что-то вроде HashiCorp Vault или credstash - это еще один вариант.

AFAIK Не существует оптимального шаблона для использования конфиденциальных данных в процессе сборки. На самом деле, у меня есть вопрос по этой теме. Вы можете использовать docker-squash для удаления слоев с изображения. Но для этого в Docker нет встроенной функциональности.

Вы можете найти полезные комментарии к конфигурации в контейнерах .

Бен Уэйли
источник
Как отмечено в других комментариях, будет 2 слоя (после ADD и после первого RUN), которые содержат .configфайл.
Петр Гладких
1
Да, переменные env, кажется, лучший путь. Я смотрел на это в контексте разработки TDDing Dockerfile.
gnoll110
5
Я обеспокоен тем, что если ваш пароль является переменной env, он появляется в docker inspect.
тонкий
Установка Docker по умолчанию (в Linux) требует привилегий sudoer для запуска docker inspect. Если злоумышленник уже может выполнить sudo, выхватывание вашего пароля из проверки докера, вероятно, занимает довольно мало места в вашем списке вещей, которые теперь могут пойти не так. Эта конкретная деталь кажется мне приемлемым риском.
GrandOpener
7
@GrandOpener Это относится только к ситуации, когда злоумышленник использует вашу систему. Если я помещаю образ докера в репозиторий, и он извлекается кем-то другим, мне все равно, есть ли у них sudo в их собственной системе, но мне совершенно безразлично, видят ли они в env секреты, которых там больше не должно быть.
vee_ess
75

Наша команда избегает ввода учетных данных в репозитории, так что это означает, что они не допускаются Dockerfile. Нашей лучшей практикой в ​​приложениях является использование кредитов из переменных среды.

Мы решаем для этого, используя docker-compose.

Внутри docker-compose.ymlвы можете указать файл, который содержит переменные среды для контейнера:

 env_file:
- .env

Убедитесь в том , чтобы добавить .envв .gitignore, а затем установить учетные данные в пределах .envфайла , как:

SOME_USERNAME=myUser
SOME_PWD_VAR=myPwd

Храните .envфайл локально или в безопасном месте, где остальная часть команды сможет его взять.

Смотрите: https://docs.docker.com/compose/environment-variables/#/the-env-file

theUtherSide
источник
15
Вы также можете сделать это без файла .env, если хотите. Просто используйте свойство среды в вашем файле docker-compose.yml. «Переменные среды, имеющие только ключ, преобразуются в их значения на компьютере, на котором работает Compose, что может быть полезно для секретных или специфичных для хоста значений».
Д. Виссер
1
дайте этому человеку печенье! :) да, это действительно хорошая практика. Я просто хочу добавить, что docs.docker.com/compose/env-file это должно работать автоматически, но в docker compose version 2 кажется, что вам нужно объявить это, как описано в этом ответе.
эквивалент 8
5
Использование переменных окружения не рекомендуется самой командой Docker, так как env var можно увидеть через / proc / <pid> / environment и docker inspect. Это только запутывает способ получения учетных данных для злоумышленника, получившего root-доступ. Конечно, учетные данные никогда не должны отслеживаться CVS. Я полагаю, что единственный способ помешать получению привилегированного пользователя - это прочитать учетные данные из веб-приложения (в надежде, что оно не обновляет файл proc-среды) из зашифрованного файла, процесс расшифровки безопасно запрашивает пароль. Я думаю, что попробую с гробницей: github.com/dyne/Tomb
pawamoy
.gitignoreчтобы .envфайл с конфиденциальной информацией не регистрировался в GitHub. Я почти уверен, что это не сработает, если вы добавите его.dockerignore
theStherSide
привет @ theUtherSide, спасибо за ваш ответ, у меня возник вопрос, когда я не проверяю .envфайл и не выполняю развертывание на сервере в помещении, вы предлагаете снова создать .envфайл на сервере вручную?
opensource-разработчик
37

Docker сейчас (версия 1.13 или 17.06 и выше) имеет поддержку для управления секретной информацией. Вот обзор и более подробная документация

Подобная особенность существует в kubernetes и DCOS

Хизер КК
источник
Некоторые полезные команды из приведенных выше ссылок:: docker secret createсоздать секрет docker secret inspect: показать подробную информацию о секрете docker secret ls: просмотреть все секреты docker secret rm: удалить конкретный --secretфлаг секрета для docker service create: создать секрет во время создания сервиса --secret-addи --secret-rmфлаги для docker service update: обновить значение секрета или удалить секрет во время обновления сервиса. Секреты Docker в покое защищены на узлах менеджера и предоставляются рабочим узлам при запуске контейнера.
PJ
7
Да, вам нужно настроить рой, чтобы использовать секреты Docker
Heather QC
11
Это хорошее начало для ответа, но ему нужно гораздо больше информации из той, которая связана, чтобы появиться в самом ответе.
Джефф Ламберт
7
Не уверен, что это может быть принятый ответ, если он работает только с роями. Многие люди не используют рои, но все же должны передавать секреты.
Иоанн
9

Никогда не следует добавлять учетные данные в контейнер, если вы не согласны с передачей кредитов тому, кто сможет загрузить изображение. В частности, выполнение и ADD credsпозже RUN rm credsне является безопасным, поскольку файл creds остается в конечном изображении на уровне промежуточной файловой системы. Любой, имеющий доступ к изображению, может легко извлечь его.

Типичное решение, которое я видел, когда вам нужны кредиты для проверки зависимостей, например, использование одного контейнера для создания другого. То есть обычно у вас есть базовая среда сборки в базовом контейнере, и вам нужно вызывать ее для сборки контейнера приложения. Поэтому простое решение - добавить исходный код приложения, а затем RUNкоманды сборки. Это небезопасно, если вам нужны кредиты в этом RUN. Вместо этого вы помещаете свой источник в локальный каталог, запускаете (как в docker run) контейнер для выполнения шага сборки, когда локальный каталог источника монтируется как том, а кредиты либо внедряются, либо монтируются как другой том. После того, как шаг сборки завершен, вы создаете свой окончательный контейнер, просто ADDиспользуя локальный исходный каталог, который теперь содержит встроенные артефакты.

Я надеюсь, что Docker добавляет некоторые функции, чтобы упростить все это!

Обновление: похоже, что в будущем будет использоваться метод построения вложенных сборок. Вкратце, файл dockerfile будет описывать первый контейнер, который используется для построения среды выполнения, а затем вторую сборку вложенного контейнера, которая может собрать все части в конечный контейнер. Таким образом, материал во время сборки не находится во втором контейнере. Это Java-приложение, в котором вам нужен JDK для сборки приложения, но только JRE для его запуска. Обсуждается ряд предложений, лучше всего начать с https://github.com/docker/docker/issues/7115 и перейти по некоторым ссылкам для получения альтернативных предложений.

TVE
источник
7

Альтернативой использованию переменных среды, которые могут стать беспорядочными, если их много, является использование томов, чтобы сделать каталог на хосте доступным в контейнере.

Если вы поместите все свои учетные данные в виде файлов в эту папку, тогда контейнер сможет читать файлы и использовать их по своему усмотрению.

Например:

$ echo "secret" > /root/configs/password.txt
$ docker run -v /root/configs:/cfg ...

In the Docker container:

# echo Password is `cat /cfg/password.txt`
Password is secret

Многие программы могут считывать свои учетные данные из отдельного файла, поэтому таким образом вы можете просто указать программе один из файлов.

Malvineous
источник
5

решение только во время выполнения

docker-compose также предоставляет решение не в режиме роя (начиная с v1.11: секреты с использованием bind mounts ).

Секреты смонтированы в виде файлов ниже с /run/secrets/помощью docker-compose. Это решает проблему во время выполнения (запуск контейнера), но не во время сборки (сборка образа), поскольку /run/secrets/не монтируется во время сборки. Кроме того, это поведение зависит от запуска контейнера с docker-compose.


Пример:

Dockerfile

FROM alpine
RUN cat /run/secrets/password
CMD sleep inifinity

докер-compose.yml

version: '3.1'
services:
  app:
    build: .
    secrets:
      - password

secrets:
  password:
    file: password.txt

Чтобы построить, выполните:

docker-compose up -d

Дальнейшее чтение:

Murmel
источник
2

В Docker v1.9 вы можете использовать инструкцию ARG для извлечения аргументов, переданных из командной строки, в образ при действии сборки . Просто используйте флаг --build-arg . Таким образом, вы можете избежать сохранения явного пароля (или другой разумной информации) в Dockerfile и передавать его на лету.

источник: https://docs.docker.com/engine/reference/commandline/build/ http://docs.docker.com/engine/reference/builder/#arg

Пример:

Dockerfile

FROM busybox
ARG user
RUN echo "user is $user"

команда построения образа

docker build --build-arg user=capuccino -t test_arguments -f path/to/dockerfile .

во время сборки распечатать

$ docker build --build-arg user=capuccino -t test_arguments -f ./test_args.Dockerfile .

Sending build context to Docker daemon 2.048 kB
Step 1 : FROM busybox
 ---> c51f86c28340
Step 2 : ARG user
 ---> Running in 43a4aa0e421d
 ---> f0359070fc8f
Removing intermediate container 43a4aa0e421d
Step 3 : RUN echo "user is $user"
 ---> Running in 4360fb10d46a
**user is capuccino**
 ---> 1408147c1cb9
Removing intermediate container 4360fb10d46a
Successfully built 1408147c1cb9

Надеюсь, поможет! До свидания.

NickGnd
источник
26
Согласно документации Docker's ARG : «Не рекомендуется использовать переменные времени сборки для передачи таких секретов, как ключи github, учетные данные пользователя и т. Д.»
Lie Ryan
3
Просто удивляясь, почему Docker рекомендует использовать --build-arg var=secretдля передачи закрытого ключа SSH в образ, обоснование не задокументировано. Кто-нибудь может это объяснить?
Хенк Вирсема
2
@HenkWiersema Информация о процессе, журналы и история команд небезопасны. Информация о процессе доступна публично и включает все параметры командной строки. Часто эти вызовы попадают в журналы, которые также могут быть открытыми. Злоумышленники нередко проверяют информацию о запущенных процессах и проверяют секретные файлы в открытых логах. Даже если он не является общедоступным, он может быть сохранен в истории команд, что облегчит кому-то получение секретов через неадминистративную учетную запись.
Tu-Reinstate Моника-Дор Дух
2
Каков рекомендуемый способ предоставления учетных данных, которые необходимы во время сборки? Например, изображение, которое нуждается в доступе aws s3 для извлечения большого набора данных, который будет находиться внутри изображения?
Ely
4
Я предполагаю, что причина, по которой это не рекомендуется, состоит в том, что docker historyвыставляет build-arg/ ARGпеременные. Можно вытащить любое изображение, проверить его и увидеть все секреты, переданные во время сборки, в качестве параметра build-arg/ ARG.
vee_ess
2

Мой подход, кажется, работает, но, вероятно, наивен. Скажи мне, почему это неправильно.

ARG, установленные во время сборки докера, выставляются подкомандой history, поэтому идти туда не нужно. Однако при запуске контейнера переменные среды, указанные в команде run, доступны для контейнера, но не являются частью образа.

Итак, в Dockerfile выполните настройку, которая не использует секретные данные. Установите CMD что-то вроде /root/finish.sh. В команде run используйте переменные среды для отправки секретных данных в контейнер. finish.shпо существу использует переменные для завершения задач сборки.

Чтобы упростить управление секретными данными, поместите их в файл, который загружается программой Docker, запущенной с --env-fileкоммутатором. Конечно, держите файл в секрете. .gitignoreи тому подобное.

Для меня finish.shработает программа на Python. Он проверяет, чтобы убедиться, что он не запускался раньше, а затем завершает настройку (например, копирует имя базы данных в Django settings.py).

Киран Мэтисон
источник
2

Появилась новая команда docker для управления «секретами». Но это работает только для скоплений роя.

docker service create
--name my-iis
--publish target=8000,port=8000
--secret src=homepage,target="\inetpub\wwwroot\index.html"
microsoft/iis:nanoserver 
Хосе Ибаньес
источник
1

Методология приложение 12-фактор говорит, что любая конфигурация должна храниться в переменных окружения.

Docker compose может выполнять подстановку переменных в конфигурации, так что он может использоваться для передачи паролей от хоста к докеру.

Bunyk
источник
Я ценю ссылку на Библию.
JakeCowton
-2

Хотя я полностью согласен, простого решения не существует. Там продолжает быть единственная точка отказа. Либо dockerfile, etcd и так далее. У Apcera есть план, который выглядит как кореш - двойная аутентификация. Другими словами, два контейнера не могут общаться, если нет правила конфигурации Apcera. В их демонстрации uid / pwd был в открытом виде и не мог быть повторно использован, пока администратор не настроил связь. Однако, чтобы это работало, это, вероятно, означало исправление Docker или, по крайней мере, сетевого плагина (если есть такая вещь).

Ричард
источник
2
Есть ли где-нибудь ответ на заданный вопрос?
Абхиджит Саркар