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

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

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

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

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

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

Пожалуйста, поделитесь в комментариях своими советами и приемами по работе с секретами!

Источник: https://habr.com/ru/company/ru_mts/blog/656351/


Интересные статьи

Интересные статьи

Важно отслеживать показатели и работоспособность приложения: это помогает нам повышать производительность, лучше им управлять и замечать неоптимизированное поведение. Мониторинг каждого сервисного мод...
Часто при разработке радио-электронных устройств возникает необходимость выполнения климатических условий с повышенными требованиями, таких как предельно допустимые рабоч...
Сегодня, специально к старту нового потока по веб-разработке, поделимся с вами туториалом, из которого вы узнаете, как создать видеочат с помощью JavaScript и NodeJS. Так...
Попробуем визуализировать данные по рекламным кампаниям, которые храняться в DataFrame. Дано: DataFrame, в котором хранится статистика по рекламным кампаниям по следующим показателям: Ca...
Хочу поделиться нашим годичным опытом при поиске решения для организации централизованного и упорядоченного доступа к ключам электронной защиты в нашей организации (ключи для доступа к площадкам ...