Сѝкрет, с ударением на первый слог (си-и-и-икрет), это производная от английского слова secret. Просто если писать секрет, вместо сикрета, то на ум приходит шпионская тайна, а не доступы до продакшена.
Что такое сикреты
Сикреты это:
- Любого вида параметры конфигурации сервисов (особенно продакшена)
- любого вида внутренние пароли (например, до базы)
- .env файлы, которые конфигурируют ваши докеры
- файлы сертификатов (например для let’s encrypt)
- ключи до апишек (например выданным вам API_KEY и API_SECRET)
- файлы конфигурации внешнего сервиса (например client_secret.json от Гугла)
- урлы до внутренних продакшен сервисов (10.10.30.1:8080)
- и многое другое, считай, любая конфигурируемая sensitive информация
Когда меня спрашивают, что такое сикреты, я предлагаю людям представить, что у них проект, главной ценностью которого являются данные. Код проекта не несёт в себе большой ценности и может быть опубликован в OpenSource. Так вот, все те данные, которые должны быть заменены на sample или зашифрованы, и являются сикретами.
В общем, все те данные, которые мы обычно прячем как снаружи, так и внутри. Те данные, которые конфигурируют наш сервис. Учитывая то, что в современном мире мы часто используем внешние интеграции, то количество сикретов с каждым днем становится больше.
Проблема
Проблема в том, что мы не можем хранить в открытом виде сикреты в нашем репозитории. Это не безопасно. Даже если ваш репозиторий приватный и не торчит наружу, то, все равно, держать все конфиги внутри приватного репо страшно… Мало ли что может сделать с этими доступами, например, технический писатель или стажер.
Из-за приватных репозиториев современные разработчики расслабились. Организация сикретов в некоторых проектах сегодня оставляет желать лучшего, порой они просто влеплены в код, доступы на продакшн могут лежать почти в открытом виде. Все мы помним недавнюю историю из Gitlab, где ключи от ПРОДАКШЕНА лежали в хендбуке новичка.
Исторически так сложилось, что разработчики суют в .gitignore конфиги, а админы держат их где-то в другом отдельном защищенном месте: в отдельной папочке в гугл драйве, списком в таблице, на флешке в сейфе, в корпоративном 1password.
Это все приводит к двум жопам:
- чтобы новому разработчику запустить интеграционные тесты или как-то поднять сервис, чтобы протыкать, нужно ходить по команде и выпрашивать сикреты. Выясняется, что полный доступ ко всем сикретам только у админа, а он непонятно где. Либо хуже того, никто не знает, где взять те или иные сикреты для работы.
- когда мы добавляем в проект новую интеграцию и кладём в свои сикреты доступы, то нам нужно распинать всю команду, чтобы все обновили свои сикреты. Этого, конечно, толком никто не делает и в результате разрабы утром спуливают проект, запускают, а он не работает.
Обратите внимание на картинку ниже
Решение
Все очень просто: необходимо держать сикреты в репозитории, там где они и должны быть, но в зашифрованном виде. Сикреты расшифровываются либо командой, либо на лету. Расшифровка и шифровка сикретов доступна только определенным юзерам, для этого используется GnuPG (gpg). Такие сикреты можно держать даже в публичном репо.
Давайте еще раз… Мы прямо-таки меняем парадигму отношения к репозиторию, не разносим сикреты по секретным местам, а коммитим и пушим их прямиком в репку проекта.
Сикреты лежат там, где они и должны лежать. Нет больше файла `config.example.yml`. Есть просто `config.yml` где лежит все то, что нужно для работы сервиса. Ок, `config.example.yml` может остаться для того, чтобы те, кто не может расшифровать секрет (джун, тестер или технический писатель) могли понять что там в настройках может находиться. Но рядом с `config.example.yml` лежит зашифрованный `config.yml`. Хотя самым правильным вариантом является следующее: есть полноценный README проекта, где описаны все параметры настроек, что они значат, как их юзать и куда складывать.
Возможен вариант с двумя и более конфигами:
- config.local.yml — локальный настроенный конфиг, не шифрованный, значения могут переопределяться разработчиком через переменные окружения.
- config.testing.yml — конфигурации для тестового окружения, файл подхватывается тестами, не шифрованный. Файл может лежать в репке, а может быть создан самими разрабами, где каждый прописал свои личные данные, например.
- config.production.yml (или config.yml) — шифрованный файл, где хранятся реальные сикреты для прода, используется при деплое. Расшифровывать могут только те, кто отвечает за продакшен.
- ⚠️ эти варианты даны лишь для примера понимания разделения конфигов на шифрованные или не шифрованные, а не для того, как нужно конфигурировать проект. Конфиги могут быть разными, и политика шифрования может быть строже. В этом вопросе каждый проект должен решать самостоятельно, исходя из политики безопасности команды и удобства разработчиков.
Как работает магия GnuPG (gpg)
GnuPG
Перед тем как спускаться в конкретику давайте поймем концепт решения. На рынке есть более-менее три зрелые тулзы для работы с сикретами в гите (git-secret, git-crypt и blackbox — о них ниже) и все они работают с gpg (GnuPG).
Что такое gpg и почему используется именно он? Все просто! gpg шифрует сообщения, используя асимметричные пары ключей, генерируемые пользователями gpg. Открытые ключи шифрования можно, не боясь, передавать друг другу, в то время как зашифрованные сообщения, могут быть расшифрованы только закрытыми ключами, которые каждый пользователь хранит у себя. Подробно ознакомиться можно в Википедии в статье “Криптосистема с открытым ключом”.
Помимо этого gpg позволяет производить шифрование несколькими открытыми ключами, давая возможность пользоваться зашифрованными данными группой лиц, где каждый обладает только своим закрытым ключом. Идеальное решение для команды разработчиков.
В результате у нас появляется шифрованная информация, и при этом нет одного общего пароля, для ее расшифровки. Если мы при шифровании указали открытые ключи Алисы и Боба, то только Алиса и Боб, своими приватными ключами могут расшифровать информацию. Если нужно убрать Боба и добавить Кэрол, то сообщение перешифровывается с ключами Алисы и Кэрол, и без ключа Боба. В результате Боб уже не может расшифровать новую версию зашифрованного сообщения, а Алиса и Кэрол могут.
Особенности работы с gpg
Для начала работы, нам нужно создать нашу пару ключей через gpg. Есть очень подробная дока от Гитхаба на этот счет -> https://help.github.com/articles/generating-a-new-gpg-key/
Это очень краткая, но понятная дока. Однако есть нюанс. На одной из моих машин генерация ключа была настолько долгой, что я подумал о том, что система зависла. В результате оказалось, что настройки железа и ядра системы не дают той энтропии для генерации случайных чисел, чтобы ключ можно было сгенерировать быстро. Для ускорения на stack overflow предлагаются разные решения, вплоть до активного чтения диска через sudo file / и записью в /dev/null данных из /dev/urandom.
Имеем решение простое, нужно установить rng-tools и ключ после этого начинает генерится быстро. rng-tools — это демон для генерации случайных чисел, который для энтропии использует несколько источников. В результате повышается уникальность генерируемых значений и скорость.
Привожу две ссылки для тех, кто столкнется с этой проблемой:
- Начало исследования тут https://serverfault.com/questions/471412/gpg-gen-key-hangs-at-gaining-enough-entropy-on-centos-6.
Утилиты
Git-crypt
Рассмотрим первый тул из списка: git-crypt https://github.com/AGWA/git-crypt. Особенность, отличающая его от blackbox в том, что он шифрует и расшифровывает ваши сикреты на лету, прозрачно, без явного вызова команд и встраивается в git. Таким образом у вас появляется новая команда в гите: git crypt.
Процесс настройки простой (он весь описан в ридмишке проекта, там очень просто):
- вы создаете файл .gitattributes и в нем прописываете список файлов сикретов либо явно, либо по маске
- добавляете своего gpg юзера
- дальше процесс происходит прозрачно, можно смело пушить конфиги в репо, они будут зашифрованы
Я пару раз ловил себя на мысли, что при пуше очкую, вдруг файл не включится в процесс шифрования, вдруг не сработала маска или криво описал все в .gitattributes. На этот счет я перед пушем запускаю команду git-crypt status -e которая показывает список файлов, которые будут зашифрованы. Вижу там свой файл, успокаиваюсь и пушаю.
Когда выгодней юзать git-crypt?
Когда в проекте всего два участника: вы и ваша CI (или сервер, где вы делаете git pull для деплоя), использовать его — одно удовольствие. Но в git-crypt есть две большие проблемы, которые мешают проекту быть использованным большой командой для серьезной работы:
- Он не поддерживается мейнтейнером вот уже год, а форка-преемника пока не появилось.
- Нет опции удаления пользователей из группы, которая шифрует и дешифрует сикреты. Вот тут: https://github.com/AGWA/git-crypt/issues/47 автор объясняет почему это сложно. Хотя мне кажется, что процедурно не сложно вообще. Как только ты убираешь из группы человека, то есть он выходит из проекта, надо менять все сикреты. Автор считает, что сикреты менять не надо, надо хранить историю… Автор живет в своем виртуальном мире.
Git-secret
Помучив git-crypt и поняв, что он не годится для командной работы выбор пал на очередной тул git-secret. Судя по активности в репозитории и по фичам все очень удобно. Есть нужная функция удаления пользователя и повторной шифровки репозитория после удаления, при этом удаленный пользователь доступов не имеет, а оставшимся не нужно менять свои ключи.
Вот на этом скринкасте автор подробно показывает как работать с продуктом: https://asciinema.org/a/41811
Однако, после того как решил использовать git-secret на интеграционной машине вылезла очень неприятная проблема, давно кем-то описанная в этой ишью: https://github.com/sobolevn/git-secret/issues/136
Вкратце, на машине где идет разработка стоит gpg 2.2.4, а на интеграционной gpg 2.1. Файлы, зашифрованные через git-secret на одной машине могут быть расшифрованны на другой машине только если версии gpg на боксах совпадают.
Казалось бы, давайте обновим версию 2.1 до последней из ветки 2.2, но выясняется, что это не просто сделать, особенно если у вас на сервере не совсем свежая версия дистрибутива. Извратиться, конечно, можно. Вот тут даже есть пошаговая инструкция: https://gist.github.com/vt0r/a2f8c0bcb1400131ff51. Плохо то, что в ней слишком много фрикций. И представьте, если у вас распределенная команда из 10 человек с разным опытом и бэкграундом, с разными операционками на рабочих машинах… Это слишком сложный способ.
Вот тут ребята из git-secret явно намекают, что быстрого фикса не будет https://github.com/sobolevn/git-secret/issues/228. Можно попытаться поэкспортить ключи в разных форматах, можно использовать gpg нужной версии через Докер, можно дождаться, когда в git-crypt запилят фичу Stable public key storage: https://github.com/sobolevn/git-secret/blob/master/RFC/RFC001.md
Blackbox
Нет, это не оконный менеджер https://en.wikipedia.org/wiki/Blackbox. Это система управления сикретами от StackExchange https://github.com/StackExchange/blackbox и, пожалуй, она максимально хорошо задокументирована. Помимо описания работы команд описываются еще и методологические особенности подхода к управлению сикретами. Их ридмишка обязательна к прочтению.
Однако, у blackbox точно такая же болячка, как и у git-secret — несовместимость gpg версий. У меня, следуя дефолтному мануалу, не получилось расшифровать сикреты на интеграционке, ровно по той же причине, что и у git-secret. Но если у git-secret эти проблемы описаны в ишьюсах, то у blackbox я их не нашел… Видимо есть способ использовать ключи в разных форматах.
Разбираться в этом не стал, так как blackbox показался слегка заброшенным и немного древним проектом.
Вывод
Если вы хотите менеджить сикреты для себя одного, то идеальный вариант — это git-crypt. Если у вас команда и есть возможность легко управлять версиями GPG на машинах разработчиков и на серверах — git-secret ваш помощник. У blackbox можно почитать ридми, она самая подробная в концептуальном плане.
Если у кого-то есть успешный опыт починки проблем с разными версиями GPG, то поделитесь этим в комментариях. Если вы встречали людей, которые успешно решили эту проблему, скиньте ссылку на них или на их статьи, пожалуйста. Вы используете для управления сикретами успешно тулзы вне перечисленного списка — будет интересно о них узнать.
Ранее статья была опубликована тут.