Наши партнеры

UnixForum





Библиотека сайта 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 -pubout3. Данная директория не должна зеркалироваться и клиенты должны получать официальный ключ напрямую из каталога PyPI или использовать его копию, предоставляемую в комплекте с клиентскими приложениями PyPI. Зеркальные сервера все же должны скачивать ключ для того, чтобы определять факт продления его срока действия.

Для каждого пакета зеркалируемая подпись находится в директории /serversig/package. Это подпись DSA для параллельной страницы с URL /simple/package в форме DER с использованием алгоритма SHA-1 с DSA4.

Клиенты, использующие зеркальные сервера, должны выполнить следующие действия для проверки пакета:
  1. Скачать страницу /simple и рассчитать ее хэш с помощью алгоритма SHA-1.
  2. Сформировать подпись DSA на основе данного хэша.
  3. Скачать соответствующий файл /serversig и побайтово сравнить его с подписью, сформированной на шаге 2.
  4. Рассчитать и проверить (сравнив со страницей /simple) хэши MD5 для всех скачиваемых с зеркального сервера файлов.

При скачивании файлов с центрального сервера проверка не требуется и клиенты должны отказаться от ее выполнения с целью снижения нагрузки.

Примерно раз в год ключ меняется на новый. Зеркальные серверы должны повторно получить все страницы /serversig после смены ключа. Клиенты, использующие зеркальные серверы, должны получить заслуживающую доверия копию ключа сервера. Одним из способов получения ключа является его загрузка с ресурса https://pypi.python.org/serverkey. Для установления факта реализации атак перехвата трафика клиенты должны проверять SSL-сертификат сервера, который должен быть подписан центром CACert.


Далее: 14.5. Подробности реализации