Docker и защита паролей

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

11 ответов


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

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

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

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

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

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


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

мы решаем с помощью docker-compose.

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

 env_file:
- .env

добавьте .env to .gitignore, затем установите учетные данные в например:

SOME_USERNAME=myUser
SOME_PWD_VAR=myPwd

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

см.:https://docs.docker.com/compose/environment-variables/#/the-env-file


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

аналогичная функция существует в kubernetes и DCOS


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

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

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

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


С настройки В1.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

надеюсь, что это помогает! Пока.


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

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

например:

$ 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

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


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

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

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

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

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


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


существует новая команда docker[1] для управления" секретами", но это работает только для кластеров Роя.

docker service create
--name my-iis
--publish target=8000,port=8000
--secret src=homepage,target="\inetpub\wwwroot\index.html"
microsoft/iis:nanoserver 

[1]https://docs.docker.com/engine/swarm/secrets/


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

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

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


пример:

Dockerfile

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

докер-сочинять.в формате YML

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

secrets:
  password:
    file: password.txt

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

docker-compose up -d

читайте далее:


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

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