image
В этой статье один из сотрудников нашей компании Сергей Полунин 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, но в данном случае у нас публичный репозиторий.
image

А также добавим наш сервер SonarQube:
image

Кроме этого, установим плагины для работы с docker и SonarQube.

Автоматизация 101


Теперь давайте автоматизируем то, что у нас и так есть. Мы хотим, чтобы контейнер собирался по инструкции из Dockerfile, который лежит у нас в github.com, где, кстати, лежат файлы самого нашего приложения. Затем собранный образ нужно закинуть в DockerHub и уже потом запустить наш контейнер на веб-сервере.
Сделаем в Jenkins простой пайплайн, в котором опишем эти четыре шага. Предварительно в настройках пайплайна не забудем указать, что весь исходный код у нас хранится в репозитории на github.com:
image

Итак, шаг первый, получим необходимые файлы из 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
...


Всё готово, теперь запустим наш пайплайн:
image

Отлично, теперь сборку и доставку новой версии можно осуществлять полностью автоматически, как только появится что добавить в образ. Никакого больше ручного ввода команд!

Добавим безопасности


Теперь было бы здорово интегрировать в этот пайплайн несколько инструментов, которые бы проверяли наше веб-приложение. В самом простом варианте нужно 3 инструмента:
— Static Application Security Testing (SAST), он же статический анализатор кода,
— Dynamic Application Security Testing (DAST), он же динамический анализатор кода,
— какое-нибудь решение для проверки самого контейнера.
И поскольку бюджет нашего проекта всё еще не превышает нуля рублей, мы возьмем бесплатные инструменты, т.е. соответственно SonarQube, OWASP ZAP и Trivy.
Давайте добавим их в наш пайплайн.
SonarQube я установил на отдельный сервер, создал там простой quality gate, который требует, чтобы количество багов было не более 1, а количество серьёзных проблем не более 5:
image

Теперь после того, как код будет загружен из 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"
}

Здесь всё чуть менее сурово, нам достаточно будет отчёта о сканировании. Тем более что прерывать пайплайн уже нет смысла, приложение уже развернуто и доступно нашим клиентам.
Запустим, что получилось:
image

Отлично, наш образ автоматически был собран, проверен и развернут на удаленном сервере. Стоп, и это всё? Конечно же, нет! Это только самое начало. Мы ещё можем:
  • добавить инструменты в наш пайплайн;
  • заставить Jenkins собирать и доставлять новый контейнер, как только на гитхабе кто-то сделает коммит;
  • добавить дополнительные плейбуки Ansible для настройки различных аспектов: от самих контейнеров до сервера, на котором они запускаются;
  • протестировать другие SAST/DAST и совместно с разработчиками и решить, какие лучшие использовать или даже комбинировать;
  • перейти от запуска отдельных контейнеров к Kubernetes;
  • написать более сложные политики и quality gate;
  • сделать отдельные пайплйаны для тестовых и продуктивных сред;
  • и многое другое.

В любом случае, если вы самостоятельно попробуете сделать такой пайплайн для своих задач, то скорее всего, лучше других сможете сформулировать, что же вы хотите в итоге получить в вашем конкретном случае. Но даже внедрение этих нескольких инструментов наверняка существенно повысят уровень безопасности ваших продуктов.
Материал подготовил сотрудник компании «Газинформсервис» Сергей Полунин, блог Сергея можно почитать по ссылке.

Комментарии (2)


  1. Gutt
    09.11.2021 19:54
    +2

    Скачаем GPG-ключ:
    wget –q –O – pkg.jenkins.io/debian/jenkins.io.key | sudo apt-key add –

    У вас редактор заменил дефисы на тире.


    1. Gazinformservice Автор
      12.11.2021 16:57

      Большое спасибо, поправим.