В этой статье один из сотрудников нашей компании Сергей Полунин Belowzero273 расскажет, как с помощью бесплатных инструментов можно построить простой CI/CD-пайплайн с инструментами контроля безопасности. И сделает это настолько просто, чтобы если даже вы никогда не слышали о подобном подходе, то вам захочется начать экспериментировать в этом направлении, как только появится свободное время.
— Самый популярный вопрос, который я слышу последние несколько лет от заказчиков, звучит так: «А что, так можно было?». Звучит он почти каждый раз, когда мы внедряем новый инструмент, технологию или процесс. В этом, безусловно, нет ничего удивительного – ИТ и информационная безопасность стали слишком необъятной областью даже для крупных команд специалистов. Давно прошли времена, когда можно было нанять одного крутого сисадмина, который будет во всем разбираться и быть в курсе всех трендов. Эти времена ушли, судя по всему, навсегда. Но сегодня даже для узкого специалиста сложно быть «в теме» – постоянно читать профильные блоги, телеграм-каналы, форумы, смотреть записи выступлений гуру на ютубе и тому подобное. Мы привыкаем решать проблемы определенным образом и выход за пределы «пузыря» может происходить долго и порой весьма болезненно.
А уж если заходит речь о том, что какая-то непонятная и вряд ли нужная по мнению бизнеса вещь будет стоить каких-то дополнительных денег, то желание отложить изучение появляется само собой.
Часто, даже если специалист прочитает обзорную статью о какой-то технологии, первая мысль будет в духе «Ну, это не про меня / тут слишком много всего / с чего тут вообще начать?». И дорога в тысячу ли опять начинается сами знаете с чего.
Вот как с популярным нынче DevSecOps. Термин хайповый, всем вроде надо, но с чего начать – непонятно. Даже нет единого мнения, что это конкретно такое, зато есть тонна программных продуктов, которые вроде как должны нам этот DevSecOps обеспечить.
Итак, у нас есть группа разработчиков, которые усердно создают очень нужный бизнесу Продукт™, упаковывают в docker-образ, загружают в репозиторий DockerHub, а затем благополучно запускают его где-то в облаке или просто на сервере под столом. Команда программистов пишет код, а все прочие операции вручную делает ещё один инженер. Затем клиенты подключаются к этому приложению через браузер и все довольны.
Начнем мы с установки средства автоматизации. В нашем случае это будет бесплатный Jenkins, потому что мы с вами договорились, что наш бюджет составляет ноль рублей ноль копеек.
Установка Jenkins
Установка Jenkins не должна вызвать каких-то трудностей, это обычное Java-приложение, которое мы поставим на сервер под управлением Debian 10.
Обновим репозитории:
sudo apt-get update
Установим Java:
sudo apt-get install default-jdk
Скачаем GPG-ключ:
wget-q-O-https://pkg.jenkins.io/debian/jenkins.io.key | sudo apt-key add-
И добавим репозиторий:
sudo sh –c ‘echo deb https://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list’
Теперь ещё раз обновимся и установим Jenkins:
sudo apt-get update
sudo apt-get install Jenkins
И пускай Jenkins запускается автоматически:
sudo systemctl start jenkins
sudo systemctl enable jenkins
Теперь наш Jenkins доступен по адресу localhost:8080, но его ещё предстоит разблокировать ключом, который лежит в /var/lib/jenkins/secrets/initialAdminPassword. Добро пожаловать!
Теперь нам нужно добавить две учётные записи. Одну для DockerHub, которую мы назовём docker_id, она потребуется нам для работы с hub.docker.com, а другую – ключ для SonarQube. Была бы нужна ещё одна, для github.com, но в данном случае у нас публичный репозиторий.
А также добавим наш сервер SonarQube:
Кроме этого, установим плагины для работы с docker и SonarQube.
Автоматизация 101
Теперь давайте автоматизируем то, что у нас и так есть. Мы хотим, чтобы контейнер собирался по инструкции из Dockerfile, который лежит у нас в github.com, где, кстати, лежат файлы самого нашего приложения. Затем собранный образ нужно закинуть в DockerHub и уже потом запустить наш контейнер на веб-сервере.
Сделаем в Jenkins простой пайплайн, в котором опишем эти четыре шага. Предварительно в настройках пайплайна не забудем указать, что весь исходный код у нас хранится в репозитории на github.com:
Итак, шаг первый, получим необходимые файлы из SCM (в нашем случае github.com):
stage('Clone Git repository') {
checkout scm
}
Теперь создадим образ:
stage('Build Image') {
sh 'echo Build application image'
app = docker.build("<имя_вашего_репозитория>/<имя_образа> ", "./<путь к Dockerfile> ")
}
Теперь нужно загрузить наш образ на hub.docker.com:
stage('Push image to Docker Hub') {
sh 'echo Push image to a Docker Hub'
docker.withRegistry('https://registry.hub.docker.com', 'docker_id') {
app.push("latest")
}
}
Загружаем мы с помощью учётных данных, которые до этого мы назвали docker_id, и даём нашему образу тэг latest. И наконец, запустим наш контейнер на веб-сервере:
stage('Run container') {
sh 'echo Run container'
sh 'ansible-playbook /opt/playbooks/docker_playbook.yaml -i /opt/playbooks/hosts'
}
Здесь запускается несложный плейбук Ansible, который с помощью модуля docker_container и запустит наш контейнер. Плейбук действительно крайне прост:
---
- name: Run all-your-base-image
docker_container:
name: all-your-base
image: < имя_вашего_репозитория>/<имя_образа >:latest
state: started
recreate: yes
pull: true
ports:
- "80:80"
exposed_ports:
- "80"
detach: true
container_default_behavior: compatibility
...
Всё готово, теперь запустим наш пайплайн:
Отлично, теперь сборку и доставку новой версии можно осуществлять полностью автоматически, как только появится что добавить в образ. Никакого больше ручного ввода команд!
Добавим безопасности
Теперь было бы здорово интегрировать в этот пайплайн несколько инструментов, которые бы проверяли наше веб-приложение. В самом простом варианте нужно 3 инструмента:
— Static Application Security Testing (SAST), он же статический анализатор кода,
— Dynamic Application Security Testing (DAST), он же динамический анализатор кода,
— какое-нибудь решение для проверки самого контейнера.
И поскольку бюджет нашего проекта всё еще не превышает нуля рублей, мы возьмем бесплатные инструменты, т.е. соответственно SonarQube, OWASP ZAP и Trivy.
Давайте добавим их в наш пайплайн.
SonarQube я установил на отдельный сервер, создал там простой quality gate, который требует, чтобы количество багов было не более 1, а количество серьёзных проблем не более 5:
Теперь после того, как код будет загружен из github.com, мы будем его проверять нашим сканером:
stage('SonarQube analysis') {
sh 'echo Run SAST - SonarQube analysis'
def scannerHome = tool 'sonar_scanner';
withSonarQubeEnv() {
sh "${scannerHome}/bin/sonar-scanner -Dsonar.projectKey=myapp"
}
}
stage("SonarQube Quality Gate") {
waitForQualityGate abortPipeline: true
}
При этом, если проблемы в коде будут найдены, выполнение нашего pipeline прервется.
Теперь проверим собранный контейнер. Это мы будем делать сразу после того, как наш собранный образ отправится в DockerHub:
stage('Trivy analysis') {
sh 'echo Trivy check'
sh 'trivy image --exit-code 1 --severity CRITICAL,HIGH <имя_вашего_репозитория>/<имя_образа>:latest '
}
Здесь мы указали, что в случае, если Trivy найдет проблемы уровня Critical или High, то пайплайн нужно прервать и разобраться в чем дело.
И наконец уже развернутое веб-приложение мы просканируем с помощью OWASP ZAP:
stage('OWASP ZAP analysis') {
sh 'echo Run DAST - OWASP ZAP analysis'
sh "docker run -t owasp/zap2docker-stable zap-baseline.py -t http://192.168.0.197 || true"
}
Здесь всё чуть менее сурово, нам достаточно будет отчёта о сканировании. Тем более что прерывать пайплайн уже нет смысла, приложение уже развернуто и доступно нашим клиентам.
Запустим, что получилось:
Отлично, наш образ автоматически был собран, проверен и развернут на удаленном сервере. Стоп, и это всё? Конечно же, нет! Это только самое начало. Мы ещё можем:
- добавить инструменты в наш пайплайн;
- заставить Jenkins собирать и доставлять новый контейнер, как только на гитхабе кто-то сделает коммит;
- добавить дополнительные плейбуки Ansible для настройки различных аспектов: от самих контейнеров до сервера, на котором они запускаются;
- протестировать другие SAST/DAST и совместно с разработчиками и решить, какие лучшие использовать или даже комбинировать;
- перейти от запуска отдельных контейнеров к Kubernetes;
- написать более сложные политики и quality gate;
- сделать отдельные пайплйаны для тестовых и продуктивных сред;
- и многое другое.
В любом случае, если вы самостоятельно попробуете сделать такой пайплайн для своих задач, то скорее всего, лучше других сможете сформулировать, что же вы хотите в итоге получить в вашем конкретном случае. Но даже внедрение этих нескольких инструментов наверняка существенно повысят уровень безопасности ваших продуктов.
Материал подготовил сотрудник компании «Газинформсервис» Сергей Полунин, блог Сергея можно почитать по ссылке.
Gutt
У вас редактор заменил дефисы на тире.
Gazinformservice Автор
Большое спасибо, поправим.