Привет, меня зовут Симигин Евгений и я являюсь ключевым экспертом по внедрению 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 можно наблюдать такую картину:

Слева вы можете видеть список неймспейсов, давайте переключимся в 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 ?)