Search
Write a publication
Pull to refresh

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

Level of difficultyEasy
Reading time8 min
Views1.1K

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

Tags:
Hubs:
+11
Comments5

Articles