Модуль secrets-store-integration реализует доставку секретов для приложения в Kubernetes-кластерах путем подключения секретов, ключей и сертификатов, хранящихся во внешних хранилищах секретов.
Секреты монтируются в поды в виде тома с использованием реализации драйвера CSI. Хранилища секретов должны быть совместимы с API-интерфейсом HashiCorp Vault.
Доставка секретов в приложения
Доставить секреты в приложение из vault-совместимого хранилища можно несколькими способами:
-
Пользовательское приложение само обращается в хранилище.
Это наиболее безопасный вариант, но требует модификации приложений.
-
В хранилище обращается приложение-прослойка, а ваше приложение получает доступ к секретам из файлов, созданных в контейнере.
Если нет возможности модифицировать приложение, используйте этот вариант. Он проще в реализации, но менее безопасный, так как секретные данные хранятся в файлах в контейнере.
-
В хранилище обращается приложение-прослойка, и пользовательское приложение получает доступ к секретам из переменных среды.
Если нет возможности читать из файлов, можно использовать этот вариант, но он небезопасен. При таком подходе секретные данные хранятся в 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.
Плюсы:
- Классический способ передачи секрета в приложение через переменные окружения — достаточно подключить секрет Kubernetes.
Справочно: Инжектор vault-agent
Статус: не имеет плюсов в сравнении с механизмом CSI. Поддержка отсутствует и не планируется, поскольку этот вариант не имеет преимуществ перед использованием механизма CSI.
При создании пода происходит мутация, которая добавляет контейнер с vault-agent. Агент обращается к хранилищу секретов, извлекает их, и помещает в общий том на диске, к которому может обратиться приложение.
Минусы:
-
Для каждого пода нужен sidecar-контейнер, который так или иначе потребляет ресурсы.
Например, возьмем кластер в котором 50 приложений, и каждое приложение имеет от 3 до 15 реплик. Так как для каждого sidecar-контейнера с агентом нужно выделить ресурсы CPU и памяти, то даже при незначительных ресурсах для sidecar-контейнера в размере 0.05 CPU и 100 MiB памяти, на все приложения в сумме получаются десятки ядер CPU и десятки ГБ памяти.
-
Так как сбор метрик осуществляется с каждого контейнера, то с таким подходом мы получим в два раза больше метрик только по контейнерам.