Процесс DevOps состоит из нескольких важных этапов: разработки, сборки, тестирования и собственно выпуска в продуктивную среду. Однако, после того, как протестировали решение, нам необходимо пометить полученный артефакт (например, образ Docker) в доверенное хранилище. При этом, каждый пользователь, загрузивший наш артефакт должен быть уверен в том, что он загрузил действительно то, что хотел.
Проект Notary, первоначально спонсируемый компанией Docker, призван обеспечить высокий уровень доверия к цифровому контенту с помощью механизма надежных криптографических подписей. Помимо обеспечения происхождения программного обеспечения, он также предоставляет гарантии того, что контент не будет изменен без одобрения автора в процессе доставки потребителю.
Это позволяет системам более высокого уровня, таким как Docker Enterprise Edition (EE) с Docker Content Trust (который использует Notary), устанавливать четкую политику использования контента. Например, можно установить политику, согласно которой только подписанный контент может быть использован во время выполнения и развертывания средствами оркестрации Docker. В целом Notary является ключевым элементом в подходе Docker к безопасной цепочке поставок, при котором безопасность плавно и единообразно встраивается в рабочий процесс от разработки до эксплуатации.
Давайте посмотрим подробнее как работает Notary и как его можно использовать на практике.
В чем проблема?
С помощью Notary любой пользователь может доверять произвольным коллекциям данных. Используя пару закрытых и открытых ключей, Notary может подписывать и проверять цифровые артефакты, хранящиеся в реестрах, совместимых с OCI (Open Container Initiative), например образы контейнеров, спецификации программного обеспечения или результаты сканирования. После подписания эти артефакты можно перемещать по различным реестрам OCI без потери доверия к целостности артефакта.
Для того, чтобы было понятно о чем идет речь рассмотрим небольшой пример. Допустим мы подготовили некоторый образ Docker для последующей передачи его клиентам. Однако в нашем хранилище неаккуратно настроены права доступа, в результате чего злоумышленник смог подменить это образ на свой, в результате чего, клиенты скачали «чужой» образ, который в итоге скомпрометировал их данные.
Использование Notary позволяет избежать подобных неприятностей и снизить вероятность попадания скомпрометированных артефактов в рабочую среду. По сути Notary это один из инструментов обеспечения процессов DevSecOps, которые являются логичным развитием DevOps с добавлением безопасности.
Разобравшись с тем, зачем нужен Notary, давайте развернем данное решение.
Настройка локального реестра контейнеров
Прежде чем приступить к работе, вам понадобится реестр контейнеров, в который будут поступать и из которого будут извлекаться образы. Для этого мы воспользуемся реестром с открытым кодом Distribution.
Данный реестр поддерживает хранение образов контейнеров с использованием спецификации OCI distribution. Он представляет собой простой, безопасный и масштабируемый частный реестр, идеально подходящий для демонстрации Notary.
Выполните следующую команду, чтобы запустить локальный экземпляр Distribution:
docker run -d -p 5000:5000 ghcr.io/oras-project/registry:v0.0.3-alpha
Сборка и размещение образа
После того как реестр Distribution запущен и работает, следующим шагом будет сборка, а затем размещение в нем образа.
Для этого мы создадим наш тестовый образ со следующим содержимым:
FROM alpine
ARG SLEEP="30m"
ARG TEXT="Local net-monitor docker image text no arguments"
RUN echo $TEXT 'now sleeping for' $SLEEP 'at:' >message.txt
RUN echo $SLEEP >sleep.txt
CMD cat message.txt && date && sleep $(cat sleep.txt)
Только содержимое этого файла мы возьмем из репозитория https://github.com/wabbit‑networks/net‑monitor.git#main а итоговой образ поместим в наш локальный реестр.
Для этого выполните следующие команды:
docker build -t localhost:5000/net-monitor:v1
https://github.com/wabbit-networks/net-monitor.git#main

Конечно, вы можете использовать любой образ Docker, но если у вас нет такого образа, смело используйте представленный образ wabbit‑networks/net‑monitor.
Установка Notation
Notary — это название проекта CNCF, и его часто упоминают, когда говорят о процессе подписания цифровых артефактов, но Notation — это инструмент командной строки, который делает всю тяжелую работу. Выполните следующие команды, чтобы установить Notation.
Для начала загрузим архив:
curl -Lo notation.tar.gz
https://github.com/notaryproject/notation/releases/download/v0.10.0-alpha.3/notation_0.10.0-alpha.3_linux_amd64.tar.gz
С помощью следующей конструкции распакуем его:
[ -d ~/bin ] || mkdir ~/bin
tar xvzf notation.tar.gz -C ~/bin notation
Добавим значение в переменную PATH:
export PATH="$HOME/bin:$PATH"
Генерация сертификата
Без сертификата у Notation нет возможности создавать новые подписи или проверять существующие. И хотя Notation поддерживает добавление существующих сертификатов, в нем также есть вспомогательная команда, которая сгенерирует для вас новый локальный сертификат.
Выполните следующую команду, чтобы сгенерировать новый локальный сертификат:
notation cert generate-test --default "
wabbit-networks.io
"

Команда notation cert genereate‑test автоматически добавляет ключ сертификата в Notation для использования при подписании, но не открытый ключ сертификата.
Подписание образа контейнера
Теперь, когда у вас есть образ контейнера и сертификат для подписи, осталось только подписать образ, хранящийся в реестре.
Для того, чтобы это сделать выполним следующую команду:
notation sign --plain-http localhost:5000/net-monitor:v1
Для просмотра подписи можно выполнить:
notation list --plain-http localhost:5000/net-monitor:v1
При этом, ключ ‑plain‑http используется для доступа к реестру с помощью обычного HTTP, без необходимости вводить имя пользователя и пароль или проходить другую проверку подлинности.
Проверка подписи
Теперь нам осталось только проверить созданную подпись для нашего артефакта. Команда notation verify, как следует из названия, проверяет артефакты OCI, используя открытый ключ сертификата, чтобы убедиться, что артефакт не был изменен.
Прежде чем выполнять команду verify, необходимо добавить открытый ключ сертификата в конфигурацию Notation.
Для этого выполните следующую команду:
notation cert add --name "
wabbit-networks.io
" ~/.config/notation/localkeys/
wabbit-networks.io
.crt
По умолчанию команда notation cert genereate‑test хранит сертификаты в папке ~/.config/notation/localkeys.
Теперь мы можем выполнить проверку образа контейнера:
notation verify --plain-http localhost:5000/net-monitor:v1

Как видно, все достаточно просто и консольные команды можно без труда встроить в конвейер CI/CD для того, чтобы перед использованием готового артефакта в автоматическом режиме проверять его подпись.
Заключение
В этой небольшой статье мы рассмотрели использование проекта Notary в качестве средства обеспечения доверия к цифровому контенту, в частности к загружаемым пользователями артефактов. С помощью подобных инструментов мы можем усилить защищенность процессов DevOps в целом.
Если вам интересно углубиться в практическое применение инструментов DevOps, приглашаем на открытые уроки курса «DevOps: Практики и инструменты» в OTUS:
30 апреля — «Prometheus: быстрый старт». Записаться
13 мая — «Docker образы. Микросервисы». Записаться
20 мая — «Знакомство с Terraform». Записаться