Настраиваем Git server hook в GitLab On-Premise для защиты кода от вмешательства злоумышленников

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Привет, Хабр!

Представь себе ситуацию:

Пятница. Прямо как сегодня. Конец рабочего дня. Релиз готов, пройдены последние тесты. Кнопка «Опубликовать» нажимается, и релиз растекается по серверам обновлений и дальше по серверам клиентов.

Суббота. Саппорт завален тикетами вида: «После вчерашнего обновления при формировании отчета XXX выскакивает картинка Warhammer 40k. Эта фича не была заявлена в обновлениях и в документации не описана».

Воскресенье. Чат продукта после диагностики проблемы.

Тимлид: Женя, ты зачем закоммитил картинку с warhammer40k?!
Женя: Да я вообще в отпуске вторую неделю, ты чего, какой hammer40k?
Тимлид: Ну вот же, смотри, в понедельник от тебя коммит через webide!
Женя: Всю неделю провел в тайге. Ел мох и грибы. Какой коммит, спутниковой связи даже не было!
Тимлид: Похоже, это неЖеня от имени Жени...

Как убедиться в том, что коммиты в продуктовых репозиториях «настоящие», то есть отправлены тем человеком, имя которого указано в коммите? Мы с коллегами из команды DevOps задались целью построить процесс, который будет давать нам полностью прозрачную картинку, и у нас это получилось. Эта статья довольно практическая, и решение, о котором я, Рамазан Ибрагимов, вместе с моим коллегой Александром Паздниковым пишу в этом материале, — лишь часть большой схемы по обеспечению безопасности. В качестве хранилища кода будем опираться на инстанс GitLab On-Premise внутри компании — вендора ПО. Будем рады обсудить, как подобные задачи решаете в своей инфраструктуре вы. 

Знакомимся. Злоумышленник и его цели

Итак, перед нами злоумышленник. Он прошел внешний периметр защиты компании, закрепился внутри сети и получил доступы одного из разработчиков. Зачем ему это? Дело в том, что в большинстве случаев исполняемый код попадает в кодовую базу репозиториев продукта через коммиты разработчиков с их рабочих машин.

Злоумышленник хочет:

  1. Добавить вредоносный или открывающий уязвимость код в релиз продукта компании.

  2. Через продукты компании развить атаку на инфраструктуру клиентов.

  3. Реализовать недопустимые события для клиентов.

В итоге получаем крайне негативный веерный сценарий. Такой сценарий трудно отслеживается и детектируется средствами мониторинга, потому что выглядит «настоящим» и нормальным.

Вернемся все же к злоумышленнику, который уже внутри сети компании. Как он сможет (и сможет ли?) влить вредоносный код на корпоративный GitLab On-Premise? Основных сценариев три.

  1. C захваченной машины вливает нужный ему код через веб-интерфейс GitLab.

  2. C захваченной машины вливает нужный ему код через git push по протоколу HTTPS в репозиторий.

  3. Добавляет новый SSH public key в учетную запись разработчика на GitLab и вливает код с любой машины через git push по SSH в репозиторий.

А что же git? А у git для проверки достоверности коммитов есть механизм подписи коммитов. GitLab умеет задним числом обрабатывать запушенные коммиты и отмечать коммиты с проверенными подписями статусом Verified в своей WebUI. Только это слабо помогает, потому что в процессе CI/CD требуется проверять, что кодовая база отмечена статусом Verified. А что делать, если Verified на деле оказался совсем не Verified?

Таким образом, проверка коммитов на достоверность задним числом, после попадания в GitLab-репозиторий, добавляет кучу головоломок и сценариев на обработку на стороне CI/CD.

Как изначально быть уверенными, что весь код в GitLab-репозиториях гарантированно имеет статус Verified в подписях коммитов разработчиков? Принимать только подписанный код в GitLab-репозитории и отвергать неподписанный.

Как защититься от лжекоммитов

Отвергать прием неподписанных коммитов

Первым приходит на ум каким-то образом обязать разработчиков подписывать код. Для этого будем проверять подписи коммитов в момент пуша в GitLab-репозитории при помощи Git server hooks. По умолчанию такого хука у GitLab нет. Написать самим выглядит посильной задачей. Решаемо.

Блокировать возможность использовать поддельные ключи

Исключаем возможность подделать пары ключей для подписи, выпустив новую пару ключей и прикинувшись разработчиком. Простой механизм GnuPG нам для этого не подходит. Публичная часть находится в профиле разработчика и аналогична добавлению SSH public key для идентификации пользователя при git push через SSH. Можно выпустить новую пару GnuPG, подложить в профиль разработчика и подписывать и пушить код от его имени нелегитимной парой GnuPG. Заметить и задетектить такой коммит крайне сложно.

Зато есть альтернатива GnuPG — это цепочки сертификатов PKI X.509. Развернув свой корневой сертификат (CA), мы сможем выписывать сертификаты для конкретных людей и проверять подписи по цепочке доверия до сертификата корневого CA вместо доверия конечной паре ключей подписи. В итоге злоумышленнику нужно выпустить новый сертификат на нашем CA или украсть с рабочей машины разработчика его ключ. И тот и другой сценарий выполнить незаметно на порядок сложнее. Решаемо.

Управлять выпуском сертификатов

Хотим держать под полным контролем небольшой группы людей создание новых пар ключей для подписи коммитов. Для GnuPG придется создать какой-то свой keyring или аналогичное хранилище допустимых публичных частей проверки подписи. А в PKI X.509 это решено из коробки.

При компрометации сертификата легко отозвать сертификат через стандартный CRL в PKI X.509.

Отзывать сертификат ключа подписи коммитов

Для решения задачи контроля выпуска сертификатов и их отзыва хорошо подходит стандартный PKI X.509.

Ну и вишенкой на торте стала фича в GitLab 12.8+ проверки подписей коммитов через корневой сертификат X.509 и отображения статуса Verified для коммитов в GitLab WebUI.

Проверять подписи коммитов

Все нужные нам сценарии по управлению сертификатами решены в техстеке PKI X.509. Что же мы сделали: 

  1. Подняли свой CA.

  2. Подготовили скрипты для выписывания сертификатов конечных разработчиков.

  3. Написали глобальный Git server hook для проверки подписей всех коммитов в пуше по стеку PKI X.509 и установили его на инстанс GitLab. Для проверки знаем только корневой сертификат и проверяем дальше сертификаты конечных пользователей в коммитах, а также автоматом и CRL на отзыв сертификата.

  4. Сконфигурировали GitLab нужным образом для проверки коммитов и отображения статуса Verified через корневой сертификат CA.

  5. За управление выписыванием/отзывом сертификатов отвечает небольшая централизованная группа сотрудников в ИТ. Просто так выписать дублирующий сертификат уже не получится.

Общая схема работы

Упрощенная схема работы процесса
Упрощенная схема работы процесса

Как мы внедрили выбранное решение

Нужно было раздать под тысячу сертификатов. Разработчики используют различные ОС, иногда достаточно экзотические для нас дистрибутивы Linux. Если Debian/Ubuntu и Windows мы смогли протестировать на себе и отладить большинство нюансов, то с редко встречающимися у нас дистрибутивами Mint, Arch, Fedora и другими помогали разбираться сами пользователи этих систем и сводить в FAQ для таких же пользователей. Всего было выписано уже более двух тысяч сертификатов.

Сначала ввели проверку подписей на месяц в рекомендательном характере. Выявили массу нюансов конкретных ОС и зафиксировали основной FAQ по решению подписи на конкретных версиях ОС.

Затем уже вводили блокирующую проверку подписей, и, в принципе, все прошло достаточно гладко.

Из минусов — потерялась возможность изменений через GitLab Web IDE. Такова плата за безопасность кодовой базы.

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

Количество обращений с подписями коммитов и сертификатами через 2-3 месяца начало стремиться к нулю (очень редко случается, что коллеги бывают невнимательны, но мы работаем над этим).

Исключения

Да, конечно, нам пришлось ввести исключения в проверки подписей. И эти исключения всегда рассматриваются комитетом безопасности по допустимости рисков. В исключения попадают только репозитории, не участвующие в кодовой базе продуктов, и только если с подписями ну совсем никак не получается работать. Например, для определенных не ИТ-ролей: юристов, финансистов и других, далеких от git clone/commit/push. В коде серверного хука это белый список.

Настройки для вашего GitLab On-Premise

Как видите, пока что проверка подлинности коммитов работает не «из коробки». Когда-нибудь GitLab добавит эту фичу, по меньшей мере запрос на нее уже есть. А пока вы можете взять кодовую базу нашего Commit Signature Verifier и инструкции по его настройке тут. Пользуйтесь на здоровье и делайте свою кодовую базу заведомо безопасной.

Источник: https://habr.com/ru/companies/pt/articles/771022/


Интересные статьи

Интересные статьи

Рассказываем, как работать с CI/CD, о шагах при настройке сервера и о полезных командах, которые помогут в работе. Привет! Меня зовут Николай, я Backend-разработчик в РЕЛЭКС.В статье ты найдешь полез...
Исходный код программы надо визуализировать — отобразить в виде схем для лучшего понимания, изучения, осмысления, создания документации и др.Рисовать схемы вручную никто хочет — на...
Можно ли построить удобный для всех pipeline, приложив усилия один раз, а не 100? Об этом расскажет Виктория Вольферц. Она работает в БКС DevOps-инженером в управлении микросервисной архитектуры. БКС ...
Source generators (генераторы исходного кода) — это часть платформы Roslyn, которая появилась в .NET 5. Они позволяют анализировать существующий код и создавать новые файлы с исходным кодом, которые в...
Рабочий понедельник начался со следующего диалога: Руководитель (P): У тебя в команде не понятно, кто чем занимается. Я (Я): Это да, у нас нет инструмента, который бы отображал общую картину ...