Библиотека сайта rus-linux.net
Архитектура системы управления пакетами в Python
Глава 14 из 1 тома книги "Архитектура приложений с открытым исходным кодом".
Оригинал: Python Packaging
Автор: Tarek Ziade
Дата публикации: 7 Июня 2012 г.
Перевод: А.Панин
Дата публикации перевода: 3 апреля 2013 г.
Creative Commons. Перевод был сделан в соответствие с лицензией Creative Commons. С русским вариантом лицензии можно ознакомиться здесь.
14.4. Усовершенствованные стандарты
14.4.4. Усовершенствования каталога PyPI
Как я говорил ранее, каталог PyPI может оказаться единой точкой отказа. Стандарт PEP 380 направлен на устранение данной проблемы и описывает протокол зеркалирования, позволяющий пользователям обращаться к альтернативным серверам в случае неработоспособности центрального сервера PyPI. Целью данных усовершенствований является предоставление возможности членам сообщества вводить в строй зеркальные серверы по всему миру.
Рисунок 14.6: Зеркалирование
Список зеркал формируется в виде списка имен узлов в форме X.pypi.python.org
, где X
является последовательностью буквенных символов a,b,c,...,aa,ab,...
. Сервер с именем a.pypi.python.org
является мастер-сервером, а имена зеркальных серверов начинаются с символа b. Запись CNAME last.pypi.python.org
указывает на имя последнего узла, поэтому клиенты, использующие PyPI, могут составить список зеркальных серверов, получив запись CNAME.
h.pypi.python.org
, а это значит, что каталог PyPI на данный момент использует 6 серверов зеркал (обозначенных символами от b до h):
>>> import socket >>> socket.gethostbyname_ex('last.pypi.python.org')[0] 'h.pypi.python.org'
Теоретически данный протокол позволяет клиентам осуществлять переадресацию запросов на ближайший к ним зеркальный сервер, устанавливая расположение серверов на основе их IP-адресов, а также переходить к другому зеркальному серверу в случае неработоспособности зеркального сервера или мастер-сервера. Протокол зеркалирования сам по себе является более сложным, чем простой протокол rsync, так как мы хотели получать точную статистику скачиваний и поддерживать минимальные меры безопасности.
Синхронизация
Зеркальные сервера должны снижать объем данных, передаваемых между центральным и зеркальным сервером. Для достижения этой цели они должны использовать вызов changelog
интерфейса XML-RPC PyPI и обновлять только те пакеты, содержимое которых было изменено после последней проверки. Для каждого пакета P зеркальными серверами должны быть скопированы документы из директорий /simple/P/
и /serversig/P
.
Если пакет был удален на центральном сервере, на зеркальных серверах этот пакет также должен быть удален вместе со всеми ассоциированными файлами. Для определения модификации файлов пакетов зеркальные сервера могут кэшировать параметр ETag для каждого файла и запрашивать файл с использованием заголовка If-None-Match
, не принимая сам файл. Как только синхронизация завершается, зеркальный сервер помещает текущую дату в файл /last-modified
.
Распространение статистических данных
Когда вы скачиваете релиз с одного из зеркал, информацию о скачивании передается мастер-серверу PyPI и другим зеркальным серверам по соответствующему протоколу. Этот принцип позволяет быть уверенным в том, что люди или инструменты, просматривающие каталог PyPI в поисках количества скачиваний релиза, получат значение, просуммированное по всем зеркальным серверам.
Статистические данные обрабатываются и заносятся файлы формата CSV со статистикой за день и за неделю, расположенные в директории stats
на центральном сервере PyPI. Каждый зеркальный сервер должен использовать директорию local-stats
для хранения своей собственной статистики. Каждый файл содержит данные о количестве скачиваний для каждого архива, сгруппированные по используемым заголовкам "User-Agent". Центральный сервер ежедневно посещает зеркальные сервера для сбора их статистических данных и добавления их в файлы из глобальной директории stats
, поэтому каждый зеркальный сервер должен обновлять содержимое директории /local-stats
как минимум раз в день.
Подлинность зеркальных серверов
- компрометацию центрального каталога
- подмену данных на зеркальных серверах
- атаку перехвата данных между центральным сервером и конечным пользователем или между зеркальным сервером и конечным пользователем
Для установления факта реализации первого типа атаки авторы пакетов должны подписывать свои пакеты с помощью ключей PGP, позволяя таким образом пользователям проверять, выпущен ли пакет автором, которому они доверяют. Протокол зеркалирования сам по себе предусматривает меры борьбы только со второй угрозой, хотя в нем и предпринята попытка определения факта реализации атак перехвата данных.
На центральном сервере в директории /serverkey
хранится ключ DSA в формате PEM, сгенерированный с помощью команды openssl dsa -pubout
3. Данная директория не должна зеркалироваться и клиенты должны получать официальный ключ напрямую из каталога PyPI или использовать его копию, предоставляемую в комплекте с клиентскими приложениями PyPI. Зеркальные сервера все же должны скачивать ключ для того, чтобы определять факт продления его срока действия.
Для каждого пакета зеркалируемая подпись находится в директории /serversig/package
. Это подпись DSA для параллельной страницы с URL /simple/package
в форме DER с использованием алгоритма SHA-1 с DSA4.
- Скачать страницу
/simple
и рассчитать ее хэш с помощью алгоритма SHA-1. - Сформировать подпись DSA на основе данного хэша.
- Скачать соответствующий файл
/serversig
и побайтово сравнить его с подписью, сформированной на шаге 2. - Рассчитать и проверить (сравнив со страницей
/simple
) хэши MD5 для всех скачиваемых с зеркального сервера файлов.
При скачивании файлов с центрального сервера проверка не требуется и клиенты должны отказаться от ее выполнения с целью снижения нагрузки.
Примерно раз в год ключ меняется на новый. Зеркальные серверы должны повторно получить все страницы /serversig
после смены ключа. Клиенты, использующие зеркальные серверы, должны получить заслуживающую доверия копию ключа сервера. Одним из способов получения ключа является его загрузка с ресурса https://pypi.python.org/serverkey
. Для установления факта реализации атак перехвата трафика клиенты должны проверять SSL-сертификат сервера, который должен быть подписан центром CACert.
Далее: 14.5. Подробности реализации