понедельник, 12 августа 2013 г.

Используем travis-ci.org для сборки debian пакетов с github.

Раз уж мы все равно используем travis-ci.org для тестов наших open-source программ, и раз в процессе тестов эти программы собираются, то почему бы не сделать еще один-два шага в том же направлении?

Так появилась мысль поручить travis-ci.org еще и сборку deb пакета, и deploy этого пакета в репозиторий.

Рассмотрим на простом примере.
Есть у нас вот такая чудесная программа: https://github.com/korjavin/zbackup про которую я обязательно напишу еще и  отдельно.

При появлении нового коммита в репозитарии github, travis-ci делает ряд действий, а именно:
а) Ставит зависимости
б) Выполняет команды:  cmake . && make

Добавим к этой программе правила сборки пакета для debian.
К счастью это очень просто, команда dh_make создаст для нас шаблоны файлов в каталоге debian/ которые мы немного исправим под свои нужды.

а) Обязательно исправим changelog, добавим туда версию. Именно она будет фигурировать в названии собранного пакета.
б) Впишем зависимости и описание пакета в control файл
остальное по вкусу.

Теперь, собрать deb пакет (без крипто подписи издателя) можно командой "dpkg-buildpackage  -us -uc"
Запомним ее, и перейдем к подготовке хранилища для deb пакета.

Насколько я понимаю travis-ci хранит файлы только во время сборки. Каждый раз он создает чистое окружение, разворачивает в нем зависимости и выполняет команды описаные в .travis.yml , после чего все очищает. Плоэтому после завершения его работы, доступа к deb пакету у нас не будет. Поэтому мы должны куда то его скопировать.

Для этих целей у меня есть микро-инстанс в amazon ec2.
На самом деле конечно неважно какой внешний сервер будет "получать" этот пакет, но стоит подумать вот о чем.
Все файлы внутри репозитория, и все логи выполнения команд на сервере travis-ci.org доступны публично.
Это значит что какую бы информацию мы туда не поместили, она будет доступна третьей стороне. Т.е. если там будет команда копирования deb пакета на сервер ec2 , злоумышленник ее увидит. Скопирует нам нужный ему пакет,  а мы его поставим на все свои стопицот машин и заразим их неизвестным кодом.

Как сделать так, что б команда переданная открытыми каналами, не была доступна третим лицам?

Ну, ответ мне известен только один. Асиметричная криптография.

При подключении репозитория github.com к travis-ci.org последний создает пару ключей, закрытй и открытый. Закрытый достeпен только ноде на который идет сборка, а публичный мы можем получить.

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

Подробности про ключи здесь: http://about.travis-ci.org/docs/user/encryption-keys/

Мы воспользуемся готовой программой https://github.com/travis-ci/travis
Она извлечет публичный ключ проекта, и зашифрует нашу информацию.

Итак, приступим к практике.
На своем ec2, я создаю отдельного пользователя repo, генерирую ему пару ключей, прописываю в authorized_keys, и приватный ключ заливаю в приватный gist github.
Ссылку , точнее clone url этого приватного gist-а , я скармливаю программе travis (gem install travis):

travis encrypt GIST=https://gist.github.com/123avnj1231121.git --add

и получаю в своем .travis.yml файле новую строку,
env:
  global:
  - secure: LEgkrieZtpJQKOWgfg3VVt85Ecx8vrqzI1d7jCPZZBB1SEeqm6VeROgRmYx7p8x2NDiOTfgtiA2zL67fcljm/60x2tE0f1A3/32RyW2V26yXEfUeNxusYeeZt19XG6hTYOqWiHVTtPc8E3xkm6mTylIqMbcdSYhYU5ADS4zsksY=

Таким же образом я шифрую другие вспомогательтные строки, а именно url для заливки файла с помощью scp на мой сервер, и dns имя моего ec2 инстанса для ssh.
travis  encrypt SCP=repo@ec2-11-111-111-211.eu-west-1.compute.amazonaws.com:/home/repo/..../  --add

travis encrypt SSH=repo@ec2-11-111-111-211.eu-west-1.compute.amazonaws.com --add


Теперь, нода на которой будет выполнятся скрипт из моего проекта, будет иметь доступ к этой информации, но больше никто.
Если же кто то форкнет мой проект и подключит его к travis-ci от своего имени, то приватный ключ изменится, и он все равно не получит доступа к этой информации.

На этом с криптографией все, осталось лишь подготовить ec2 и создать скрипт для travis-ci.

На eс2 я уже заранее создал каталог repo в котором будут хранится deb пакеты.
Поставил nginx , и настроил алиас на этот каталог.


        location ...../.../repo/ {
                root /home/.../.../repo/;
                autoindex on;
                allow all;
        }

Также ставлю пакет dpkg-dev, он понадобится для команды dpkg-scanpackages которой мы будем создавать файл Packages.gz

Итак, как будет работать наш скрипт сборки и копирования

# собираем пакет
dpkg-buildpackage  -us -uc
# Достаем из приватного gist-а ключ и меняем права на него
git clone $GIST ../keys && chmod 400 ../keys/id_rsa 
# Ловкий трюк, запрещаем ssh проверять подписи хостов, иначе она не сможет работать неинтерактивно, а будет запрашивать подверждения
mkdir -p ~/.ssh/ && echo "StrictHostKeyChecking no" >> ~/.ssh/config  
 #копируем deb пакет используя приватный ключ и расшифрованный на ноде путь SCP
scp -q -B -o User=repo -i ../keys/id_rsa ../zbackup_1.1_amd64.deb $SCP
# Запускаем по ssh команду пересканировать пакеты
  ssh -q -i ../keys/id_rsa $SSH 'cd .../repo; dpkg-scanpackages . | gzip -9c > Packages.gz' 

Теперь, после каждого нового push в github репозиторий, travis-ci.org будет собирать deb пакет, безопасно копировать его на ec2 сервер, и генерировать правильный Packages.gz

Все что нам осталось, это прописать на наши сервера репозиторий для apt.
Для этого в файле /apt/sources.list добавим строку
deb http://ec2-11-111-111-211.eu-west-1.compute.amazonaws.com /