Прямой ответ
Приватный реестр пакетов решает три задачи: размещение внутренних пакетов, кеширование публичных и контроль того, что попадает в сборку. Без него внутренние пакеты распространяются копированием файлов, а состав устанавливаемого определяется внешним реестром.
Настройка клиента выполняется через адрес индекса:
# pip.conf
[global]
index-url =
Установка после этого обращается только к внутреннему индексу. Параметр extra-index-url добавляет дополнительный источник:
[global]
index-url =
extra-index-url =
Именно второй вариант создаёт основную опасность.
Путаница зависимостей (dependency confusion). При наличии двух индексов клиент выбирает пакет по наибольшей версии, а не по приоритету источника. Если внутренний пакет с именем billing версии 1.2.0 существует в приватном реестре, а злоумышленник опубликует в публичном реестре пакет billing версии 99.0.0, установка возьмёт публичный.
Защита — отказ от дополнительного индекса при наличии внутреннего:
# безопасно: только внутренний индекс, который проксирует публичный
[global]
index-url =
Внутренний индекс при этом выступает прокси: он отдаёт собственные пакеты и загружает публичные по мере обращения, кешируя их. Имя внутреннего пакета не может быть разрешено из внешнего источника, поскольку внешний источник не участвует в разрешении; о рисках — в статье про supply chain.
Три режима работы приватного индекса:
| Режим | Что содержит | Когда применяется |
|---|---|---|
| Только внутренние пакеты | Собственные пакеты | Дополняется публичным индексом |
| Прокси с кешем | Публичные пакеты + кеш | Ускоряет установку, экономит трафик |
| Прокси с внутренними | Оба типа в одном индексе | Рекомендуемый вариант |
Кеширование даёт дополнительный эффект: пакет, загруженный один раз, доступен при недоступности внешнего реестра, и его содержимое не может измениться задним числом.
Эксплуатация приватного индекса
Индекс становится критичной инфраструктурой: его недоступность останавливает сборку всех проектов, использующих внутренние пакеты.
Резервное копирование. Хранилище внутренних пакетов копируется наравне с базами данных. Потеря индекса означает невозможность собрать прежние версии сервисов, поскольку дистрибутивы внутренних пакетов нигде больше не хранятся.
Мониторинг. Контролируется доступность индекса, время ответа прокси и объём кеша. Рост времени ответа прокси означает деградацию внешнего источника либо исчерпание ресурсов.
Ротация кеша. Кешированные публичные пакеты занимают место, и его объём требует ограничения. При этом удаление закешированной версии может сделать недоступной старую сборку, поэтому ротация учитывает срок хранения версий.
Журналирование. Журнал обращений показывает, какие пакеты запрашиваются и из каких конвейеров. Необычный запрос — признак неверной конфигурации либо попытки получить пакет, которого нет в разрешённом наборе.
Обновление самого индекса. Программное обеспечение индекса требует обновлений, а его остановка на время обновления блокирует сборку. Обновление выполняется так же, как обновление любого другого сервиса.
Отдельный аспект — доступ из конвейеров. Учётные данные для публикации внутренних пакетов выдаются конвейеру, а не разработчику, и ограничиваются конкретным хранилищем.
Практика: настройка приватного реестра
1. Используйте один индекс вместо основного и дополнительного. Единственный источник устраняет путаницу зависимостей как возможность.
2. Настройте проксирование публичного реестра. Внутренний индекс загружает публичные пакеты по мере обращения и кеширует их.
3. Разделяйте индексы по типу пакетов. Внутренние пакеты в отдельном хранилище, проксируемые — в другом; клиент видит их как один индекс.
4. Публикуйте внутренние пакеты в приватный индекс. Распространение внутренних пакетов файлами лишает их версионирования и контроля; о публикации — в статье про PyPI.
5. Фиксируйте версии с контрольными суммами. Блокировка с хешами дополняет контроль источника проверкой содержимого; о механизме — в статье про lock-файлы.
6. Ограничьте права на публикацию. Публикация в приватный индекс выполняется из конвейера, а не с машины разработчика.
7. Настройте резервное копирование индекса. Потеря индекса делает невозможной сборку всех проектов, зависящих от внутренних пакетов.
8. Ведите журнал загрузок. Необычный запрос к публичному индексу при настроенном прокси — признак неверной конфигурации клиента.
Рекомендации:
- Проверяйте конфигурацию клиента в конвейере. Переменная окружения с дополнительным индексом может переопределить файл конфигурации.
- Не полагайтесь на имена как на защиту. Имя внутреннего пакета не предотвращает публикацию такого же имени в публичном реестре.
- Проверяйте установку в чистом окружении. Установка только из внутреннего индекса подтверждает отсутствие внешних источников.
- Учитывайте задержку первого обращения. Пакет, которого нет в кеше, загружается из внешнего источника, что увеличивает время первой установки.
- Различайте кеш и разрешённый набор. Кеш ускоряет установку, но не заменяет контроль того, какие пакеты допустимы.
Практический сценарий: попытка подмены внутреннего пакета через публичный реестр
Контекст: в журнале прокси обнаружился запрос к публичному реестру за пакетом, который является внутренним. Конфигурация клиента содержала дополнительный индекс.
- Диагностика. Один из сервисов настраивался с
extra-index-urlдля доступа к публичным пакетам. Внутренний индекс использовался как основной, но разрешение выполнялось по обоим источникам. - Причина. Дополнительный индекс добавлялся как временное решение до настройки проксирования и не был убран. Приоритета источников клиент не учитывает — выбирается наибольшая версия.
- Действия. (а) Настроили проксирование публичного реестра во внутреннем индексе; (б) удалили дополнительный индекс из конфигурации всех сервисов; (в) добавили проверку конфигурации в конвейер: наличие дополнительного индекса считается ошибкой; (г) проверили журнал загрузок за месяц и убедились в отсутствии установленных внешних пакетов с внутренними именами; (д) добавили блокировку с контрольными суммами для всех сервисов.
- Результат. Разрешение зависимостей выполняется только из внутреннего индекса, а подмена имени из внешнего источника стала невозможной.
Вывод: дополнительный индекс в конфигурации клиента отменяет контроль, который даёт приватный реестр. Защита от путаницы зависимостей достигается единственным источником с проксированием публичного реестра, а не приоритетом индексов, который клиент не учитывает.
FAQ
Зачем нужен приватный реестр, если есть PyPI? Для размещения внутренних пакетов, кеширования публичных и контроля состава устанавливаемого. PyPI не может содержать внутренние пакеты.
Чем опасен extra-index-url? Разрешение выполняется по всем индексам, и выбирается наибольшая версия. Это позволяет подменить внутренний пакет публичным с большим номером версии.
Нужно ли кеширование публичных пакетов? Да. Кеш ускоряет установку, экономит трафик и обеспечивает доступность при недоступности внешнего реестра.
Как проверить, что установка идёт только из внутреннего индекса? Установкой в чистом окружении с проверкой конфигурации и журнала обращений прокси.
Источники: pip docs (pip install), devpi docs, Python Packaging Guide — ссылки в шапке.