• Познакомьтесь с пентестом веб-приложений на практике в нашем новом бесплатном курсе

    «Анализ защищенности веб-приложений»

    🔥 Записаться бесплатно!

  • CTF с учебными материалами Codeby Games

    Обучение кибербезопасности в игровой форме. Более 200 заданий по Active Directory, OSINT, PWN, Веб, Стеганографии, Реверс-инжинирингу, Форензике и Криптографии. Школа CTF с бесплатными курсами по всем категориям.

Статья Travis как система непрерывной интеграции и доставки

Доброго времени суток, codeby. Не так давно в моем городе “отгремел” локальный хакатон в одном из универов и мне хотелось бы поделиться одним из полезнейших навыков для комфортного участия в таких мероприятиях - настройкой инфраструктуры для непрерывной доставки и развертывании.
Итак формат хакатона следующий: за отведенное время (26 часов) участникам (командам) предлагается решить одну из задач (головных болей) бизнеса (читай заказчика). Разумеется чем более готовый продукт, тем более выше шансы на успех. При таких данных, хочется максимально минимизировать затраты на прогон всех тестов и время для развертывания приложения. Хочется заняться более интересными и трудозатратными вещами: архитектурой, кодингом, анализом проблемы, поиском решения и так далее.

Статья заточена на стек .Net(Core) и React. База данных не делилась на продуктовую и тестовую (вместо этого изначально предполагалось запускать её в контейнере, но от этого решения принято было отказаться в процессе разработки, за избыточностью).

В качестве системы CI\CD был выбран Travis, за счёт простоты настройки и того факта что предоставляет бесплатно свои услуги для open source проектов, приложение разворачивалось на обычной VPS системе под debian, арендованной на (не буду рекламить, хотя хостер весьма достойный и известный местной аудитории). Небольшое замечание, в статье не рассмотрена защита самого сервера, nginx конфигураций, предполагается, что %username%, успешно может загуглить это. Мне не хотелось писать дополнительное приложение ради этой статьи - поэтому это будет просто сочетания стандартного create-react-app на фронте и стартовое приложения asp.netcore на беке. Приступим.

Репозиторий
Как и большинство CI\CD систем, Travis работает с github репозиториями (вообще не только с ними, но я люблю github) эта прелесть основана на github хуках (на случай если кто захочет написать свою ci\cd систему). Надеюсь с созданием репозитория могут справиться абсолютно все читатели данной статьи (если это не про тебя, то дальше читать не стоит).
Я создал два репозитория под статью:
Фронтенд
Начнём с фронтенд приложения. Про то как сделать настройку для react и typescript я уже писал, можно почитать в моей подписи, сейчас же применим супер способ от facebook - create-react-app.

На рабочей машинке создаём директорию, клонируем созданный репозиторий для фронтенда.

30335


Далее выполняем команду для создания react приложения.

30336


Ждём пока yarn установит все зависимости, по окончании в случае успеха получим следующее сообщение

30337


Удалим созданый create-react-app README.md файл за ненадобностью. Добавим созданный файл .gitignore, а затем всё остальное в репозиторий.
Проверим что приложение работает - выполнив команду yarn start. В результате откроется браузер по адресу localhost:3000 и мы увидим такое вот

30338


Отлично, теперь переходим к настройки Travis. Вся настройка сводится к созданию файла .travis.yml в корне репозитория, давайте воспользуемся прекрасным редактором vscode и откроем папку репозитория и создадим файл.

30339


Добавим его в индекс, закоммитаем, запушим и переключимся на настройку удаленной машины. Цепляемся по ssh…

Nginx
Замечательный легковесный веб-сервер. Юзается для всего. Прост и податлив в настройке. Настройка сводится к настройке файла nginx.config плюс минус разграничение по правам для системы.

30340


вот так в данном случае выглядит конфигурация. Этот файл мы помещаем по пути

Код:
/etc/nginx/sites-available/articleapp.ru.conf

Саму статику размещаем там где удобно не забывая поправить root в конфиге, например сюда: /home/example/www/articleapp.ru
далее делаем линкуем его с sites-enabled

Код:
ln -s /etc/nginx/sites-available/articleapp.ru.conf /etc/nginx/sites-enabled/articleapp.ru.conf

и перезапускаем nginx. Ах да, если есть домен, лучше соблюдать доменные наименования.
Ну вообщем всё просто как и обещал, проверим что всё это работает. создав html заглушку c its works.

30341


На этом с настройкой линукс машины закончили (тема с тем что у nginx свой пользователь должен быть под каждый сайт и и т.д. опущена)

Настройка Travis для Фронтенда
Переходим к настройки CI Travis, подошли к самому интересному. Итак, прежде всего нужно зайти на travis-ci.org под своим гитхаб аккаунтом.
Далее Travis предложит выбрать репозиторий

30342


Я выбираю CIfrontend - двигая свитч напротив репозитория:

30343


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

Я хочу организовать следующий процесс:
  1. Устанавливаем зависимости
  2. Запуск тестов. Если тесты прошли успешно переходим к шагу два, если нет - останавливаем цикл.
  3. Запускаем билд. Если билд успешен, переходим к деплою
  4. Запускаем деплой, если всё прошло хорошо переходим к оповещению

Итак, пошли по порядку.
Первый шаг реализуется строкой где мы указываем Travis какой язык используем (подробнее тут )

30344


тут мы также указываем версию node. Почему мы собираем на node? Для сборки react приложений нужен webpack, а ему node - всё логично. Неплохо было бы кэшировать модули которые установит yarn, так что давайте реализуем эту возможность добавив папку node_modules в кэш:

30345


Самое простое выполнено, дальше у нас идет секция скрипт, где мы уже можем управлять своим пайплайном.

30346


Помните да? Сначала тесты, потом билд. А пока мне бы хотелось подробнее рассказать про строки 9 и “--coverage && codecov”. Как многие наверное догадались - это метрика покрытия кода, существует проект codecov который собирает статистику по вашему коду вернее по тому как ваши тесты покрывают ваш код. Разумеется чем выше покрытие, тем лучше, тем больше достоверности что ваше приложение работает так как вы того ожидаете. Так вот на строке 9 мы устанавливаем раннер для проверки покрытия а затем запускаем тестирование (в данном случае jest) чтобы убедиться, что у нас всё хорошо. Я вернусь к покрытию, когда буду рассказывать о гитхаб бейджиках. Пока давайте остановится и закоммитаем travis-файл в репозиторий, мне не терпиться показать вам что случилось.
Итак оно работает

30347


только что я просто закомитал код, а тревис начал собирать мне релиз. Чудеса… Тревис выполнит свою работу выложит вам всю информацию в удобный лог, который я не буду скринить, а затем сохранит инфу о успешном билде в Build History

30348


А значит мы можем гордо забрать динамичный бейдж для нашего Readme.md - для этого составим ссылку вот такого вида (markdown)

Код:
[![Build Status](https://travis-ci.org/enterDevelop/CIfrontend.svg?branch=master)](https://travis-ci.org/enterDevelop/CIfrontend)

выглядит теперь у нас readme будет так

30349


Закоммитаем, запушем, погладим себя по голове - мы молодцы, мы заслужили пойдём намутим кофе.
Вернемся к разговору о покрытии кода тестами. Так как мы поставили пакет codecov мы можем получить ещё один бейджик с информацией о покрытии. Для этого нам нужно отредактировать вот эту вот ссылку

Код:
[![Codecov Coverage](https://img.shields.io/codecov/c/github/enterDevelop/CIfrontend/master.svg?style=flat-square)](https://codecov.io/gh/enterDevelop/CIfrontend/)

тут нужно заменить enterDevelop/CIfrontend на путь до вашего репозитория и мы получим вот такую вот картинку

30350


Теперь переходим к самой интересной на мой взгляд части - автодеплою.

Travis CD
Travis предоставляет множество способов деплоя из коробки в различные облака, хостинги и тд. Мы же пойдём путём джедаев, попутно сэкономив на облаке. Travis поддерживает деплой как как набор команд оболочки, воспользуемся этой фичей и настроим деплой по ssh. План такой:
  1. Расшарить ключ для автоконнекта тревиса к серверу
  2. Скопировать файлы
Звучит просто, но не будем столь наивны, так как, хранить в публичном репозитории ssh ключ к серверу сродни полному идиотизму, однако есть довольно действенный способ избежать этого. Мы можем хранить закриптованный ключ, для этого нам придётся воспользоваться утилитой Travis для командной строки. Установим её на linux систему (существует известная проблема если криптовать ключ с windows-тачки travis - поднимая билд на linux-тачке не сможет его расшифровать, чёрт знает почему, но об этом ребяткам не раз писали, однако на момент выхода статьи - ничего не разрешилось. Я криптую ключи на кали-виртуалке и всё прекрасно работает).
Так вот первое что нужно сделать сгенерить ключи для ssh.
Используем для этого команду

Код:
ssh-keygen -t rsa -b 4096 -C 'CD Fronted key' -f ./deployf_rsa

Далее криптуем всё это дело командой

Код:
travis encrypt-file deployf_rsa --add

Копируем публичный ключ на сервер

Код:
ssh-copy-id -p server_port -i deployf_rsa.pub login@server_ip

удаляем файлы ключи из директории

Код:
rm -f deployf_rsa deployf_rsa.pub

добавляем в репозиторий зашифрованный ключ для тревис

Код:
git add . && git commit -m ‘added ssh encrypted key’

В случае успеха в Travis кликаем на More options, выбираем Settings проматываем до секции “Environment Variables” и видим примерно такую картину:

30351


Travis создал себе ключи для расшифровки, а так же сам добавил расшифровку в файл .travis.yml:

30352


Создадим еще несколько переменных, с помощью формы ниже , для большей секьюрности. А именно server_port, server_ip, server_user так мы сможем инкапсулировать пользователя ssh (разумно будет для тревиса создать отдельного юзера). В финале должно получиться что-то такое

30353


Переходим к конфигурированию в файле travis.yml. Добавим секцию before_deploy которая отвечает за действия (очевидно) происходящие перед деплоем.

30354


на 16ой строке мы проверяем наличие ssh-agent и тот факт что он запущен (на всякий случай). Далее разрешаем доступ ко всем хостам (отключив проверку stricthostkey) тревис каждый раз поднимает новую машинку для билда, так что нам не принципиально что это не очень секьюрно. Далее мы выставляем права на расшифрованный ключ.

Далее переходим непосредственно к стадии deploy

30355


В качестве provider выбираем script - это позволит Travis исполнять команды bash во время деплоя, в секции скрипт указываем команду для копирования результатов билда:
тут важно использование переменной $TRAVIS_BUILD_DIR - это системная переменная в которой хранится путь куда Travis помещает файлы так как create-react-app билдит свои файлы в папку build мы дописываем путь и до туда. Секция on позволяет нам указать при пуше в какую ветку, мы должны провести деплой (мы же не хотим на каждый коммит отправлять файлы на сервер, верно?). Вот собственно и всё - теперь при коммите мы увидим как тревис запустит свой цикл. Закомитав и запушив мы получим следующую информацию

30356


Как видим Travis сообщил нам что деплой прошёл успешно. Проверим перейдя по адресу сервера.

30357


Вот мы и закончили с настройкой для фронтенда. Передохнем и пойдём намутим кофе.

Настройка Linux сервера для Backend приложения .NetCore
Теперь настало время заняться вторым репозиторием. Установим на машинку окружения для запуска Netcore приложений, следуя инструкциям

Далее переходим к рабочей машине, клонируем созданный пустой репозиторий для backend создаём в нём asp.netcore проект с апи для демонстрации (следим за тем, чтоб версия проекта сочеталась с версией рантайма на линукс машине). Чучуть поменяем файл Program.cs для того чтоб указать где будет запускаться наше приложение

30358


В данном случае это происходит на порту 5001. Добавляем всё в индекс гита и переходим к настройке Travis.
Возвращаемся к linux машине, напишем демона для запуска нашего dotnet приложения, а также настроим nginx.
Конфиг для nginx выглядит следующим образом

30359


Таким образом мы настроим обратный прокси для Kestrel (мы так же изменим listen порт на 82 и порт у proxy_pass на 5001)
Деплоить будем рядом с фронтенд приложением.
Проводим аналогичные мероприятия с ngnix (создаём конфигурацию, линкуем в sites-enabled), переходим к написанию демона.
Код выглядит так

30360


Сохранить данный файл нужно по пути

Код:
/etc/systemd/system/имясервиса.service

я назвал его art-test.service, теперь для включения сервиса мне нужно выполнить команду

Код:
systemctl enable art-test.service

Переходим к настройке Travis CI

Travis CI для Backend app на .NetCore
Настройка происходит аналогичным образом за исключением некоторых моментов.
Первым делом, мы точно так же добавляем репозиторий в Travis.
Мы точно так же создаём файл .travis.yml в корне проекта

30361


Как видите поменялись команды в секции скрипт и первые строки, но всё логично - мы заменили язык с Node на C# указали версию dotnet. Далее в секции скрипт мы используем dotnet restore - эта команда запустит установку всех пакетов, которые мы установим в наше приложение. Далее идёт билд и публикация конфигурации release - ничего сложного. Мы аналогичным образом генерируем ключи и шифруем их и точно так же появляется строка before install, как видите тут тоже ничего сложного.

30362


Теперь продублируем секцию before_deploy из фронтенда она тоже будет идентична

30363


Секция deploy будет аналогична фронтенду, за исключением пути к билду ( мы точно так же создаём 3 секьюрных переменных в Travis )

30364


Пожалуй мы подобрались к единственному отличию - это перезапуск нашего демона после того как тревис выполнит деплой. Для этого есть секция after_deploy, давайте добавим её

30365


Да, чуть не забыл, на линукс машине можно отключить запрос пароля для sudo при перезапуске нашего сервиса (гуглим по visudo). Ну вот и всё - пушим и проверяем что CI\CD работает.

30366


Как видим, приложение загрузилось и демон его рестартнул.

30367


А на этом у меня всё, с этими знаниями мы можем сосредоточиться на том чтоб писать код и не отвлекаться. Как всегда актуальные версии в моих репозиториях, спасибо за внимание.
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!