Привет, Хабр! Меня зовут Евгений Симигин, я занимаюсь внедрением DevOps-практик в Центре компетенций по разработке облачных и интернет-решений в МТС Digital. А еще я куратор практикумов docker и kubernetes на платформе rebrainme.com.
Практика показывает, что далеко не все инженеры знают о том, как шифровать секреты в своих репозиториях. Поэтому расскажу об инструментах helm-secrets, sops и vals, которые помогают быстро и просто решить эту задачу. Надеюсь, что после выхода моей статьи закоммиченных паролей в репах станет меньше :).
О каких инструментах я расскажу:
Mozilla sops для шифрования yaml/json (без helm)
Helm-secrets и sops
Helm-secrets и
философский каменьenvsubstОдин vals, чтоб править всеми
Mozilla sops
Позволяет шифровать yaml/json на gpg-ключах. Репозиторий проекта тут.
Обратите внимание, у вас должна быть версия не ниже 3.7.1. В противном случае могут появляться различные мистические ошибки, которые лечатся обновлением версии.
Для того, чтобы воспользоваться инструментом, необходимо сгенерировать ключи:
gpg --gen-key
Отвечаем на вопросы о пользователе и почте и получаем сообщение, что все прошло успешно:
…
gpg: key 45369266A697BDC7 marked as ultimately trusted
gpg: revocation certificate stored as '/home/dadmin/.gnupg/openpgp-revocs.d/0D955807E53158CB209E3A5645369266A697BDC7.rev'
public and secret key created and signed.
pub rsa3072 2022-03-18 [SC] [expires: 2024-03-17]
0D955807E53158CB209E3A5645369266A697BDC7
uid prod-habrauser <prod-habramail@prod-habramail.ru>
sub rsa3072 2022-03-18 [E] [expires: 2024-03-17]
Список всех ключей можно просмотреть командой gpg --list-keys
/home/dadmin/.gnupg/pubring.kbx
-------------------------------
pub rsa3072 2022-03-18 [SC] [expires: 2024-03-17]
48EF05B385B1DA8713ADCA7694D3BD5F3B78E0F7
uid [ultimate] habrauser <habramail@habramail.ru>
sub rsa3072 2022-03-18 [E] [expires: 2024-03-17]
pub rsa3072 2022-03-18 [SC] [expires: 2024-03-17]
0D955807E53158CB209E3A5645369266A697BDC7
uid [ultimate] prod-habrauser <prod-habramail@prod-habramail.ru>
sub rsa3072 2022-03-18 [E] [expires: 2024-03-17]
У меня в системе 2 ключа так как мы будем имитировать dev- и prod-окружение, шифруемое на разных ключах. Создадим два файла с секретами, которые будем шифровать.
secrets.dev.yaml:
secrets-dev:
secret1: value1
secret2: value2
secrets.prod.yaml:
secrets-prod:
secret1: value1
secret2: value2
Создадим файл .sops.yaml
, в котором пропишем маску имени файла и отпечаток ключа, который будет к нему применяться.
creation_rules:
- path_regex: \.*prod*\.yaml$
pgp: 0D955807E53158CB209E3A5645369266A697BDC7
- path_regex: \.*dev*\.yaml$
pgp: 48EF05B385B1DA8713ADCA7694D3BD5F3B78E0F7
Зашифруем секрет: sops -e secrets.dev.yaml > enc.secrets.dev.yaml
cat enc.secrets.dev.yaml
secrets-dev:
secret1: ENC[AES256_GCM,data:sM0ZcEj3,iv:wJsvNcOGTNB7KETqUUYeS5HT5YcAI3mvomrSFKDjuWg=,tag:6qZ7RJaDulpk59ll2rzqLw==,type:str]
secret2: ENC[AES256_GCM,data:H6jpTf+X,iv:MOOmbabkzJmyKWmFngNUDm2PFYaHmKGh3KCbofilqKQ=,tag:zqzmpaA877K058VhAeqFmg==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age: []
lastmodified: "2022-03-18T04:00:30Z"
mac: ENC[AES256_GCM,data:KkHyTaHMljUS86GQJCMFFjKPi77mFbwF48dF4WK7F5UrSmGUkqJnfzvjFDb3bAoGU8d+SIdEHg+XQDAzF5LJi2itqppRI+NQA9AKIiEj1t8ebiGkOcPfz2NFD4XltofhbBzr5FjcLwTz+FZ74V//5RKxCmEBHfXDiZo2BOo5qeE=,iv:1FGM3gBkk40DkL/Cxmg08CpG4HqfxnjX+XhwYAVvlSY=,tag:iYpDEuPUAF2m/be3nBM+6g==,type:str]
pgp:
- created_at: "2022-03-18T04:00:30Z"
enc: |
-----BEGIN PGP MESSAGE-----
hQGMA/B9NJDVd05oAQwAqWc68igJA1kPBf5iTN1x7qcYx6urjD72A/IYyXZqaPM8
WsIPEwu7u4KZnb7zXnm0ICY3oFj+yznDvZr5BklytCJZ45G8RBFenbUGKh0vVVsw
zsmvGkoe9LR4hzo2QtXtmaydg3EBwkoeeJC0Vk2I8U+Wmo/JXkgmcCtTva39PmU7
yGA2Mv0RvpmHHL/fEj52wFGsOFpyLpEXjDQamqhGLAXjbqqjPMmc7fjP/Nr5TGtA
TTlvC1RusahxznnL3GJ2QUeHZMPahdkq1R/SzQonVgzy0MzMzZcH82e5CxazmBBL
3f/Zn8YyjQbVveJF1zaLKk4msBrYcOqxXtQR6yoUdOVtYHSiraaxfJfOgx7XLvNS
7rdisJ/5CzcfoP6BLh6Y9H5sVd56j8A9gxiv30QH9YrVcSJW/RurOtrKMa9nrnZs
0gcPF4nnQOfJ9KYgfLVKBFhiK6Afx/lRKbK1E5aHshseZ9leOZpJOavYdHl9kaPd
D4DZCy78cX0PDhHA6pQx0l4BH1yv3afgmb2zSoKcVC++rztVrNt/spnCOFB7lBrS
HeXVpCNYQuXLGHTlDuoYviWDFdJtY6SW/9FHX+zviKOKuQiRI0jG7izHIkyy0j7C
podcI9bilsCqxTq0sSRX
=+0c5
-----END PGP MESSAGE-----
fp: 48EF05B385B1DA8713ADCA7694D3BD5F3B78E0F7
unencrypted_suffix: _unencrypted
version: 3.7.2
Команда sops -d enc.secrets.dev.yaml
выведет нам в консоль расшифрованный файл:
secrets-dev:
secret1: value1
secret2: value2
Аналогичные манипуляции можно проделать для второго файла. Для in-place редактирования используейте sops -i
. Инструмент простой, не требует дополнительных инфраструктурных решений и позволяет быстро внедрить шифрованные секреты в проект.
Из минусов: для редактирования секретов придется носить с собой ключи. Ниже приведем пример экспорта/импорта ключа:
gpg --armor --export-secret-key 0D955807E53158CB209E3A5645369266A697BDC7 > key-prod.gpg
gpg --allow-secret-key-import --import key-prod.gpg
gpg: key 45369266A697BDC7: "prod-habrauser <prod-habramail@prod-habramail.ru>" not changed
gpg: key 45369266A697BDC7: secret key imported
gpg: Total number processed: 1
gpg: unchanged: 1
gpg: secret keys read: 1
gpg: secret keys unchanged: 1
Helm-secrets и sops
Для меня целевым инструментом является helm и его плагин helm-secrets. Репо проекта.
Обычно он используется как обертка для sops, но это только видимая часть айсберга.
При использовании helm-secrets мы получаем дополнительные фичи:
In-place шифрование секрета helm secrets enc secrets.dev.yaml;
Просмотр helm secrets view secrets.dev.yaml;
Редактирование helm secrets edit secrets.dev.yaml откроет расшифрованный файл в $EDITOR (у vscode есть плагин, который автоматически шифрует и расшифровывает секреты при редактировании);
Автоматический рендер переменных при разворачивании чарта helm secrets upgrade --install -f values.yaml -f secrets.dev.yaml project;
Возможность интеграции с различными системами хранения секретов (об этом чуть позже).
А вот расшифровка in-place подкачала – helm secrets dec secrets.dev.yaml – создаст расшифрованный файл secrets.dev.yaml.dec, а исходный останется без изменений.
Helm-secrets и envsubst
Частая задача – отрендерить переменные в каком-либо файле соответствующими переменными в ENV. В этом поможет замечательная утилита envsubst, которая принимает входящий поток и заменяет в нем переменные на значения из ENV. Как обычно это делают при деплое:
envsubst < ./deploy-config/secrets.dev.yaml > secrets.dev.yaml
helm upgrade --install -f values.yaml -f secrets.dev.yaml $CI_PROJECT_NAME ./deploy-chart
Тоже самое можно реализовать in-place при помощи helm-secrets с драйвером envsubst:
HELM_SECRETS_DRIVER=envsubst helm secrets upgrade --install -f values.yaml -f $CI_PROJECT_NAME ./deploy-chart
Обратите внимание, в первом случае просто helm
так как мы на вход подаём уже отрендеренный конфиг, а во втором - helm secrets
ибо требуется извлечение секретов.
Файл secrets.dev.yaml в данном случае выглядит приблизительно так:
secrets-dev:
secret1: $ENV-VAR1
secret2: $ENV-VAR2
Драйвер – это обертка на bash, он позволяет подключать любые системы хранения секретов.
Один vals, чтоб править всеми
У драйверов для helm-secrets есть один недостаток – нельзя использовать несколько драйверов одновременно.
Таким образом мы подходим к гвоздю программы – vals. Он позволяет из одного манифеста ссылаться на различные источники секретов: sops, vault, aws, gcp. Также его можно использовать как драйвер для helm secrets.
Принцип работы – в файл вставляются ссылки вида:
secrets-dev:
secret1: ref+sops://path/to/file#/foo/bar
secret2: ref+vault://mykv/foo#/bar?address=https://vault1.example.com:8200
secret3: ref+gcs://BUCKET/KEY/OF/OBJECT[?generation=ID]
secret4: ref+драйвер(хранилище):/путь/относительно/хранилища
Для интеграции с vault достаточно задать переменные VAULT_ADDR и VAULT_TOKEN и можно вытаскивать секреты ref+vault://kv/annotation#pod_annotation,
Но есть и особенности:
Для рендера всего чарта используйте
helm secrets -d vals -f values.yaml template .
Если не укажете-f values.yaml
– вместо значений увидите свои ссылки.Для просмотра секретов в конкретном файле используйте
helm secrets -d vals view values.yaml -
. Работает команда странно: сортирует все ключи по алфавиту. Кажется, что она выводит не весь файл. На родной интеграции helm + vault (не через vals) у меня так и не заработал рендер этой командой.
Использование vals вне helm выглядит следующим образом: vals eval -f values.yaml
. Файл с подставленными переменными будет выведен в консоль.
Vals разделяет понятие переменных и секретов: для секретов можно использовать дополнительную маркировку secretref+драйвер
, тогда команда vals eval --exclude-secret -f values.yaml
отрендерит только ссылки, начинающиеся с ref+
, а secretref+
останутся в виде переменных. Этот функционал можно использовать, чтобы увидеть, как в итоге собрался файл конфигурации, не показывая при этом секреты всем.
Заключение
Рассмотренные инструменты – это проекты c открытым исходным кодом, написанные на golang и вы можете добавить свой функционал по необходимости.
Для внедрения sops не требуется каких-либо сторонних инфраструктурных решений и специалистов, вы можете сделать это уже сегодня.
Использование комбинаций helm/sops/vals позволяют соблюсти требования безопасности на старте проекта и плавно переехать на целевую инфраструктуру по мере ее готовности.
Пожалуйста, поделитесь в комментариях своими советами и приемами по работе с секретами!
Комментарии (10)
pshhpshh
26.03.2022 00:33Как же хорошо было жить на азуре, где все блин на порядки проще...
Сейчас перешел на проект с AWS и это ужас - хелмы, датадоги (хорошая штука, конечно), аппвееры, куча еще какой-то фрагментированной лабуды.
Признаюсь: о чем статья и зачем все это нужно, если есть Azure KeyValult - не понял.
S1M Автор
26.03.2022 04:43Например, вы сидите в любой крупной корпоративной конторе и вам просто запрещено выносить что-либо за пределы контролируемой зоны.
dolfinus
26.03.2022 01:51Также стоит включить на уровне настроек репозитория или push хуков проверку на то, что в репозиторий не залили секрет в открытом виде. Например, с помощью https://github.com/Yelp/detect-secrets
zartdinov
26.03.2022 14:13Вроде всегда получается не хранить ничего в репозитории, просто везде использую переменные окружения
barkalov
Все хорошо, но теперь нужна инфраструктура для хранения и деплоя ключей для секретов.
S1M Автор
В случае helm secrets и sops все хранится в репе и ничего дополнительно не нужно. И потом можно разворачивать инфраструктурные решения и перезжать туда.
lokkersp
вас тут немного обманули, дело в том, что sops поддерживает и KMS(AWS,GCP)-ключи, Vault.
S1M Автор
По коммитам vault завезли "16 Jul 2020" я честно говоря пропустил этот момент, т.к. инструмент начал использовать гораздо раньше. KMS опять же не целевая архитектура для корпоратов: я долгое время работал в банке и внешние системы не рассматриваю. Спасибо, что указали на неточность, я в документации по sops вычитал интересную вещь: он может запушить секреты из файла в vault:
sops publish $file
lokkersp
для кого как, мы например sops используем совместно с терраформом, и не таскать ключи за собой это прям хорошо.
amarao
sops полностью автономный, и пока что, самый админолюбивый из всего, что я видел для работы с секретами.
Во-первых он в гите, т.е. секреты соответствуют версии приложения.
Во-вторых диффы можно смотреть без содрогания.
В третьих, даже если нет diff view, то даже в зашифрованном виде диффы можно смотреть без содрогания.