Использования Traefik в качестве обратного прокси для маршрутизации трафика внутрь docker контейнеров. Использование Traefik для автоматического получения Let’s Encrypt сертификатов Использование Traefik для разграничения доступа к docker registry при помощи basic auth Все перечисленное выше будет настраиваться исключительно внутри docker-compose.yml и не потребует передачи отдельных конфигурационных файлов внутрь контейнеров. Практически все инструкции, которые есть в интернете, используют несколько дополнительных  файлов с конфигурациями, которые нужно будет скопировать в контейнер при запуске. Мы нашли способ сделать все необходимые настройки исключительно внутри compose файла. Помимо этого в интернете мало информации на тему использования traefik для контроля доступа к docker registry. Описанную ниже технику можно использовать для контроля доступа к любому приложению, реализующему Rest API. Вот ссылка на официальную статью по развертыванию docker registry. Крутим страницу вниз и видим пример развертывания через docker-compose. Я перепечатаю пример ниже: Нам предлагают терминировать https трафик прямо внутри сервиса registry, чего мы делать не будем. Мы не станем усложнять себе жизнь и копировать сертификаты внутрь сервиса. Кроме того у нас есть другие https сервисы, которым также нужны сертификаты, так что у нас уже есть единая точка входа, где происходит автоматическая генерация сертификатов для новых сервисов с помощью let's encrypt - это контейнер с traefik. Также нам предлагают использовать базовую авторизацию для доступа к registry, однако не предлагают способа разделения прав доступа. То есть авторизованный пользователь будет иметь полный доступ к сервису,  сможет читать и писать в любом  репозитории. На сайте есть пример использования nginx, но и там мы видим единственного пользователя с полными правами. В интернете мы находим идеальный пример использования nginx для авторизации и разделения прав доступа. Мы сделаем то же самое, но через traefik. Итак, приступаем.  Сперва запустим сервис registry через отдельный compose файл. Создадим новую папку “registry", в которой создадим compose файл: Вставим в файл следующее содержимое и сохраним: Запустим сервис Откроем в браузере страницу http://<IP>:5000/v2/_catalog , где <IP> - это ip адрес докер машины. В ответ увидим страницу с текстом: Значит, все работает. Если это не так - проверьте firewall. Знакомство с traefik начнем с базовой конфигурации. Позже мы добавим SSL, сжатие трафика и авторизацию с аутентификацией. Сперва запустим сервис registry через отдельный compose файл. Создадим новую папку “registry", в которой создадим compose файл: Вставим в файл следующее содержимое и сохраним: Через command передаются параметры запуска нашего приложения. Включаем доступ к dashboard в insecure режиме. Это означает, что dashboard будет доступен напрямую в точке входа с названием traefik. Если указанная точка входа traefik не настроена, она будет автоматически создана на порту 8080.  Перенаправление с порта 8080 на docker машине в аналогичный порт контейнера traefik. Эта настройка также как и предыдущая необходима, чтобы попасть в dashboard traefik Запускаем наш сервис: Открываем страницу с IP адресом докер машины и портом 8080: Мы могли бы упростить себе задачу, объединив оба сервиса в одном compose файле, но мы не будем этого делать, чтобы показать более сложный сценарий использования. В случае объединения нам не пришлось бы прописывать общие сети. Новый compose для Traefik:  Включаем докер провайдер. После этого traefik будет следить за появлением специальных меток на других контейнерах и перенастраивать все согласно этим меткам. Запрещаем автоматическое добавление HTTP сервисов и HTTP маршрутов в traefik. Если этого не сделать, то traefik опубликует все docker контейнеры, в которых есть expose порта наружу автоматически. В качестве доменного имени он будет использовать имя контейнера.  Таким образом, без этой строки мы неявно открываем публичный доступ ко всем своим контейнерам! Все, что нужно для атаки - угадать имя контейнера! Я проверил эту теорию на практике: после добавления в файл hosts строки “IP_докер_машины имя_контейнера”, страница “http://имя_контейнера" открылась в браузере. Перенаправление стандартного веб порта 80 (http) на docker машине в аналогичный порт контейнера traefik. Это нужно для обработки и маршрутизации полезного трафика. Подключение к коммутатору, обслуживающему контейнеры из другого compose файла. Дело в том, что для каждого compose файла создается виртуальный коммутатор с именем “имя_родительской_папки_default, таким образом сервисы внутри одного compose файла могут легко друг с другом взаимодействовать. Подключаем docker.sock докер машины внутрь контейнера traefik. Это необходимо, чтобы traefik мог отслеживать изменения в чужих контейнерах. Он будет перенастраивать свою конфигурацию на лету, исходя из меток, принадлежащих другим контейнерам. Новый compose для Registry:  Эта метка оповещает traefik, что данный сервис нужно опубликовать Эта метка указывает traefik, что доменное имя <REGISTRY.FQDN> необходимо связать с данным сервисом. Запросы, в заголовках которых будет указано данное имя, будут перенаправлены в текущий контейнер. Мы также можем указать порт, на который будет перенаправлен трафик, но в данном случае это делать не обязательно. Если docker файл нашего сервиса открывает наружу всего лишь 1 порт, этот порт будет выбран автоматически.  Перезапустим оба наших сервиса: Откроем в браузере страницу http://<REGISTRY.FQDN>:5000/v2/_catalog , где <REGISTRY.FQDN> - это полное доменное имя нашего сервиса, описанное в метке compose файла. В ответ увидим страницу в текстом: Значит все работает. Мы будем автоматически получать и продлять SSL сертификаты через Let's Encrypt.  Новый compose для Traefik: Меняем имя стандартного entrypoint с http на web для удобства. Добавляем автоматическое перенаправление трафика с entrypoint web на websecure. Другими словами перенаправление с HTTP на HTTPS Создаем новый entrypoint на 443 порту с именем websecure Настраиваем режим выдачи сертификатов Let’s Encrypt через http challenge Настраиваем entrypoint для http challenge Настраиваем <email> адрес для регистрации в центре сертификации Меняем стандартное расположение файла acme.json. В этот файл будут записываться выданные сертификаты. Дело в том, что стандартное расположение файла “/acme.json" в корне не позволяет хранить этот файл на подключенном томе. Перенаправление стандартного веб порта 443 (https) на docker машине в аналогичный порт контейнера traefik. Это нужно для обработки и маршрутизации полезного трафика. Подключаем именованный том для постоянного хранения SSL сертификатов. Теперь даже после пересоздания контейнера нам не придется заново получать все сертификаты.Именованный том будет храниться здесь: /var/lib/docker/volumes/<имя тома> Новый compose для Registry: Меняем entrypoint со стандартного http (web) на websecure Задаем имя резолвера для работы SSL сертификатов Перезапустим оба наших сервиса: Откроем в браузере страницу http://<REGISTRY.FQDN>:5000/v2/_catalog , где <REGISTRY.FQDN> - это полное доменное имя нашего сервиса, описанное в метке compose файла. Мы увидим, что: схема сменилась с http на https автоматически соединение защищено сертификатом выданным Let's Encrypt В случае проблем с получением сертификата, traefik будет использовать само-подписанный сертификат. Если это произошло, следует использовать команду docker logs traefik для просмотра логов. Как ни странно, маршрутизация трафика во встроенный dashboard отличается от маршрутизации трафика во внешние сервисы, запущенные в докер контейнерах. Я потратил не мало времени, пытаясь использовать те же правила, что и раньше. Новый compose для Traefik: Регистрируем роутер для направления трафика домена <traefik.fqdn> во внутренний dashboard. Явно указываем имя сервиса в который мы будем перенаправлять трафик. api@internal - это зарезервированное имя сервиса. Перенаправление в dashboard не будет работать без этой строки. Мы не указывали подобную строку в контейнере registry, так как регистрация имени сервиса и привязка роутера к сервису выполнялась автоматически. Перезапустим traefik: Откроем в браузере страницу http://<TRAEFIK.FQDN>, где <TRAEFIK.FQDN> - это полное доменное имя нашего для доступа к traefik dashboard, описанное в метке compose файла. Сжатие сильно ускоряет загрузку сайтов на клиенте. Обязательно нужно включать. Новый compose для Traefik: Регистрируем новый middleware с именем traefik-compress и функцией сжатия трафика. Этот middleware мы затем сможем использовать в любом стороннем докер контейнере.   Добавляем middleware с именем traefik-compress в цепочку обработки трафика для сервиса traefik   Новый compose для Registry: Добавляем middleware с именем traefik-compress в цепочку обработки трафика для сервиса registry   Сначала мы собираемся сгенерировать комбинацию пользователя и пароля для базовой аутентификации с использованием htpasswd. Если он у вас не установлен, вам нужно сначала сделать это (например, для сервера Ubuntu): Мы должны экранировать каждый символ “$” в нашем зашифрованном пароле (заменить $ на $$), если мы используем пароль напрямую в docker-compose.yml Пример вывода команды (результат будет разный при каждом запуске команды): Вывод команды нужно поместить в наш docker-compose.yml внутрь traefik метки, заменив  <USER-PASSWORD-OUTPUT> в примере ниже. Новый compose для Registry: Регистрируем новый middleware с именем auth и функцией авторизации. Этот middleware мы затем сможем использовать в любом стороннем докер контейнере.   Добавляем middleware с именем auth в цепочку обработки трафика для сервиса traefik   Внимание: Если вы используете переменные среды (например .env файл) в вашем docker-compose.yml вместо прямого указания <USER-PASSWORD-OUTPUT>, то  вы не должны экранировать $.  Генерация пароля в этом случае будет выглядеть так:  После перезапуска docker контейнера (docker-compose up -d) мы увидим окно базовой авторизации, когда откроем dashboard traefik в браузере.  Новый compose для Registry: Зарегистрируем на этом контейнере 2 набора роутеров и сервисов: registry - роутер и сервис с таким именем будут предоставлять полный доступ (чтение\запись) guest-registry - роутер и сервис с таким именем будут предоставлять гостевой доступ (чтение) Так же мы создаем одноименные middleware для basic авторизации и добавляем их в роутеры. Вы можете заметить, что мы добавили основного пользователя в оба набора правил. Это сделано потому, что наборы методов не пересекаются. Если сделать их пересекающимися - роутинг не будет работать как задумано. Перезапустим registry: Авторизовываемся пользователем с ограниченными правами. Делаем Get запрос - работает. Делаем Post запрос - 401. Авторизовываемся пользователем с полными правами. Делаем Get запрос - работает. Делаем Post запрос - работает. Авторизация пройдена, но сам запрос отклоняется registry, так как не является допустимым. Мы не стали подбирать правильный запрос для экономии времени. На мой взгляд traefik гораздо удобнее классического nginx, если мы живем внутри docker контейнеров. Единственная проблема, с которой мы столкнулись при миграции на traefik - это невозможность использовать отрицания в правилах маршрутизации. Подробнее о проблеме можно почитать по ссылке.