Helm secrets — недостающая часть Kubernetes

в 9:19, , рубрики: AWS, deployments, devops, helm, helm-plugin, k8s, kubernetes, kubernetes-secrets, secrets-management, security, Блог компании Southbridge, Серверное администрирование, системное администрирование

Helm secrets — недостающая часть Kubernetes - 1

В этой статье я расскажу о том, как мы управляем секретами в Kubernetes-инфраструктуре BaseCRM.

Наша цель — использование Helm Charts в Kubernetes-кластерах BaseCRM с минимальными усилиями, подразумевающими управление лишь значениями параметров и секретами. В Helm или Kubernetes нет официального инструмента управления секретами, и мы решили это исправить.

Введение

Kubernetes — это разработанная в Google при существенной поддержке сообщества платформа для автоматизации развертывания и масштабирования контейнеризованных приложений в кластере. Это переносимая, надежная и способная к самовосстановлению система, предназначенная для построения PaaS-инфраструктур следующего поколения.

Поверх Kubernetes мы используем Helm — официальный менеджер пакетов Kubernetes. Располагая системой Charts с поддержкой шаблонов, он помогает управлять различными типами выполняющихся в Kubernetes приложений.

Helm Charts нужен для определения, установки и обновления многократно используемых шаблонов приложений в кластере Kubernetes, включая самые сложные, c множественными зависимыми субчартами (sub-charts). С Helm Charts можно легко управлять множественными версиями чартов, а также останавливать их с помощью прямых манифестов (direct manifests), которые в стоковом Kubernetes управляются только копипастом, что совершенно неприемлемо для сложных окружений.

С помощью Helm мы можем использовать части шаблонов чартов с чартами приложений любой сложности, которые пригодны для многократного использования в развертываниях Kubernetes PaaS в нескольких кластерах. С CI/CD мы можем с легкостью развернуть стек приложений в кластере Kubernetes или просто запустить Helm вручную и задеплоить целый мир с нуля.

Какую проблему мы пытаемся решить?

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

Одни хранят секреты в Git за VPN, при этом получая проблемы с множественными копиями, незашифрованными дисками и ротацией секретов. Другие прописывают их прямо в кластере и теряют эти данные вместе с кластером, когда с ним что-то случается.

С другой стороны, существует возможность интегрировать Kubernetes с сервисом Hashicorp Vault, который является хранилищем секретов. В этом случае кластер при получении секретов Kubernetes будет ссылаться на этот сервис.

Мы хотим разворачивать приложения в кластерах Kubernetes без использования сервиса Vault, который по соображениям безопасности не должен быть частью кластера Kubernetes. Нам нужна возможность работать локально и выполнять холостые прогоны без необходимости подключения к инфраструктуре Vault.

Как мы это делаем?

С самого основания компании Base мы используем Ansible. Также мы решили, что для развертывания кластеров Kubernetes будем использовать Helm (эта тема, скорее всего, заслуживает отдельной статьи). Столкнувшись с проблемой управления секретами, мы придумали плагин helm-secrets, который во многом напоминал Ansible vault. В то время мы использовали PGP и шифровали файл с секретами целиком.

Это было простое решение, хотя с самого начала было понятно, что оно не окончательное. Вскоре мы решили перейти к управлению каждым YAML-секретом по отдельности.

Сначала мы составили список требований и провели поиск инструментов, которые бы им удовлетворяли. Нам удалось найти Mozilla SOPS, который по своим возможностям подходил в качестве бэкенда системы управления секретами для нашего плагина.

Все, что оставалось сделать, — это написать простую прослойку между SOPS-бэкендом и Helm-фронтендом с использованием первой версии helm-secrets.

Именно это мы и сделали, попутно решив поделиться результатами работы с общественностью. Встречайте релиз плагина helm-secrets – https://github.com/futuresimple/helm-secrets.

Вот список его возможностей (их даже больше, чем перечислено здесь):

  • Простой уровень интеграции и установки совместно с плагином helm.
  • Поддержка шифрования YAML-структур Helm.
  • Шифрование отдельных значений – это позволяет использовать diff даже с зашифрованными файлами.
  • Для git diff обеспечивается расшифровка «на лету».
  • Для команд helm install/upgrade/rollback с помощью команды helm-wrapper обеспечивается расшифровка «на лету» и очистка.
  • Поддерживается одновременное использование в одном файле секретов решений управления множественными ключами, таких как PGP и AWS KMS.
  • Для зашифрованных файлов поддерживается простое добавление/удаление ключей.
  • Поддерживается работа с системой управления разрешениями для ключей AWS KMS без необходимости перешифрования.
  • Разделение дерева каталогов для хранения файлов секретов с использованием рекурсивного поиска по файлам .sops.yaml.
  • Извлечение отдельных элементов из зашифрованной структуры файлов.
  • Шифрование части файла.

Система способна работать в рамках CI/CD, обслуживая несколько команд разработчиков, имеющих изолированный доступ к определенным поддиректориям репозитория Git, который содержит секреты в разрезе проектов/окружений/регионов для определенных кластеров Kubernetes. Мы шифруем секреты с помощью разных ключей KMS и мастер-ключа PGP в качестве резерва.

Для автоматизации и ускорения выполнения задач в нашем внутреннем чарт-репозитории используется Makefile.


Вот как это работает

Установка Helm

Следуйте инструкциям на странице проекта helm.

Установка плагина helm-secrets

helm plugin install https://github.com/futuresimple/helm-secrets

Пример использования

В репозитории helm-secrets приведен пример работы с этим плагином, а также соответствующая структура каталогов, предназначенная для хранения значений чартов helm. Для чартов kubernetes применяется аналогичная структура.

Для этого примера используется файл test.sh из репозитория helm-secrets.

example/helm_vars/
├── .sops.yaml
├── projectX
│   ├── .sops.yaml
│   ├── production
│   │   └── us-east-1
│   │       └── java-app
│   │           ├── secrets.yaml
│   │           └── value.yaml
│   └── sandbox
│       └── us-east-1
│           └── java-app
│               ├── secrets.yaml
│               └── value.yaml
├── projectY
│   ├── .sops.yaml
│   ├── production
│   │   └── us-east-1
│   │       └── java-app
│   │           ├── secrets.yaml
│   │           └── value.yaml
│   └── sandbox
│       └── us-east-1
│           └── java-app
│               ├── secrets.yaml
│               └── value.yaml
├── secrets.yaml
└── values.yaml

Давайте разберем этот пример.

  • У нас есть два PGP-ключа (также можно использовать KMS-ключи):
    • один для projectx;
    • другой для projecty.
  • Все остальные секреты управляются в рамках проекта, и для каждого проекта используется один ключ.
  • Ключи изолированы друг от друга, и только глобальный файл secrets.yaml, находящийся в корне helm_vars, может быть расшифрован любым из этих ключей.
  • Все правила глубины рекурсии для шифрования/расшифровки находятся в файлах .sops.yaml.

Шифрование, расшифровка и даже больше

Перед шифрованием example/helm_vars/secrets.yaml

global_secret: global_bar

Теперь шифруем:

helm-wrapper secrets enc example/helm_vars/secrets.yaml

В результате мы получим файл с незашифрованными ключами и зашифрованными значениями.

После раздела с ключами идут sops-данные, необходимые для шифрования или расшифровки структур секретов.

Также есть метаданные типа sops version, lastmodified или unencrypted_suffix. Почитать о формате файла sops можно на сайте проекта Mozilla SOPS.

global_secret: ENC[AES256_GCM,data:pTyPdC6YA+z84Q==,iv:aF5hb9CS8Au0B3RWADPtP8fXYzYakU7JJ8ZxzJgHRF0=,tag:c3pCyOf0NpQU7VPL/72XPg==,type:str]
sops:
.…

….

….

    unencrypted_suffix: _unencrypted
    version: 2.0.9

Теперь расшифровка:

helm-wrapper secrets dec example/helm_vars/secrets.yaml

И результат:

global_secret: global_bar

Теперь мы можем работать с такими файлами без расшифровки, например, при поиске ключей в нескольких файлах секретов. Мы даже можем расшифровывать их «на лету» с git diff config, что делает работу еще более комфортной, особенно по сравнению с приложениями, которые не поддерживают подобную функциональность.

Мы также можем более гибко управлять разрешениями секретов, не пересоздавая их благодаря более продвинутому AWS KMS.

Более того, просмотр и редактирование секретов с помощью простых команд плагина облегчают ежедневную работу.

helm-wrapper secrets view example/helm_vars/secrets.yaml

После расшифровки файл секретов будет выведен в stdout:

helm-wrapper secrets edit example/helm_vars/secrets.yaml

По команде edit расшифрованный файл откроется в редакторе, а изменения будут автоматически сохранены в зашифрованном виде.

Эти функции значительно облегчают работу с зашифрованными данными практически при любом сценарии.

Пример использования Helm

Давайте развернем что-нибудь в кластере Kubernetes.

Чтобы упростить процесс и сделать его более прозрачным, мы создали helm-wrapper. Эта написанная на bash обвязка для helm автоматически расшифровывает все заданные секреты и использует расшифрованные данные для выполнения процедуры развертывания с помощью helm. При возникновении ошибки или в случае успешного завершения процедуры все временные данные с секретами удаляются.

Реальный пример для приложения типа helloworld:

AWS_PROFILE=production helm-secrets upgrade --install --timeout 600 --wait helloworld stable/java-app --kube-context=production --namespace=projectx --set global.app_version=bff8fc4 -f helm_vars/projectx/sandbox/us-east-1/java-app/helloworld/secrets.yaml -f helm_vars/projectx/sandbox/us-east-1/java-app/helloworld/values.yaml -f helm_vars/secrets.yaml -f helm_vars/values.yaml
>>>>>> Decrypt
Decrypting helm_vars/projectx/sandbox/us-east-1/java-app/helloworld/secrets.yaml
>>>>>> Decrypt
Decrypting helm_vars/secrets.yaml

Release "helloworld" has been upgraded. Happy Helming!
LAST DEPLOYED: Fri May  5 13:27:01 2017
NAMESPACE: projectx
STATUS: DEPLOYED

RESOURCES:
==> extensions/v1beta1/Deployment
NAME        DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
helloworld  3        3        3           2          1h

==> v1/Secret
NAME        TYPE    DATA  AGE
helloworld  Opaque  10    1h

==> v1/ConfigMap
NAME        DATA  AGE
helloworld  2     1h

==> v1/Service
NAME        CLUSTER-IP      EXTERNAL-IP  PORT(S)   AGE
helloworld  100.65.221.245         8080/TCP  1h

NOTES:
Deploy success helloworld-bff8fc4 in namespace projectx

>>>>>> Cleanup
helm_vars/projectx/sandbox/us-east-1/java-app/helloworld/secrets.yaml.dec
helm_vars/secrets.yaml.dec

Как можно увидеть из листинга, там есть специальная команда, которая выполняется на стороне CI для развертывания приложения. В этом примере используется наш внутренний универсальный чарт для приложений на java, который содержит шаблон для config map, секретов, сервисов и развертывания.

Все это генерируется из значений в файлах, указанных с помощью опции -f команды helm. Если в таком файле встретится зашифрованный секрет, скрипт расшифрует его «на лету», и helm ничего не заметит.

При использовании AWS KMS необходимо указать имя AWS_PROFILE.

При возникновении ошибки будет выполнена очистка.

AWS_PROFILE=production helm-wrapper upgrade --install --timeout 600 --wait helloworld stable/java-app --kube-context=wrongcontext --namespace=projectx --set global.app_version=bff8fc4 -f helm_vars/projectx/sandbox/us-east-1/java-app/helloworld/secrets.yaml -f helm_vars/projectx/sandbox/us-east-1/java-app/helloworld/values.yaml -f helm_vars/secrets.yaml -f helm_vars/values.yaml
>>>>>> Decrypt
Decrypting helm_vars/projectx/sandbox/us-east-1/java-app/helloworld/secrets.yaml
>>>>>> Decrypt
Decrypting helm_vars/secrets.yaml

Error: could not get kubernetes config for context 'wrongcontext': context "wrongcontext" does not exist

>>>>>> Cleanup
helm_vars/projectx/sandbox/us-east-1/java-app/helloworld/secrets.yaml.dec
helm_vars/secrets.yaml.dec

Такой подход при использовании секретов в helm позволяет минимизировать усилия, сохраняя максимальный уровень безопасности.

Безопасное использование с git

При наличии расшифрованных секретов (расшифрованных вручную) у нас остается еще два уровня обеспечения безопасности: исключение расшифрованных файлов с помощью .gitignore и добавление хуков, которые проверяют, не зашифрованы ли файлы коммита с помощью SOPS.

Все это также есть в документации helm-secret и проверено нашим процессом CI/CD.

Заключение

Helm-secrets — это лишь тонкая обертка для sops-бэкенда, и любая команда этого плагина может быть заменена на другие инструменты.

Мы также используем этот плагин для распространения секретов через публичный git-репозиторий и планируем добавить в процесс работы с секретами интегрированную в Kubernetes службу Vaulting, что придаст нашему решению законченность.

Для инфраструктуры небольшого размера должно быть достаточно плагина helm-secrets. Надеемся, его использование вам понравится.

При желании добавить в проект какие-либо функции или просто его обсудить заходите на https://github.com/futuresimple/helm-secrets.

Ссылки:

  1. Оригинал: HELM SECRETS – A MISSING PIECE IN KUBERNETES.

Автор: olemskoi

Источник

Поделиться

* - обязательные к заполнению поля