EN

OpenBao v Docker Compose — init, unseal a AppRole

Provoz self-hosted OpenBao v Docker Compose: init a unseal, AppRole, KV secrets, audit log, hledání příčiny 403, rekey, zálohy, upgrade a migrace z Vaultu.

Co tato dovednost pokrývá

Provoz self-hosted OpenBao (open-source fork HashiCorp Vaultu) jako služby Docker Compose na jednom hostu: první inicializace, unseal po každém restartu a jeho typické chyby, zapnutí secrets engines, přihlašování aplikace přes AppRole místo statického tokenu, ukládání a čtení KV secrets, výměna unseal klíčů (rekey), nový root token, zálohy a obnova a nakonec znovuzaložení storu, když se klíče ztratí. Je to provozní vrstva — návrh politik a integraci konkrétní knihovny řeší dokumentace OpenBao .

Kdy ji použít

  • Při zprovoznění OpenBao v Compose stacku vedle aplikace, která z něj čte secrets
  • Po restartu hostu nebo kontejneru, když aplikace hlásí, že secret nejde přečíst (store je sealed)
  • Když unseal hlásí chybu, nebo když chcete vyměnit unseal klíče či root token
  • Při přidávání nového secretu nebo nové aplikace s vlastní AppRole a politikou
  • Před upgradem nebo migrací — záloha storage

Služba v Compose

openbao:
  image: openbao/openbao:2.4.1
  command: server -config=/openbao/config/openbao.hcl
  environment:
    BAO_ADDR: http://127.0.0.1:8200   # CLI uvnitř kontejneru jinak zkouší https
  volumes:
    - ./openbao/config:/openbao/config:ro
    - openbao-data:/openbao/file
  healthcheck:
    # healthy = API odpovídá; zapečetěný store není chyba kontejneru
    test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8200/v1/sys/health?sealedcode=200&uninitcode=200"]
    interval: 10s
  restart: unless-stopped
  # žádné ports: — klienti chodí po interní síti Compose

volumes:
  openbao-data:      # pojmenovaný volume, jinak data zmizí s kontejnerem
# openbao/config/openbao.hcl
storage "file" {
  path = "/openbao/file"
}

listener "tcp" {
  address     = "0.0.0.0:8200"
  tls_disable = true   # jen na privátní síti Compose; ven vždy přes TLS
}

api_addr = "http://openbao:8200"
ui       = false

Všechny příkazy níže se pouštějí z adresáře s Compose souborem jako docker compose exec openbao bao … — port nemusí být vůbec publikovaný na host.

Tokeny a klíče do terminálu

Většina potíží při ruční obsluze není v OpenBao, ale v tom, jak se token nebo klíč dostane do příkazu. read -rs je správná cesta (hodnota nezůstane v historii ani na obrazovce), má ale tři vlastnosti, na které se snadno zapomene:

  • Nic nevypíše — žádnou výzvu, žádné hvězdičky. Kurzor jen čeká, až vložíte hodnotu a stisknete Enter.
  • Pouštějte ho samostatně, nikdy jako součást vloženého bloku. Když se do terminálu vloží víc řádků najednou, read jako vstup spolkne další vložený řádek (nebo prázdný) a proměnná zůstane bez tokenu — potichu. Všechna další volání pak končí 403 permission denied.
  • Vkládejte pravým tlačítkem nebo Ctrl+Shift+V (Windows Terminal, WSL); ve skrytém vstupu se vložení nijak neprojeví, takže není vidět, jestli proběhlo.

Proto hodnotu po načtení hned očistěte od neviditelných znaků a zkontrolujte délku (tabulka uvádí typické délky; u tokenu je skutečná kontrola bao token lookup):

read -rs BAO_TOKEN
BAO_TOKEN=$(printf %s "$BAO_TOKEN" | tr -cd 'A-Za-z0-9._-'); export BAO_TOKEN; echo "délka: ${#BAO_TOKEN}"
HodnotaOčekávaná délka
root token, OpenBao 2.x (s.…; jiné tokeny se liší)26
unseal klíč, base6444 (bez = na konci)
unseal klíč, hex66
AppRole role_id / secret_id36 (UUID)

Délka 0 znamená, že se nic nenačetlo. Když se skrytý vstup vzpírá, jsou dvě náhradní cesty:

read -rp "Token: " BAO_TOKEN     # viditelně…
clear; export BAO_TOKEN; echo "délka: ${#BAO_TOKEN}"   # …a hned smazat obrazovku

nebo přes dočasný soubor, který se úplně vyhne vkládání do terminálu:

install -m 600 /dev/null ~/.bao-token && nano ~/.bao-token
export BAO_TOKEN=$(tr -cd 'A-Za-z0-9._-' < ~/.bao-token); echo "délka: ${#BAO_TOKEN}"
rm ~/.bao-token                  # po skončení práce

Proměnná platí jen v okně terminálu, kde jste ji načetli — v jiném okně je prázdná.

První start: init

docker compose up -d openbao
docker compose exec openbao bao status      # Initialized false, Sealed true
docker compose exec openbao bao operator init -key-shares=5 -key-threshold=3

init vypíše jednou pět unseal klíčů a root token. Hned je přesuňte do password manageru — ne do souboru v repozitáři, ne do .env, ne do chatu nebo ticketu. Klíče jsou v base64 — 44 znaků bez = na konci (dílek má 33 bajtů, takže padding nevzniká); hex podoba má 66 znaků. S -format=json dostanete obě podoby, unseal_keys_b64 a unseal_keys_hex; ukládejte a používejte jen jednu z nich.

Inicializujte hned po startu: sys/init nevyžaduje autentizaci, takže kdokoli na stejné síti by server mohl inicializovat jako první a klíče si nechat. Pokud bao status ukáže Initialized true u serveru, který jste neinicializovali, neodpečeťujte ho — smažte volume a začněte znovu.

Jediný operátor může zvolit -key-shares=1 -key-threshold=1; pak ale jeden klíč otevírá všechno.

Unseal — po initu a po každém restartu

docker compose exec openbao bao operator unseal    # 3× s různými klíči
docker compose exec openbao bao status             # Sealed false

Příkaz se na klíč ptá skrytě, takže klíč nezůstane v historii shellu. bao status vrací exit code 0 (odpečetěno), 2 (zapečetěno) a 1 (chyba) — hodí se do skriptů a monitoringu:

docker compose exec -T openbao bao status >/dev/null; echo $?

Rozpracovaný unseal (např. po špatném klíči) vynulujete:

docker compose exec openbao bao operator unseal -reset

Když vložení do skrytého promptu opakovaně selže, předejte klíč jako argument — přes proměnnou, ať nezůstane v historii (na okamžik je vidět v ps, na hostu s jedním uživatelem přijatelné):

read -rs K
K=$(printf %s "$K" | tr -cd 'A-Za-z0-9+/='); echo "délka: ${#K}"; docker compose exec openbao bao operator unseal "$K"; unset K
ChybaCo znamená
'key' must be a valid hex or base64 stringVložený text není klíč — nejčastěji root token (začíná s.), nebo celý řádek výpisu včetně Unseal Key 2: . Průběh zůstává, stačí vložit správný klíč.
failed to compute combined key: all parts must be the same lengthJeden klíč má jinou délku — zkomolený, s mezerou navíc, nebo jiný formát (b64 vs. hex). -reset a znovu.
cipher: message authentication failed po třetím klíčiKlíče jsou z jiného initu (store byl mezitím založen znovu).
Klient dostává 503 / Vault is sealedStore po restartu nikdo neodpečetil.
403 permission denied u každého příkazu s -e BAO_TOKENBAO_TOKEN je prázdný nebo z jiného initu — zkontrolujte délku (viz Tokeny a klíče do terminálu ).

Mounty: KV, transit, AppRole

Jednou po prvním unsealu, s root tokenem načteným do BAO_TOKEN podle předchozí sekce . Nejdřív ověřte, že je to opravdu root token tohoto storu:

docker compose exec -T -e BAO_TOKEN openbao bao token lookup | grep policies    # [root]
docker compose exec -e BAO_TOKEN openbao bao secrets enable -path=secret kv-v2
docker compose exec -e BAO_TOKEN openbao bao secrets enable transit   # volitelné: jen pokud přes něj něco šifrujete
docker compose exec -e BAO_TOKEN openbao bao auth enable approle
docker compose exec -e BAO_TOKEN openbao bao secrets list
docker compose exec -e BAO_TOKEN openbao bao auth list

AppRole pro aplikaci

Aplikace nemá držet statický token. Přihlásí se dvojicí role_id + secret_id a dostane krátce žijící token, který smí jen to, co dovolí její politika.

# openbao/policies/myapp.hcl — jen čtení vlastních secrets
path "secret/data/myapp/*" {
  capabilities = ["read"]
}
# politika a role (s root tokenem z předchozího kroku)
docker compose exec -T -e BAO_TOKEN openbao bao policy write myapp - < openbao/policies/myapp.hcl
docker compose exec -e BAO_TOKEN openbao bao write auth/approle/role/myapp \
  token_policies=myapp token_ttl=5m token_max_ttl=15m

# role_id (není tajný) — vypíše se, zkopírujte do .env
docker compose exec -e BAO_TOKEN openbao bao read -field=role_id auth/approle/role/myapp/role-id

# secret_id (je tajný) — rovnou do .env, nikdy na terminál (upravte název proměnné)
touch .env && chmod 600 .env
printf 'MYAPP_SECRET_ID=%s\n' "$(docker compose exec -T -e BAO_TOKEN openbao \
  bao write -f -field=secret_id auth/approle/role/myapp/secret-id)" >> .env

Obě hodnoty patří do .env aplikace (gitignored), pak kontejner aplikace znovu vytvořte (docker compose up -d app), aby je načetl. Ověření, že login funguje — vypíše jen TTL, ne token:

read -rs SECRET_ID      # samostatně, pak vložit secret_id a Enter
printf %s "$SECRET_ID" | docker compose exec -T openbao \
  bao write -field=token_duration auth/approle/login role_id=<role_id> secret_id=-
unset SECRET_ID

Rotace secret_id: vydat nový, vyměnit v .env, znovu vytvořit kontejner a starý zničit podle accessoru:

docker compose exec -e BAO_TOKEN openbao bao list auth/approle/role/myapp/secret-id
docker compose exec -e BAO_TOKEN openbao bao write \
  auth/approle/role/myapp/secret-id-accessor/destroy secret_id_accessor=<accessor>

Co smí který token

Při ladění politik se vyplatí zeptat přímo serveru, místo čtení HCL:

docker compose exec -e BAO_TOKEN openbao bao policy read myapp
docker compose exec -e BAO_TOKEN openbao bao token capabilities secret/data/myapp/api_token   # co smí váš token
docker compose exec -e BAO_TOKEN openbao bao token capabilities -accessor <accessor> secret/data/myapp/api_token   # co smí cizí token, bez jeho hodnoty

Pozor na prefix KV v2: politika musí jmenovat secret/data/… (čtení hodnoty) a secret/metadata/… (výpis a verze), i když CLI s -mount=secret píše jen myapp/….

KV secrets

Hodnotu posílejte přes stdin (value=-), ať se neobjeví v historii ani ve výpisu procesů:

read -rs SECRET          # samostatně, pak vložit hodnotu a Enter
printf %s "$SECRET" | docker compose exec -T -e BAO_TOKEN openbao \
  bao kv put -mount=secret myapp/api_token value=-
unset SECRET

docker compose exec -e BAO_TOKEN openbao bao kv list -mount=secret myapp
docker compose exec -e BAO_TOKEN openbao bao kv metadata get -mount=secret myapp/api_token   # verze, bez hodnoty
docker compose exec -T -e BAO_TOKEN openbao bao kv get -mount=secret -field=value myapp/api_token | wc -c   # délka místo hodnoty
docker compose exec -e BAO_TOKEN openbao bao kv rollback -mount=secret -version=1 myapp/api_token

Secret uložte dřív, než aplikaci přepnete na čtení z OpenBao. Jakmile ho čte odtud, nemá mít druhý zdroj — viz fail closed níže.

Audit log

Úložiště secrets bez auditu neodpoví na otázku „kdo a kdy četl tenhle secret“. Od OpenBao 2.4 se audit zařízení deklaruje v konfiguraci serveru; zapnutí přes API (bao audit enable) je od 2.3.2 zakázané, pokud v konfiguraci nepovolíte unsafe_allow_api_audit_creation — file device totiž umí zapisovat kamkoli.

# openbao/config/openbao.hcl
audit "file" "file" {
  description = "Audit log do souboru"
  options {
    file_path = "/openbao/logs/audit.log"
  }
}
# do služby openbao v Compose
    volumes:
      - openbao-logs:/openbao/logs
# a openbao-logs: do horních volumes:

Nový pojmenovaný volume patří rootovi a proces OpenBao neběží jako root, proto mu ho před prvním startem jednou předejte — jinak nemůže otevřít audit.log a podle pravidla níže odmítá všechny požadavky:

docker compose run --rm --no-deps --user root --entrypoint chown openbao -R openbao:openbao /openbao/logs
docker compose up -d openbao                              # restart → zase unseal
docker compose exec -e BAO_TOKEN openbao bao audit list
docker compose exec openbao tail -n 3 /openbao/logs/audit.log

Hodnoty v záznamech jsou HMAC, ne čitelné secrets. Dvě věci k provozu: když OpenBao do žádného audit zařízení nedokáže zapsat, požadavky odmítá (plný disk = výpadek), a log roste bez omezení — dejte mu logrotate nebo ho posílejte do centrálního logování (file_path = "stdout" a sběr přes Docker logging driver).

Aplikace dostává 403: postup hledání

Fail-closed aplikace hlásí jen „secret nejde přečíst“. Příčin je víc a v řetězu na sebe navazují, takže je projděte popořadě od OpenBao k aplikaci (app je služba aplikace, MYAPP_* její proměnné):

# 1. OpenBao je inicializovaný a odpečetěný
docker compose exec openbao bao status | grep -E 'Initialized|Sealed'

# 2. Aplikace na něj dosáhne — z jejího kontejneru, ne z hostu
docker compose exec app curl -s -o /dev/null -w '%{http_code}\n' http://openbao:8200/v1/sys/health
#    200 ok · 503 sealed · 501 neinicializovaný · 000 jiná síť nebo DNS
#    (prázdný výstup nebo 000 může znamenat i image bez curl — zkuste: docker compose exec app wget -qO- http://openbao:8200/v1/sys/health)

# 3. Kontejner aplikace má AppRole v prostředí (délky, ne hodnoty; obě 36)
docker compose exec app sh -c 'echo role=${#MYAPP_ROLE_ID} secret=${#MYAPP_SECRET_ID}'

# 4. Kontejner běží s aktuální konfigurací (Recreate = běží starší verze)
docker compose up -d --dry-run 2>&1 | grep -i recreate

# 5. AppRole login projde (viz AppRole výše)
# 6. Secret existuje a má čekanou délku
docker compose exec -T -e BAO_TOKEN openbao bao kv get -mount=secret -field=value myapp/api_token | wc -c

# 7. Politika role ho smí číst
docker compose exec -e BAO_TOKEN openbao bao policy read myapp

Krok 3 a 4 bývají příčinou častěji, než by se čekalo: hodnoty v .env se do běžícího kontejneru nepropíšou samy, je potřeba docker compose up -d app.

Root token: zrušit a v případě potřeby vyrobit znovu

Root token slouží jen k nastavení. Až existují role a secrets, zrušte ho:

docker compose exec -e BAO_TOKEN openbao bao token revoke -self
unset BAO_TOKEN

Nový root token se vyrobí z unseal klíčů:

docker compose exec openbao bao operator generate-root -init   # vypíše OTP a nonce
docker compose exec openbao bao operator generate-root         # 3× s unseal klíči → encoded token
docker compose exec openbao bao operator generate-root -decode=<encoded_token> -otp=<otp>

Rekey: nová sada unseal klíčů

Když klíče chcete vyměnit (odešel člověk, který jeden držel, klíče byly uložené nepořádně) — potřebujete prahový počet současných klíčů:

docker compose exec openbao bao operator rekey -init -key-shares=5 -key-threshold=3
docker compose exec openbao bao operator rekey          # 3× se starými klíči → 5 nových
docker compose exec openbao bao operator rekey -status
docker compose exec openbao bao operator rekey -cancel  # rozpracovaný rekey zahodit

Nové klíče se vypíšou jednou, stejně jako u initu. Staré po dokončení přestanou platit.

Zálohy a obnova (file storage)

File storage zálohujte se zastaveným kontejnerem, ať je kopie konzistentní. Záloha je zašifrovaná — bez unseal klíčů je k ničemu, s nimi je to celý store:

docker compose stop openbao
docker run --rm -v <projekt>_openbao-data:/data:ro -v ~/backups/openbao:/backup alpine \
  tar czf /backup/openbao-$(date -u +%Y%m%dT%H%M%SZ).tgz -C /data .
docker compose start openbao      # a znovu unseal

Obnova do prázdného volume:

docker compose stop openbao
docker run --rm -v <projekt>_openbao-data:/data -v ~/backups/openbao:/backup alpine \
  sh -c 'find /data -mindepth 1 -delete && tar xzf /backup/<soubor>.tgz -C /data'
docker compose start openbao      # unseal klíči z doby zálohy

S Raft storage místo file se zálohuje snapshotem za běhu: bao operator raft snapshot save /tmp/bao.snap.

Upgrade OpenBao

Na jednom hostu je upgrade výměna image nad stejnými daty:

# 1. záloha pořízená při zastaveném OpenBao (viz Záloha a obnova) — je i cesta zpět: až nová verze
#    data zmigruje, starý image na nich už nemusí nastartovat
# 2. nová verze image v Compose, např. openbao/openbao:2.4.1 → novější 2.4.x
docker compose pull openbao
docker compose up -d openbao
docker compose exec openbao bao operator unseal      # 3×, nový proces je zapečetěný
docker compose exec openbao bao status | grep -E 'Version|Sealed'

Před skokem na vyšší minor verzi si přečtěte release notes — mezi verzemi se mění chování, které rozbije provoz (příklad: od 2.3.2 už nejde zapnout audit přes API). Verze zvedejte postupně, ne přes několik minor verzí najednou. Cesta zpět: zastavte OpenBao, obnovte zálohu do volume (viz Záloha a obnova), vraťte starý image a odpečeťte klíči z doby zálohy.

Migrace z HashiCorp Vaultu

OpenBao vychází z Vaultu 1.14, takže CLI i API jsou kompatibilní a většina skriptů projde po záměně vault → bao a VAULT_* → BAO_*. Přenos dat je ale opatrná záležitost. Oficiální průvodce je otestovaný jen pro Vault Community 1.14.1 (Raft, Shamir) a výslovně říká, že novější verze Vaultu jsou netestované a kompatibilita storage není zaručená. Hlavní body:

  • Vault starší než 1.14.1 nejdřív upgradovat na 1.14.1; Vault Enterprise testovaný není.
  • Před migrací záloha (Raft snapshot) a soupis mountů (vault secrets list, vault auth list) — mounty s pluginem, který OpenBao nemá, se při startu přeskočí a je potřeba je vypnout.
  • Z konfigurace odstranit disable_mlock (OpenBao mlock od 2.0 nepoužívá).
  • Nové tokeny mají jiný formát (s., b., r.); klienti, kteří formát tokenu kontrolují, se můžou rozbít.

U malého single-host nasazení bývá jednodušší založit čistý OpenBao a secrets do něj přenést znovu (kv get → kv put), než migrovat storage.

Znovuzaložení storu (klíče jsou ztracené)

Bez prahového počtu platných unseal klíčů se k datům nedostanete — ani rekey, ani nový root token. Zbývá store smazat a začít znovu. Nevratné: zmizí všechny secrets, politiky, AppRole i transit klíče (a s nimi platnost všeho, co jimi bylo podepsáno). Předtím volume zazálohujte, kdyby se klíče našly.

docker compose stop openbao
# záloha volume (viz výše), pak:
docker compose rm -f openbao
docker volume rm <projekt>_openbao-data
docker compose up -d openbao
docker compose exec openbao bao operator init -key-shares=5 -key-threshold=3
docker compose exec openbao bao operator unseal      # 3×

Po novém initu je všechno, co aplikace znala, neplatné. Postup:

  1. Mounty a politiky znovu (sekce výše).
  2. AppRole znovu — staré role_id a secret_id v .env aplikace nefungují, i když role se jmenuje stejně.
  3. Secrets znovu uložit — dřív, než aplikace začne číst, jinak fail closed odmítá.
  4. Kontejner aplikace převytvořit (docker compose up -d app), aby načetl nové hodnoty, a projít postup hledání 403 .

Záludnosti (jeden host, Compose)

  • Fail closed je správně. Aplikace, která čte secret z OpenBao, nemá při zapečetěném storu tiše sáhnout po proměnné prostředí — tím by se vrátil secret, který měl OpenBao nahradit. Endpoint, který secret potřebuje, má odmítat (403/503) a log má říct, který klíč se nepřečetl. Počítejte s tím, že po každém restartu hostu služba stojí, dokud někdo neodpečetí store, a monitorujte to (bao status exit code 2).
  • Manuální unseal vs. auto-unseal. Bez auto-unsealu (cloud KMS, transit jiného Vaultu/OpenBao) je unseal ruční krok člověka. Na jednom hostu to je cena za to, že klíč nikdy neleží na disku vedle dat.
  • Healthcheck kontejneru. /v1/sys/health vrací 503 při sealed a 501 před initem. Bez sealedcode=200&uninitcode=200 vypadá zapečetěný, ale zdravý server jako rozbitý kontejner: služby s depends_on: condition: service_healthy nenastartují a docker compose up --wait selže.
  • BAO_ADDR v kontejneru. CLI ve výchozím stavu zkouší https://127.0.0.1:8200; s tls_disable nastavte BAO_ADDR=http://127.0.0.1:8200, jinak bao status hlásí chybu TLS.
  • $ v .env. Docker Compose v .env interpoluje $NĚCO jako proměnnou — heslo nebo secret s dolarem se tiše usekne (varování The "…" variable is not set). Dolar zdvojte ($$) nebo hodnotu dejte do jednoduchých uvozovek.
  • Necitlivý výstup. Při ověřování vypisujte délku nebo TTL, ne hodnotu (… | wc -c, -field=token_duration); tokeny a secrets nemají končit v logu terminálu ani v historii (read -rs, value=-).
  • Po změně .env převytvořit kontejner. Běžící kontejner si drží prostředí a sítě z doby, kdy vznikl; docker compose up -d app ho převytvoří, restart ne. Kontejner, který „funguje“ už týdny, může být mimo síť, ve které OpenBao později přibyl.
  • Reverse proxy po převytvoření aplikace. Když nginx překládá jméno upstreamu jen při startu, po převytvoření aplikace hlásí could not be resolved a vrací 502. Převytvořte i proxy, nebo jí nastavte resolver 127.0.0.11 s proměnnou v proxy_pass.
  • mlock. OpenBao od 2.0 mlock nepoužívá — cap_add: IPC_LOCK ani disable_mlock nepotřebuje (na rozdíl od návodů pro Vault).
  • Port nepublikovat. OpenBao stačí na interní síti Compose; pokud musí ven, tak jen přes TLS reverse proxy a s omezením na konkrétní klienty.

Časté otázky

Co je OpenBao?

Open-source fork HashiCorp Vaultu pod Linux Foundation (licence MPL 2.0). CLI se jmenuje bao místo vault, proměnné prostředí BAO_ADDR a BAO_TOKEN místo VAULT_*, API a většina příkazů jsou stejné.

Proč je OpenBao po restartu zapečetěný (sealed)?

Hlavní šifrovací klíč storu se nikdy neukládá na disk. Po každém startu procesu ho musí složit operátor z unseal klíčů (bao operator unseal), dokud není nastavený auto-unseal přes KMS nebo jiný Vault/OpenBao. Do té doby server žádná tajemství nevydá.

Co znamená chyba „failed to compute combined key: all parts must be the same length“?

Jeden ze zadaných unseal klíčů má jinou délku než ostatní — je zkomolený při kopírování, nebo míchá formáty (base64 z běžného výpisu initu a hex z unseal_keys_hex). Průběh se zahodí; spusťte bao operator unseal -reset a zadejte tři klíče znovu ve stejném formátu.

Dají se unseal klíče vygenerovat znovu?

Pro existující store jen přes bao operator rekey, a to vyžaduje prahový počet současných klíčů. Když je nemáte, data ve storu jsou nedostupná a zbývá jen smazat storage a udělat nový bao operator init.

Proč OpenBao na všechno odpovídá „403 permission denied“, i když mám root token?

Nejčastěji proto, že proměnná BAO_TOKEN je prázdná — read -rs nic nezobrazí, a když se vloží celý blok příkazů najednou, načte místo tokenu prázdný řádek. Zkontrolujte délku (echo ${#BAO_TOKEN}); root token z initu OpenBao 2.x má podobu s.… a 26 znaků (jiné tokeny mají délku jinou — skutečná kontrola je bao token lookup).