OpenBao: немного enterprise’ных возможностей при управлении секретами

от автора

Привет, меня зовут Симигин Евгений и я являюсь ключевым экспертом по внедрению DevOps-практик и инструментов развертывания в подразделении Поддержки платформ и систем информационных технологий в финансовой организации. Мы пристально следим за судьбой проекта openbao и несколько дней назад, завезли функционал о котором хотелось бы рассказать читателям Habr.

Если до этого вы не слышали об openbao, то вот некоторые факты:

  • OpenBao это форк от коммита hashicorp vault (8993802) между версиями 1.14.8 1.14.9, до смены лицензионной политики

  • Проект получил статус участника CNCF

  • Разработчики декларируют api-совместимость с vault и планируют её придерживаться

  • Несмотря на пункт выше, проект будет иметь собственную дорожную карту и развиваться независимо от hashicorp vault

  • Лицензируется по MPL 2.0

  • И как все мы любим — доступен без регистрации и смс

  • Продукт долгое время был доступен без UI т.к. оттуда вычищали весь enterpris’ный код vault, но в апреле завезли полноценный нескучный UI

  • Без проблем работает с bank-vaults webhook и с небольшими костылями с vault-operator

  • Сам продукт находится в статусе GA

  • Поддерживает HA-mode, используя бэкенды raft и postgresql

  • Из минусов: как и у многих проектов open-source, бывают проблемы с документацией. Однако процесс улучшения виден невооружённым взглядом

Таким образом проект заслуживает нашего внимания, поэтому сделаем небольшой обзор.

# устанавливать будем в kubernetes # берём последний релизный helm-чарт, доступный на текущий момент  git clone https://github.com/openbao/openbao-helm.git -b openbao-0.16.1  # В конфиге включим UI, raft и HA и сделаем установку  helm upgrade --install --create-namespace -n openbao openbao .  # подождем минуту и посмотрим статусы подов  kubectl -n openbao get pods NAME                                      READY   STATUS    RESTARTS   AGE openbao-0                                 0/1     Running   0          73s openbao-1                                 0/1     Running   0          73s openbao-2                                 0/1     Running   0          73s openbao-agent-injector-665bb59f4c-jzcbz   1/1     Running   0          74s

Стоит отметить, что в чарте очень много параметров, тут тебе и securityContext , и seccomp можно настроить. Этап установки завершён и пора приступать к распаковке 🙂

# инициализируем наше хранилище секретов  kubectl -n openbao exec -it openbao-0 -- bao operator init  # в ответ получаем ответ, очень похожий на vault (я думаю никто не удивился)  Unseal Key 1: ufTrcKoD05iKSjb5lEck2hFC7gtsJd2xKcXScH5MEb2w Unseal Key 2: lL7vyLN2wN92fGj0zp9VhzEO1fQjS6UVwaDqodg/0Z9F Unseal Key 3: OvqnFKKCn/ZL2OkaVeBApLeOtqzOmaeqxiCCgnQ7yKXz Unseal Key 4: v1Xk+RfmQ6y8EEj5hiPg3cK8CGUrKQCHcE5jokh7ZE7I Unseal Key 5: UlY+Df53ZemRQAx+rYJEN2WwCHydwp97B7YiU26rlTUo  Initial Root Token: s.7skMvkFLIPuI2wu0QYr8npZJ  # далее мы трижды вызываем команду unseal с тремя разными ключами   kubectl -n openbao exec -it openbao-0 -- bao operator unseal ufTrcKoD05iKSjb5lEck2hFC7gtsJd2xKcXScH5M Eb2w kubectl -n openbao exec -it openbao-0 -- bao operator unseal lL7vyLN2wN92fGj0zp9VhzEO1fQjS6UVwaDqodg/0Z9F  kubectl -n openbao exec -it openbao-0 -- bao operator unseal OvqnFKKCn/ZL2OkaVeBApLeOtqzOmaeqxiCCgnQ7yKXz Key                     Value ---                     ----- Seal Type               shamir Initialized             true Sealed                  false Total Shares            5 Threshold               3 Version                 2.3.1 Build Date              2025-06-25T19:20:49Z Storage Type            raft Cluster Name            vault-cluster-ad72fc67 Cluster ID              e0424c9f-d43c-0796-2ec3-59447f04799b HA Enabled              true HA Cluster              https://openbao-0.openbao-internal:8201 HA Mode                 active Active Since            2025-07-01T03:00:33.973435832Z Raft Committed Index    30 Raft Applied Index      30

После того, как распаковали первую ноду, не забываем, что raft-кластер сам не собирается, нужно присоединить ноды вручную (либо сразу прописываем retry_join в хелм чарте)

# давайте проверим  kubectl -n openbao exec -ti openbao-0 -- vault login s.7skMvkFLIPuI2wu0QYr8npZJ Success! You are now authenticated. The token information displayed below is already stored in the token helper. You do NOT need to run "bao login" again. Future OpenBao requests will automatically use this token.  Key                  Value ---                  ----- token                s.7skMvkFLIPuI2wu0QYr8npZJ token_accessor       V7bgfs3Zq7bjXqb5DC0c7dbv token_duration       ∞ token_renewable      false token_policies       ["root"] identity_policies    [] policies             ["root"]  # неловко вышло, по привычке использовали vault login. но это всё еще работает ;) # далее смотрим соседей по raft  kubectl -n openbao exec -ti openbao-0 -- /bin/bao operator raft list-peers Node         Address                            State     Voter ----         -------                            -----     ----- openbao-0    openbao-0.openbao-internal:8201    leader    true  # присоединяем ноды  kubectl -n openbao exec -it openbao-1 -- bao operator raft join http://openbao-0.openbao-internal:8200 Key       Value ---       ----- Joined    true  kubectl -n openbao exec -it openbao-2 -- bao operator raft join http://openbao-0.openbao-internal:8200  Key       Value ---       ----- Joined    true  # далее берём ключи власти и над 1 и 2 подом трижды выполняем unseal  for index in 1 2; do kubectl -n openbao exec -it openbao-$index -- bao operator unseal lL7vyLN2wN92fGj0zp9VhzEO1fQjS6UVwaDqodg/0Z9F ; done  for index in 1 2; do kubectl -n openbao exec -it openbao-$index -- bao operator unseal UlY+Df53ZemRQAx+rYJEN2WwCHydwp97B7YiU26rlTUo ; done  for index in 1 2; do kubectl -n openbao exec -it openbao-$index -- bao operator unseal v1Xk+RfmQ6y8EEj5hiPg3cK8CGUrKQCHcE5jokh7ZE7I ; done  # проверяем. что все в сборе  kubectl -n openbao exec -ti openbao-0 -- bao operator raft list-peers Node         Address                            State       Voter ----         -------                            -----       ----- openbao-0    openbao-0.openbao-internal:8201    leader      true openbao-1    openbao-1.openbao-internal:8201    follower    true openbao-2    openbao-2.openbao-internal:8201    follower    true

Стоит отметить, что механизм HA пока такой же как и в vault: есть сервер-лидер, который отвечает на запросы, остальные только делают редирект на него (как и многие наши коллеги)

Всё, после этого OpenBao готов к употреблению (если вы готовите прод, не публикуйте ваши ключи в статьях на habr 🙂 После инициализации раздайте 3 ключа эльфам, 5 гномам … и так далее, чтобы у вас в сумме была возможность распаковать волт, если он запакуется после перезапуска контейнеров.

Стоит отметить, что пока мы из консоли вручную не провели инициализацию, в веб интерфейсе мы наблюдали `503 Service unavailable`, это для тех кто любит инициализировать/распаковывать из UI — пока такой возможности нет.

Теперь нас ожидает вот такое окно:

Берём наш root-токен и логинимся:

Совсем не похоже на волт, там был чёрный фрейм, а тут зелёный 🙂

Итак акт 2, на сцене те же и выходят namespaces , сам анонс технологии был в блоге openbao, с тех пор я сидел в засаде и ждал релиза.

Если простыми словами, то namespaces — это возможность нарезать волт в волте и даже еще раз в волте, у которого будет изолированный root , secret-движки, политики, методы аутентификации…

Картинку возьмём с их же блога, в данном случае можно каждый прямоугольник сделать отдельным микроволтом:

Когда это может быть полезно:

  • Если изначально не было никакой стандартизации процессов работы с секретами и при попытке сразу всех привести к одному стандарту мы столкнёмся с саботажем

  • Если это старый проект с гибридной инфраструктурой, который приносит много денег, а их техлид занимается боксом, а у тебя из спортивных достижений 4й разряд по шахматам в школе и вам просто скажут отстать от них

  • Из позитивнного: если у вас есть команды-энтузиасты можно давать им в тест подобную технологию для изучения каких-либо возможностей хранилища секретов, которые можно потом внести в общий стандарт

  • Если у команды есть потребность программной интеграции своего сервиса и управления секретами. Если в первом пункте имелось ввиду больше организационная потребность, чтобы начать внедрять хранилище хоть как-то, то в данном случае мы говорим о разработке сервисов (например, вы запросили временные административные права к машине, по вашей заявке сервис выписал в vault, вам ssh-доступ с временным паролем и потом автоматически отозвал его)

В документации к оригинальному vault есть дополнительные мысли о том, какую выгоду может получить компания от применения этой технологии

Таким образом всё сводится к балансу сил: с одной стороны вы можете дать команде возможность самим писать свои политики и перестать дорабатывать их каждые 5 минут по запросам. С другой стороны, этот процесс нужно контролировать, чтобы команда не использовала один root-токен, чтобы править всеми, читать/писать/хранить в гите/аутентифицировать все сервисы и еще дать соседу посмотреть как у вас структура папок устроена.

Собственно, перейдём к сути, чтобы не копировать мануал создадим отдельный тенант teams , а в нём team1 для нашей команды:

# создаём некий тенант   kubectl -n openbao exec -ti openbao-0 -- bao namespace create teams Key                Value ---                ----- custom_metadata    map[] id                 c5qncb locked             false path               teams/ tainted            false uuid               dd011b49-37fc-4399-afba-3c70e5e08287  kubectl -n openbao exec -ti openbao-0 -- bao namespace create -ns teams team1 Key                Value ---                ----- custom_metadata    map[] id                 o3GJpH locked             false path               teams/team1/ tainted            false uuid               885d32a3-a2da-21c9-40a4-0034cdfc6aef

После создания, в UI можно наблюдать такую картину:

UI после создания неймспейсов

UI после создания неймспейсов

Слева вы можете видеть список неймспейсов, давайте переключимся в teams , после нажатия нас ожидает вот такое окно

Приглашения для логина в тенант

Приглашения для логина в тенант

Вот так выглядит интерфейс внутри, обратите внимания, что из неймспейса teams, мы уже не видим информацию про raft и также не можем тюлень запечатать Openbao` (seal openbao)

Вид изнутри тенанта

Вид изнутри тенанта
# далее я переключусь внутрь контейнера, чтобы уменьшить консольный вывод  kubectl -n openbao exec -ti openbao-0 -- /bin/sh  / $ bao namespace list Keys ---- teams/  / $ bao namespace scan Keys ---- teams/ teams/team1/  # иерархичненько  # Давайте включим userpass  bao auth enable -path rootuserpass userpass  Success! Enabled userpass auth method at: rootuserpass/  / $ bao auth list Path             Type        Accessor                  Description                Version ----             ----        --------                  -----------                ------- rootuserpass/    userpass    auth_userpass_20de5797    n/a                        n/a token/           token       auth_token_5d75a77e       token based credentials    n/a userpass/        userpass    auth_userpass_4eda1230    n/a                        n/a  # а вот в неймспейсе teams он не включился, т.к. там отдельный auth  bao auth list -ns teams  Path      Type        Accessor               Description                Version ----      ----        --------               -----------                ------- token/    ns_token    auth_token_a834dcbc    token based credentials    n/a  bao auth enable -path teamsuserpass -ns teams  userpass  Success! Enabled userpass auth method at: teamsuserpass/  bao auth list -ns teams Path              Type        Accessor                  Description                Version ----              ----        --------                  -----------                ------- teamsuserpass/    userpass    auth_userpass_abc1479e    n/a                        n/a token/            ns_token    auth_token_a834dcbc       token based credentials    n/a  # да, но   bao auth list -ns teams/team1  Path      Type        Accessor               Description                Version ----      ----        --------               -----------                ------- token/    ns_token    auth_token_512f6e2c    token based credentials    n/a

Из минусов то, что auth включается для каждого namespace отдельно, из плюсов: если вы криво поменяли настройки, пострадает только один тенант, а не весь vault

Дальнейшая работа с vault сводится к тому, что вы просто добавляете -ns $ns -namespace $nsк командам, или же экспортируете переменную BAO_NAMESPACE.

При работе с secret-engines и мы дополнительно указываем неймспейсы в пути ns1/ns2/kv/data/secret

bao secrets enable -path root-storage kv Success! Enabled the kv secrets engine at: root-storage/  bao secrets list  Path             Type         Accessor              Description ----             ----         --------              ----------- cubbyhole/       cubbyhole    cubbyhole_89f7854d    per-token private secret storage identity/        identity     identity_5fccfa23     identity store root-storage/    kv           kv_ce8ed3db           n/a sys/             system       system_700a4a07       system endpoints used for control, policy and debugging  bao secrets enable -path team-storage -ns teams kv Success! Enabled the kv secrets engine at: team-storage/  bao secrets list -ns teams Path             Type            Accessor              Description ----             ----            --------              ----------- cubbyhole/       ns_cubbyhole    cubbyhole_ead9aa21    per-token private secret storage identity/        ns_identity     identity_2581dce4     identity store sys/             ns_system       system_618cbfdb       system endpoints used for control, policy and debugging team-storage/    kv              kv_787e719b           n/a  bao kv put teams/team-storage/subpath/secret value=secret Success! Data written to: teams/team-storage/subpath/secret  bao kv get  teams/team-storage/subpath/secret  ==== Data ==== Key      Value ---      ----- value    secret

Что касается написания политик:

  • Если мы находимся в родительском неймспейсе и нам нужно гранулярно нарезать права на нижележащий, то подставляем его имя. Например: teams/sys/policies/* или teams/team1/sys/policies/*

  • Если мы находимся во вложенном неймспейсе и хотим назначать права внутри него, то весь синтаксис как при обычной работе без неймспейсов (мы не знаем, что над нами кто-то есть)

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

Из дальнейших перспектив, которые могут нас ожидать: «Looking ahead, the namespaces working group is actively exploring improvements such as namespace sealing, non-hierarchical namespaces, per-namespace storage backends, and plugin isolation»

За последние 6 месяцев проект сильно развился и разработчики всё еще держат темп. Поэтому призываю вас следить за судьбой проекта, вдруг еще завезут что-то энтерпрайзное, за что не нужно платить 🙂 и нам это пригодится.

Заодно хотелось бы передать привет своему товарищу и экс-коллеге по МТС Натигу: @Nat0892 как тебе такое? Будешь менять vault на openbao ?)


ссылка на оригинал статьи https://habr.com/ru/articles/923672/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *