Безопасная работа с секретами при сборке в Docker Compose

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.
Перевод статьи подготовлен в преддверии старта курса «Web-разработчик на Python».



Когда вы собираете Docker-образ вам могут понадобиться секреты, например, пароль к приватному репозиторию пакетов. Вы не хотите, чтобы этот секрет в конечном итоге оказался в образе, потому что тогда любой, кто получит доступ к образу, получит доступ и к вашу приватному репозиторию.
Примечание: Если вы думаете «Почему бы просто не использовать переменные среды?», которые используются для секретов в рантайме при создании образа. Эта статья посвящена секретам сборки, которые используются при создании образа с помощью Docker-файла.
Более новые версии Docker поддерживают секреты с помощью экспериментального сервиса BuildKit, а в Docker Compose 1.25 и более поздних версиях уже можно создавать образы с помощью BuildKit. К сожалению, по состоянию на март 2020 года, возможность безопасной работы с секретами из Compose все еще находится в процессе разработки.

Так что же теперь делать?

В сегодняшней статье я покажу, как можно использовать один и тот же Dockerfile для безопасного создания образов с секретами, но при этом не упускать преимущества быстрой разработки с помощью Docker Compose.

Два варианта использования вашего Dockerfile


Очень удобно использовать один и тот же Dockerfile для продакшена и для локальной разработки с Docker Compose. Обычно вы используете Dockerfile вместе с функцией сборки из Compose:

version: "3.7"
services:
  yourapp:
    build:
      context: "."	

Затем вы можете сделать:

$ docker-compose up

С помощью этой команды вы можете (пере)собрать образ, а затем запустить его.
Для использования на продакшене, вы собираете образ и отправляете его с push:

$ docker build -t myimage .
$ docker push myimage

И пока все идет хорошо. Но что делать, если вам нужна сборка с секретом?

Первая попытка (небезопасная)


Допустим, у вас есть скрипт, которому нужна сборка с секретом, например, чтобы загрузить пакет Python из частного репозитория DevPI. Для простоты, мы будем просто выводить секрет с помощью use-secret.sh, чтобы показать, что он у нас есть.

#!/bin/bash
set -euo pipefail

echo "Secret is: $THEPASSWORD"

Можно простодушно передать секрет с помощью аргументов сборки Docker, поскольку они поддерживаются везде, в том числе и в Docker Compose.
Примечание: Выходя за пределы нашей дискуссии, хочу сказать, что использование Docker-файлов в этой статье – не лучшая практика, однако излишняя сложность может помешать донести основной смысл статьи.
Поэтому, если вы захотите запустить свое приложение на Python на продакшене с Docker, вот два хороших способа это сделать:

  • Если вам нужен DIY: подробный список с примерами и ссылками
  • Если вам нужна рабочая версия как можно быстрее: шаблон, в котором учтены лучшие практики

FROM python:3.8-slim-buster
# Using ARG for build secrets is INSECURE!
ARG THEPASSWORD
COPY use_secret.sh .
RUN ./use_secret.sh

Мы можем написать docker-compose.yml, который будет передан в секрете:

version: "3.7"
services:
  yourapp:
    build:
      context: "."
      args:
        THEPASSWORD: "s3kr!t"

Для локальной работы можно запустить или собрать образ с помощью Compose:

$ docker-compose build | grep Secret
Secret is: s3kr!t

И все хорошо.

А еще мы можем собрать образ с помощью Docker, в качестве подготовки к перемещению его в реестр образов:

$ docker build -t myimage --build-arg THEPASSWORD=s3krit . | grep Secret
Secret is: s3krit

Так делать небезопасно: никогда так не делайте. Если мы решим просмотреть слои образа, то увидим секрет, лежащий в нем!

$ docker history myimage
IMAGE               CREATED              CREATED BY                                      SIZE
c224231ec30b        47 seconds ago       |1 THEPASSWORD=s3krit /bin/sh -c ./use_secre…   0B
6aef62acf0db        48 seconds ago       /bin/sh -c #(nop) COPY file:7aa28bbe6595e0d5…   62B
f88b19ca8e65        About a minute ago   /bin/sh -c #(nop)  ARG THEPASSWORD              0B
...

Любой, кто получит доступ к этому образу, узнает ваш пароль. Что в таком случае можно сделать?

Секреты BuildKit (частичное решение проблемы)


BuildKit – это новое (и все еще экспериментальное) решение для создания Docker-образов, которое помимо всего прочего добавляет поддержку безопасного использования секретов при сборке. В Docker Compose есть поддержка BuildKit с v1.25.

Но есть одна проблема: Docker Compose до сих пор не поддерживает функционал секретов BuildKit. Сейчас ведется работа над этим, однако по состоянию на март 2020 года, готовых решений нет, не говоря уже о стабильном релизе.

Поэтому мы собираемся объединить два этих подхода:

  • Docker Compose продолжит пользоваться аргументами при сборке, чтобы передавать секреты;
  • Для образа на продакшене, собранного с помощью docker build, мы используем BuildKit для передачи секретов.

Так мы сможем использовать один и тот же Dockerfile для работы локально и на продакшене.
BuildKit работает с секретами следующим образом: файл с секретами монтируется во временную директорию, пока выполняется команда RUN, например, в /var/secrets/thepassword. Поскольку он монтируется в течение выполнения команды RUN, он не будет добавлен в конечный образ.

Мы изменим файл use_secret.sh, чтобы он проверял, существует ли такой временный файл. Если существует, он использует его установки переменной среды $THEPASSWORD. Если файла не существует, то мы вернемся к переменной среды. То есть $THEPASSWORD может быть установлена с помощью BuildKit или аргументов сборки:

#!/bin/bash
set -euo pipefail
if [ -f /run/secrets/thepassword ]; then
   export THEPASSWORD=$(cat /run/secrets/thepassword)
fi

echo "Secret is: $THEPASSWORD"

Затем мы изменим Dockerfile, чтобы добавить BuildKit и смонтировать секрет:

# syntax = docker/dockerfile:1.0-experimental
FROM python:3.8-slim-buster
# Only use the build arg for local development:
ARG THEPASSWORD
COPY use_secret.sh .
# Mount the secret to /run/secrets:
RUN --mount=type=secret,id=thepassword ./use_secret.sh

Файл docker-compose.yml мы не меняем:

version: "3.7"
services:
  yourapp:
    build:
      context: "."
      args:
        THEPASSWORD: "s3kr!t"

Теперь нужно определить две переменные среды, одна из которых будет говорить Docker, что нужно использовать BuildKit, вторая, что Compose нужно использовать CLI-версию Docker и, следовательно, BuildKit. Также мы запишем секрет в файл:

$ export DOCKER_BUILDKIT=1
$ export COMPOSE_DOCKER_CLI_BUILD=1
$ echo 's3krit' > /tmp/mypassword

С Compose используем аргументы для сборки:

$ docker-compose build --progress=plain \
    --no-cache 2>&1 | grep Secret
#12 0.347 Secret is: s3kr!t

Обратите внимание, что --no-cache нужен, чтобы понять, что образ действительно пересоберется, если вы сами запустите все вышеприведенное. В реальной жизни этот параметр можно опустить. 2>&1 перенаправит stderr на stdout для корректной работы grep.

Когда мы будем готовы к сборке на продакшен, мы используем docker build с функционалом секретов из BuildKit:

$ docker build --no-cache -t myimage \
    --secret id=thepassword,src=/tmp/mypassword \
    --progress=plain . 2>&1 | grep Secret
#12 0.359 Secret is: s3krit

Безопасно ли это?


Давайте убедимся, что секрет не виден:

$ docker history myimage
IMAGE               CREATED             CREATED BY                                      SIZE
a77f3c32b723        25 seconds ago      RUN |1 THEPASSWORD= /bin/sh -c ./use_secret.…   0B
<missing>           25 seconds ago      COPY use_secret.sh . # buildkit                 160B
...

Ура! Мы передали секрет в один и тот же Dockerfile, используя Compose и docker build, и в последнем случае не раскрыли секрет из сборки.



Узнать подробнее о курсе.


Источник: https://habr.com/ru/company/otus/blog/501580/


Интересные статьи

Интересные статьи

Каждый Ангуляр разработчик видел декораторы в тайпскрипт коде. Их используют, чтобы описать Модули, сконфигурировать Dependency Injection или настроить компонент. Другими словами, декораторы испо...
Перевод статьи подготовлен специально для студентов курса «Безопасность Linux». Читать первую часть 5. Не оставляйте чувствительные данные в образах Docker Иногда при создании приложения в...
Вчерашняя научная фантастика постепенно становится реальностью. Компания Hyperstealth Biotechnology из Ванкувера разработала и запатентовала тонкий материал, обеспечивающий, по её словам, «кв...
Первая попытка Все началось с того, что я люблю ходить по конференциям и частенько хожу на них в Яндекс, Mail.ru и другие крупные компании. Однажды мне написал HR из Яндекса и попросила сделать ...
Среди людей, работающих удалённо в ИТ и не только, популярна привычка уезжать в тёплые края вроде Таиланда, Индонезии или Индии. На месяц-другой, а то и больше. Климат там приятнее, жизнь дешевле...