Прячем секреты в репозитории с помощью helm-secrets, sops, vault и envsubst

Kate

Administrator
Команда форума
Меня зовут Евгений Симигин, я занимаюсь внедрением DevOps-практик в Центре компетенций по разработке облачных и интернет-решений в МТС Digital. А еще я куратор практикумов docker и kubernetes на платформе rebrainme.com.

Практика показывает, что далеко не все инженеры знают о том, как шифровать секреты в своих репозиториях. Поэтому расскажу об инструментах helm-secrets, sops и vals, которые помогают быстро и просто решить эту задачу. Надеюсь, что после выхода моей статьи закоммиченных паролей в репах станет меньше :).

7c38ab38187cd62f62b095a23fd72da7.jpg

О каких инструментах я расскажу:

  1. Mozilla sops для шифрования yaml/json (без helm)
  2. Helm-secrets и sops
  3. Helm-secrets и философский камень envsubst
  4. Один 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

К сожалению, sops не поддерживает in-place редактирование файлов, поэтому нужно перенаправить вывод в файл.

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
Аналогичные манипуляции можно проделать для второго файла. Инструмент простой, не требует дополнительных инфраструктурных решений и позволяет быстро внедрить шифрованные секреты в проект.

Из минусов: для редактирования секретов придется носить с собой ключи. Ниже приведем пример экспорта/импорта ключа:

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 позволяют соблюсти требования безопасности на старте проекта и плавно переехать на целевую инфраструктуру по мере ее готовности.

 
Сверху