Модуль secrets-store-integration реализует доставку секретов для приложения в Kubernetes-кластерах путем подключения секретов, ключей и сертификатов, хранящихся во внешних хранилищах секретов.

Секреты монтируются в модули в виде тома с использованием реализации драйвера CSI. Хранилища секретов должны быть совместимы с API-интерфейсом Hashicorp Vault.

Доставка секретов в приложения

Доставить секреты в приложение из vault-совместимого хранилища можно несколькими способами:

  1. Пользовательское приложение само обращается в хранилище. Рекомендация: Это наиболее безопасный вариант, но требует модификации приложений.

  2. В хранилище обращается приложение-прослойка, а ваше приложение получает доступ к секретам из файлов, созданных в контейнере. Рекомендация: Если возможности модифицировать приложения нет — используйте этот вариант. Он менее безопасный, потому что секретные данные хранятся в файлах в контейнере, но проще в реализации.

  3. В хранилище обращается приложение-прослойка, и пользовательское приложение получает доступ к секретам из переменных среды.

Рекомендация: Если нет возможности читать из файлов, можно использовать этот вариант, но он не безопасен. При таком подходе секретные данные хранятся в Kubernetes (а так же в etcd и, следовательно, потенциально могут быть прочитаны на любом узле кластера).

Вариант доставки Потребление ресурсов Как приложение получает данные? Где хранится в Kubernetes? Статус
Приложение Не меняется Напрямую из хранилища секретов Не хранится Реализовано
Механизм CSI Два пода на каждую ноду (daemonset)
  • Из дискового тома (как файл)
  • Из переменной окружения
Не хранится Реализовано
Инъекция entrypoint Один под на каждую ноду (daemonset) Секреты доставляются из хранилища в момент запуска приложения в виде переменных окружения Не хранится В процессе реализации
Секреты Kubernetes Одно приложение на кластер (deployment)
  • Из дискового тома (как файл)
  • Из переменной окружения
Хранится в Secrets Планируется
Инжектор vault-agent По одному агенту на каждый под (sidecar) Из дискового тома (как файл) Не хранится *Не будет реализовано

*Поддержка отсутствует и не планируется, поскольку этот вариант не имеет преимуществ перед использованием механизма CSI.

Вариант №1: Получение секретов самим приложением

Статус: Наиболее безопасный вариант. Рекомендован к использованию, если есть возможность модификации приложений.

Приложение обращается к API Stronghold и запрашивает необходимый секрет по HTTPS протоколу с использованием токена авторизации (токен из SA).

Плюсы:

  • Секрет, полученный приложением, нигде не хранится, кроме как в самом приложении, нет опасности что он будет скомпрометирован в процессе передачи

Минусы:

  • Требует доработки приложения для возможности работы со Stronghold
  • Требует повторения реализации доступа к секретам в каждом приложении, и в случае обновления библиотеки - пересборки всех приложений
  • Приложение должно поддерживать TLS и проверку сертификатов
  • Нет кэширования, при перезапуске приложение нужно повторно запросить секрет напрямую из хранилища

Вариант №2: Доставка секретов через файлы

Механизм CSI

Статус: Безопасный вариант. Рекомендован к использованию, если отсутствует возможность модификация приложений.

При создании подов, запрашивающих тома CSI, драйвер хранилища секретов CSI отправляет запрос к Vault CSI. Затем Vault CSI использует указанный SecretProviderClass и ServiceAccount пода для получения секретов из хранилища и монтирования их в том пода.

Инъекция переменных окружений:

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

Пример на bash:

bash -c "for file in $(ls /mnt/secrets); do export  $file=$(cat /mnt/secrets/$file); done ; exec my_original_file_to_startup"

Плюсы:

  • Всего два контейнера с прогнозируемыми ресурсами на каждой ноде для обслуживания системы доставки секретов в приложения.
  • Создание ресурсов SecretsStore/SecretProviderClass уменьшает количество повторяемого кода по сравнению с другими вариантами реализации vault agent.
  • Есть возможность при необходимости создавать копию секрета из хранилища в виде секрета kubernetes.
  • Секрет извлекается из хранилища драйвером CSI на этапе создания контейнера. Это означает, что запуск подов заблокируется до тех пор, пока секреты не будут прочитаны из хранилища и записаны в том.

Вариант №3: Инъекция entrypoint

Доставка переменных окружения через инъекцию entrypoint в контейнер

Статус: Безопасный вариант. В процессе реализации

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

Вариант №4: Доставка секретов через механизмы Kubernetes

Статус: Не безопасный вариант, не рекомендован к использованию. Поддержка отсутствует, но планируется в будущем.

Этот метод интеграции, который реализует оператор секретов Kubernetes с набором CRD, отвечающих за синхронизацию секретов из Vault в секреты Kubernetes.

Минусы:

  • Секрет находится и в хранилище секретов, и в секрете Kubernetes, то есть доступен через API Kubernetes, а так же в etcd, а значит потенциально может быть считан на любом узле кластера или извлечён из бэкапа etcd. Нет возможности не хранить данные в секретах kubernetes.

Плюсы:

  • Классический способ передачи секрета в приложение через environment variables - достаточно подключить секрет kubernetes.

Справочно: Инжектор vault-agent

Статус: Не имеет плюсов в сравнении с механизмом CSI. Поддержка отсутствует и не планируется, поскольку этот вариант не имеет преимуществ перед использованием механизма CSI.

При создании пода происходит мутация, которая добавляет контейнер с vault-agent. Агент обращается к хранилищу секретов, извлекает их, и помещает в общий том на диске, к которому может обратиться приложение.

Минусы:

  • Для каждого пода нужен сайдкар, который так или иначе потребляет ресурсы. Представим кластер, в котором 50 приложений, каждое имеет от 3 до 15 реплик. Так как для сайдкара с агентом нужно выделить пусть и не большие, но ресурсы cpu и memory, в сумме на кластер это может получиться. 50mcpu + 100Mi на все приложения в сумме десятки ядер и десятки гигабайт ОЗУ.
  • Так как мы мониторим метрики с каждого контейнера, с таким подходом мы получим х2 метрик только по контейнерам.