Pull to refresh

Mozilla Sops для управления секретами в гите

Reading time7 min
Views12K

Задача управления секретами одна из самых неприятных в IT. Само существование секретов уже неприятно, потому надо специально прикладывать усилия, чтобы у кого-то не работало (например, чтобы анонимный пользователь не мог прочитать секрет).

Когда кто-то прикладывает осмысленные усилия, появляются баги. А баги с секретами особо плохие, потому что это секреты, и смотреть на вывод нельзя. Всё равно, что USB-A втыкать вслепую, только возможных неправильных позиций больше.

В индустрии, по мере наработки практик, появилось множество систем управления секретами: с собственными серверами (hashicorp vault), 'as a service' (их ещё называют KMS, key management system), аппаратные (токены и TPM), самописные скрипты на gpg и т.д.

Среди всего этого множества я хочу выделить Mozilla Sops, и, как мне кажется, это один из лучших инструментов. Предупреждая возражения: я говорю про инструмент, а не решение. SOPS не заменяет KMS и не претендует на отмену Hashicorp'ового vault'а.

На Хабре уже был перевод про sops с точки зрения IT-директора, весьма убедительная статья, после которой я и занялся sops всерьёз. Если вы ту статью не читали, очень рекомендую начать с неё, чтобы получить заряд мотивации.

В этой статье я расскажу про техническую часть.

Модель хранения секретов

Sops использует два понятия:

  • секрет - информация, которая хранится в зашифрованных файлах и расшифровывается в нужный момент.

  • мастер-ключ - то, с помощью чего расшифровывают секреты. В случае GPG это приватный ключ. Для одного файла с секретами может использоваться несколько мастер-ключей.

Sops использует внешнего поставщика "мастер-ключей" для хранения секретов. Среди них pgp/gpg (для локальной разработки), Hashicorp Vault (для интеграции в существующие системы под его управлением), KMS в Amazon'е, Google'е и Microsoft'е, и многие другие. В этой статье я буду фокусироваться на сценариях с pgp (в форме gpg), как наиболее удобных для знакомства и для локальной работы. Соответственно, ожидается, что у вас уже есть приватный ключ в GPG keyring'е.

В SOPS шифруемые секреты доступны для просмотра (для доверенных участников). Для разных файлов секретов список участников может быть разный.

Для шифрования достаточно иметь публичные ключи всех участников (а для просмотра - хотя бы один приватный). Если приватного ключа нет, получаются "слепые секреты" (создающий новый секрет не может его потом прочитать). Поддерживается система разделения мастер-ключа (алгоритм Шамира, когда для открытия секрета надо более одного участника).

Шифрованные файлы планируется хранить в гите и они адаптированы к читаемости в diff'е при изменении.

Киллер-фича sops (для меня) — одновременная поддержка и частичного шифрования файлов, и их rekeying (смену ключей). Это функция, которой отчаянно не хватает в ansible-vault.

Частичное шифрование

Частичное шифрование поддерживается для файлов со структурой вида key/value:

  • env-файлы (SECRET=hide)

  • yaml и json-файлы, содержащие в top-level словарь (например, secret: hide)

При частичном шифровании в файле остаются незашифрованными ключи (имена), т.е. mysecret: hide превращается в mysecret: "ENC[AES256_GCM,data:...(далее неразборчиво).

Глядя в pull request вы видите какие секреты были поменяны в файле, но не видите на какие значения. С небольшой инструментацией git diff начинает показывать diff в plain-text (если у вас есть ключ для расшифровки), то есть вы видите, что, например mysecret: hide поменялся на mysecret: HIDE.

Для остальных файлов доступно полнофайловое шифрование.

При шифровании (или выполнении rekeying) sops читает свой конфигурационный файл (в текущем каталоге или в каталогах выше, .sops.yaml), берёт оттуда все требуемые публичные ключи и шифрует данные каждым из них. Если конфига нет, sops можно вызывать с переменными среды окружения, с параметрами командной строки; хотя моё наблюдение, что конфиг - самая удобная опция.

При шифровании в файл дописывается довольно большая простыня служебных данных sops, которая должна защитить целостность файла (не дать возможности заменить один секрет на старый, а оставшиеся оставить новыми), плюс предоставить достаточно информации о том, что это и чем оно шифровано при просмотре файла "глазами" (без расшифровки).

Доступ к секрету

sops предлагает несколько опций:

  • Расшифровка файла на stdout. (обычный режим -d)

  • Расшифровка файла in place; -d -i

  • Открытие расшифрованной копии на редактирование (для интерактивной работы с файлом), это режим по-умолчанию при запуске sops myfile.yaml.

  • Запуск указанной программы с путём к временному файлу (fifo или обычному файлу), который удаляется по завершению программы; sops exec-file.

  • Запуск программы с выставлением переменных окружения из шифрованного файла; sops exec-env

  • Извлечение значения по имени ключа из шифрованного файла (когда нужен один секрет из множества); --extract в сочетании с другими опциями.

Весьма интересной особенностью является возможность выставления переменных среды окружения из yaml-файлов, что делает их редактирование куда приятнее, чем редактирование самих env-файлов. В yaml доступны всякие вкусные конструкции с многострочным представлением вместо борьбы за эскейпинг третьей вложенности кавычек в обычном env'е.

Создание секрета

Есть два основных режима создания секрета: шифрование нового файла и добавление в существующий файл. Есть ещё третий режим — "создание нового файла с секретами", но он образуется сам собой при попытке редактирования несуществующего файла.

При редактировании (или создании с нуля) шифрованного файла sops запускается с именем файла без остальных параметров (например, sops foobar.sops.yaml). Если у файла уже есть содержимое, оно расшифровывается (или нет, в зависимости от наличия приватного ключа) и показывается в редакторе. После сохранения и выхода из редактора файл шифруется обратно; причём шифруется всеми публичными ключами согласно конфига или командной строки. Если при открытии файла нет, в редактор загружается пример возможных данных с указанием того, что будет шифровано, а что нет.

Комментарии шифруются; и хоть это вызывает раздражение у многих, у этого есть существенная причина - если вы закомментировали секрет (в режиме редактирования секретов), то вы точно не хотите этот "комментарий" в гите. В этом месте безопасность поставлена выше удобства.

При шифровании существующего файла (например, приватного ключа от сертификата) указывается опция -e для шифрования в stdout, или -e -i для перезаписи файла шифрованной версией.

Rekeying

Одной из проблем при управлении секретами является удаление доступа к файлам у людей (и серверов), которые это право потеряли. Не смотря на то, что человек, теоретически, мог раньше секрет скопировать, отзыв доступа к секретам (при увольнении или переходе в другую команду) — это всё равно крайне важная операция. Аналогичная же проблема возникает и при добавлении нового сотрудника — ему нужно добавить ключ на доступ.

В sops рекеинг выполняется простой командой sops updatekeys для каждого файла. Дальше он спрашивает, действительно ли убрать/добавить ключ, показывая их оттиски (fingerprints), в соответствии с конфигом .sops.yaml. Поменяли конфиг, sops его учитывает. Не меняли конфиг — сообщает, что менять нечего. До выполнения какой-то операции с файлами секретов конфиг игнорируется (т.е. смена конфига не приведёт автоматически к перешифровке всех файлов).

Аудит

Поддержка аудита есть. Sops может сообщать о всех случаях доступа к секретам. /etc/sops/audit.yaml, хотя я эту функцию не пробовал.

Применение на сервере

В силу поддержки нескольких ключей для расшифрования секретов и поддержки KMS крупных облачных провайдеров, в sops есть возможность изолировать файловую систему сервера от секретов, сохраняя при этом удобство разработки и отладки.

Идея проста: один из ключей при шифровании файла секретов — KMS. Люди используют GPG, а сервер, в момент запуска приложения, использует sops и KMS для расшифровки значений на лету и передачи их в приложение. В таком режиме доступ к секретам имеют те, кому положено, и сервер только если он запущен где положено. Если кто-то утащит бэкап или запустит сервер вне ожидаемого места, то вместо секрета он получит либо ошибку запуска, либо (если будет сильно стараться) ENC[AES256_GCMinyourface.

Применение в CI

Точнее, в Github Actions, как примере для других CI'ев. При запуске workflow мы всё-таки должны иметь один секрет из самого github'а — ключ для расшифровки, но все последующие мы можем либо добавить в перменную окружения:

echo '::add-mask::$(sops exec-file .secrets.sops "cat {} | cut -d = -f 2-")'
sops exec-file .secrets.sops "cat {} >> $GITHUB_ENV"

Первая строчка маскирует все секреты, вторая добавляет их в окружение всех последующих job.
Запуск с расшифрованным файлом секретов виден в первой строчке, где файл (точнее, именованный FIFO) передаётся как аргумент в командой строке в форме {}.

Getting started

Одной из проблем с внедрением системам управления секретами является боль при отладке этого процесса. Пройдя этот процесс, могу дать несколько советов:

  • Отлаживайте процесс установки sops отдельно от всего. Это вполне себе задача (например, есть отдельный GH Action для установки mdgreenwald/mozilla-sops-action@v1.1.0). Её можно реализовывать без привлечения секретов, т.е. комфортно.

  • Разберитесь с мастер-ключами. Если это pgp, вам нужно "прикрутить" появление ключа в keyring'е в процессе (для GH Actions есть crazy-max/ghaction-import-gpg@v4). Так же вам нужно синхронизироваться со всеми участниками команды — все должны завести себе gpg-ключи и иметь ключи коллег в keyring'е. Возня с KMS доставит вам отдельный класс развлечений вне контекста SOPS.

  • Напишите .sops.yaml . Сам файл тривиальный, но он содержит в себе полиси: чьи ключи какие файлы должны шифровать.

  • Начните с одного маленького секрета. Я выбрал секрет для запуска стейджинга. Вероятнее всего, в процессе вам придётся преодолеть борьбу с пробелами, переводами строк и ещё чем-то невидимым.

  • Настройте git diff, плагины для редактора и т.д.

  • Только после получения look-n-feel от первого внедрения, начинайте трогать что-то большее. Возможно, стоит делать это в режиме "один секрет" (или файл секретов) за раз.

  • Концентрируйте секреты в одном/двух каталогах. Не стоит разбрасывать шифрованные файлы по всей файловой системе репозитория. В частности, для шифрованных блобов/сертификатов без права смены локации можно использовать симлинки.

Заключение

Sops выглядит как добротная unix-утилита. Она делает что нужно, как нужно, и очень хорошо. У неё минимальное количество полиси и максимальное количество пользы.

Tags:
Hubs:
Total votes 12: ↑12 and ↓0+12
Comments11

Articles