OpenBao – HA cluster

Ak sa chceme s OpenBaom posunúť do produkcie, mali by sme ho mať vysoko dostupné. Preto si dnes postavíme 3 nody, spojíme ich do clustra a využijeme funkcionalitu HAProxy a Keepalived.

Linux distribúciu, na ktorej bude bežať môj lab cluster, som si vybral Debian. Vy si samozrejme môžete zvoliť OS, ktorý preferujete vy. Ja nie som linuxák a keď som konfiguroval cluster na Debiane a na Rocky Linux, Debian mi prišiel jednoduchší.

Po-inštalačné úpravy OS

Tieto úpravy vykonáme na všetkých 3 budúcich nodeoch clustra.

Po základnej inštalácii Debianu,

  1. sa prihlásime účtom, ktorý sme vytvorili pri inštalačnom procese
  2. zmeníme uživateľa na root pomocou príkazu: su –
  3. pridáme účet, ktorý sme vytvorili pri inštalačnom procese, medzi sudoers príkazom: usermod -aG sudo <user>
  4. odhlásime sa a prihlásime sa znova účtom vytvoreným pri inštalačnom procese
  5. upravíme Debian source list tak, že zakomentujeme (# deb cdrom: …) cdrom ako source: sudo nano /etc/apt/source.list
  6. spustíme: sudo apt-get update

Inštalácia Openbao, Keepalived a HAProxy

Nainštalujeme si všetky potrebné balíky, pripravíme adresár a uživateľa pre openbao. V čase písanie tohto článku, bola posledná verzia openbaa 2.4.3. Vy si skontrolujte, ktorá verzia je aktuálna v čase vašej inštalácie a upravte curl a dpkg príkaz.

sudo apt-get install -y unzip curl gnupg2 keepalived haproxy
sudo mkdir -p /etc/openbao
sudo mkdir -p /opt/openbao/data
sudo mkdir -p /var/log/openbao
sudo useradd --system --home /etc/openbao --shell /bin/false openbao
sudo chown -R openbao:openbao /opt/openbao /var/log/openbao /etc/openbao
sudo curl -LO https://github.com/openbao/openbao/releases/download/v2.4.3/bao_2.4.3_linux_amd64.deb
sudo dpkg -i bao_2.4.3_linux_amd64.deb

Funkčnosť openbaa overíme príkazom: bao version

Konfigurácia Openbao clustra

Kvôli prehľadu, si zapíšeme IP adresy, ktoré sme si zvolili pri inštalácii jednotlivých nodeov.

  • bao01 – 10.100.1.41 – bao01.<domena>
  • bao02 – 10.100.1.42 – bao02.<domena>
  • bao03 – 10.100.1.43 – bao03.<domena>
  • VIP – 10.100.1.44 – bao.<domena>

Na každom node budúceho clustra upravíme /etc/openbao/config.hcl nasledovne:

bao01

listener "tcp" {
  address = "0.0.0.0:8200"
#  cluster_address = "10.100.1.41:8201"
  tls_disable = 1
}

storage "raft" {
  path = "/opt/openbao/data"
  node_id = "bao01"
}

api_addr = "http://10.100.1.41:8200"
cluster_addr = "http://10.100.1.41:8201"
ui = true

bao02

listener "tcp" {
  address = "0.0.0.0:8200"
#  cluster_address = "10.100.1.42:8201"
  tls_disable = 1
}

storage "raft" {
  path = "/opt/openbao/data"
  node_id = "bao02"
}

api_addr = "http://10.100.1.42:8200"
cluster_addr = "http://10.100.1.42:8201"
ui = true

bao03

listener "tcp" {
  address = "0.0.0.0:8200"
#  cluster_address = "10.100.1.43:8201"
  tls_disable = 1
}

storage "raft" {
  path = "/opt/openbao/data"
  node_id = "bao03"
}

api_addr = "http://10.100.1.43:8200"
cluster_addr = "http://10.100.1.43:8201"
ui = true

Rovnako na každom node upravíme konfiguráciu služby openbao príkazom /etc/systemd/system/openbao.service nasledovne:

[Unit]
Description=Openbao Server
After=network-online.target
Wants=network-online.target

[Service]
User=openbao
Group=openbao
ExecStart=/usr/bin/bao server -config=/etc/openbao/config.hcl
ExecReload=/bin/kill --signal HUP $MAINPID
LimitNOFILE=65536
Restart=on-failure

[Install]
WantedBy=multi-user.target

Štart služby/servera openbao:

sudo systemctl daemon-reload
sudo systemctl enable openbao
sudo systemctl start openbao

Skontrolujeme, či je služba správne spustená: sudo systemctl status openbao

Premenná BAO_ADDR

Štandardne je hodnota premennej BAO_ADDR nastavena na https://127.0.0.1:8200. Keďže nemáme (zatiaľ) zapnuté TLS, musíme jej hodnotu zmeniť na http://127.0.0.1:8200.

export BAO_ADDR=http://127.0.0.1:8200

Ako chceme otestovať, či máme všetko správne, môžeme si vyvolať status servera openbao: bao status.

Výstup bude veľmi podobný tomuto:

cytroon@bao01:~$ export BAO_ADDR=http://127.0.0.1:8200
cytroon@bao01:~$ bao status
Key                Value
---                -----
Seal Type          shamir
Initialized        false
Sealed             true
Total Shares       0
Threshold          0
Unseal Progress    0/0
Unseal Nonce       n/a
Version            2.4.3
Build Date         2025-10-22T20:21:42Z
Storage Type       raft
HA Enabled         true

Inicializácia Openbao clustra

Pre inicializáciu clustra, spustíme na node bao01 príkaz: bao operator init

Výstupu bude obsahovať kľúče pre unseal a root token. Všetky kľúče a token si starostlivo uschovajte.

cytroon@bao01:~$ bao operator init
Unseal Key 1: OHe0C+........................6zYdkprFUHs8sd
Unseal Key 2: iErxIguEe0b7Zji.......................dkprFf
Unseal Key 3: tOMCGO682...................OXLMbem5/RsXPZts
Unseal Key 4: WEKzNB8kEG25SG7G..................s-9M4DkOTK
Unseal Key 5: HHnifkdj..............F7jnfGdFLYpExaQglZJxk2

Initial Root Token: s.Z9Tdf...........VyscoiYR

Vault initialized with 5 key shares and a key threshold of 3. Please securely
distribute the key shares printed above. When the Vault is re-sealed,
restarted, or stopped, you must supply at least 3 of these keys to unseal it
before it can start servicing requests.

Vault does not store the generated root key. Without at least 3 keys to
reconstruct the root key, Vault will remain permanently sealed!

It is possible to generate new unseal keys, provided you have a quorum
of existing unseal keys shares. See "bao operator rotate-keys" for more
information.

Teraz vykonáme unseal nodu bao01 príkazom:

bao operator unseal

Openbao nás vyzve zadať ktorýkoľvek Unseal Key, ktorý nám bol vygenerovaný pri inicializácii. Túto akciu vykonáme 3x resp. toľko krát, kým nebudeme mať

Sealed             false

To, ktorý Unseal Key v poradí zadávame, nám ukazuje hodnota Unseal Progress. Výstup z tohto postupu môže vyzerať takto:

cytroon@bao01:~$ bao status
Key                Value
---                -----
Seal Type          shamir
Initialized        true
Sealed             true
Total Shares       5
Threshold          3
Unseal Progress    0/3
Unseal Nonce       n/a
Version            2.4.3
Build Date         2025-10-22T20:21:42Z
Storage Type       raft
HA Enabled         true
cytroon@bao01:~$ bao operator unseal
Unseal Key (will be hidden):
Key                Value
---                -----
Seal Type          shamir
Initialized        true
Sealed             true
Total Shares       5
Threshold          3
Unseal Progress    1/3
Unseal Nonce       e6b4abb9-a875-6a93-739c-c44fa9878b8c
Version            2.4.3
Build Date         2025-10-22T20:21:42Z
Storage Type       raft
HA Enabled         true
cytroon@bao01:~$ bao operator unseal
Unseal Key (will be hidden):
Key                Value
---                -----
Seal Type          shamir
Initialized        true
Sealed             true
Total Shares       5
Threshold          3
Unseal Progress    2/3
Unseal Nonce       e6b4abb9-a875-6a93-739c-c44fa9878b8c
Version            2.4.3
Build Date         2025-10-22T20:21:42Z
Storage Type       raft
HA Enabled         true
cytroon@bao01:~$ bao operator unseal
Unseal Key (will be hidden):
Key                     Value
---                     -----
Seal Type               shamir
Initialized             true
Sealed                  false
Total Shares            5
Threshold               3
Version                 2.4.3
Build Date              2025-10-22T20:21:42Z
Storage Type            raft
Cluster Name            vault-cluster-10fca6aa
Cluster ID              95ccea94-6468-07cc-77c1-cdff24814aed
HA Enabled              true
HA Cluster              n/a
HA Mode                 standby
Active Node Address     <none>
Raft Committed Index    27
Raft Applied Index      27
cytroon@bao01:~$

Keď sa nám úspešne podarilo urobiť unseal nodu bao01, môžeme pridať nody bao02 a bao03 k bao01 a tak vytvoriť cluster.

bao operator raft join http://10.100.1.41:8200"

Ak by bol na bao01 status Sealed stále TRUE, pridanie nodu skončí s chybou:

cytroon@bao02:~$ bao operator raft join http://10.100.1.41:8200
Error joining the node to the Raft cluster: Error making API request.

URL: POST http://127.0.0.1:8200/v1/sys/storage/raft/join
Code: 500. Errors:

* failed to join raft cluster: failed to get raft challenge

Po úspešnom pridaní ďalšieho nodu budeme oboznámení potvrdzujúcim hlásením:

cytroon@bao02:~$ bao operator raft join http://10.100.1.41:8200
Key       Value
---       -----
Joined    true
cytroon@bao02:~$

Po pridaní všetkých zvyšných nodeov, ich treba postupne unseal. Či ich openbao vidí ako plnohodnotných členov clustra, skontrolujeme príkazom na node bao01:

cytroon@bao01:~$ export BAO_TOKEN='s.Z9Tdf...........VyscoiYR'
cytroon@bao01:~$ bao operator raft list-peers
Node     Address             State       Voter
----     -------             -----       -----
bao01    10.100.1.41:8201    leader      true
bao02    10.100.1.42:8201    follower    true
bao03    10.100.1.43:8201    follower    true

Poznámka: Pre tento úkon, už potrebujeme root token, ktorý bol vygenerovaný pri inicializácii clustra.

Týmto úkonom sme overili, že všetky nody sú členmi clustra. A čo je to teda ten Raft? :-)

Raft je distribuovaný konsenzuálny algoritmus, ktorý OpenBao používa na to, aby mali všetky nody v clustri rovnaký a konzistentný stav dát (storage backend). Nahrádza potrebu externých databáz ako Consul.

Raft zabezpečuje tri hlavné veci:

  1. Voľba lídra (leader election) – V clustri je vždy zvolený jeden leader, ktorý prijíma zápisy. Ostatné nody sú followers.
  2. Replikácia logu – Každý zápis (napr. vytvorenie secretu, zmena konfigurácie) ide najprv do leadera a ten ho replikuje na ostatné nody. Zápis je platný až keď väčšina (quorum) nodov potvrdí prijatie.
  3. Odolnosť voči výpadkom (fault tolerance) – Cluster môže fungovať aj pri výpadku menšiny nodov (napr. 3-node cluster vydrží výpadok 1 nodu). Pri výpadku leadera zvyšné nody automaticky zvolia nového.

Konfigurácia HAProxy

Čo robí v našom prostredí HAProxy:

  1. Smeruje klientov vždy na aktuálneho leadera – Sleduje /v1/sys/health na každom node a automaticky vyberá ten, ktorý je „leader = true“.
  2. Skryje internú topológiu clustra – Klienti sa pripájajú na jednu IP/URL, nie na konkrétny node.
  3. Zabezpečí vysokú dostupnosť pre API – Ak leader padne, HAProxy ho prestane používať a presmeruje traffic na nový leader bez potreby meniť konfiguráciu klientov.
  4. Chráni cluster pred chybnými požiadavkami – Vie robiť healthchecks a odstraňovať nefunkčné nody z rotácie.

Konfigurácia HAProxy je v našom prípade jednoduchá. Stačí na každom node editovať haproxy.cfg (sudo nano /etc/haproxy/haproxy.cfg) nasledovne:

global
        maxconn 4096
        log /dev/log    local0
        log /dev/log    local1 notice
        chroot /var/lib/haproxy
        stats socket /run/haproxy/admin.sock mode 660 level admin
        stats timeout 30s
        user haproxy
        group haproxy
        daemon

        # Default SSL material locations
        ca-base /etc/ssl/certs
        crt-base /etc/ssl/private

        # See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate
        ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE->
        ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
        ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        timeout connect 10s
        timeout client  5s
        timeout server  10s
        errorfile 400 /etc/haproxy/errors/400.http
        errorfile 403 /etc/haproxy/errors/403.http
        errorfile 408 /etc/haproxy/errors/408.http
        errorfile 500 /etc/haproxy/errors/500.http
        errorfile 502 /etc/haproxy/errors/502.http
        errorfile 503 /etc/haproxy/errors/503.http
        errorfile 504 /etc/haproxy/errors/504.http

frontend openbao_front
    bind *:9200
    default_backend openbao_leader

backend openbao_leader
    balance roundrobin
    option httpclose
    option httpchk GET /v1/sys/health
    http-check expect status 200

    default-server inter 2s fall 3 rise 3

    server node1 10.100.1.41:8200 check
    server node2 10.100.1.42:8200 check
    server node3 10.100.1.43:8200 check

…a potom už len:

sudo systemctl restart haproxy
sudo systemctl enable haproxy

Konfigurácia Keepalived

Keepalived poskytuje virtuálnu IP (VIP), ktorá sa automaticky presúva medzi HAProxy uzlami:

  1. Zjednotený entry-point pre klientov – VIP = jedna IP adresa, ktorú používame v BAO_ADDR, systemd jednotkách, CI/CD, PKI integráciách…
  2. Failover medzi HAProxy inštanciami – Ak vypadne HAProxy na node A, VIP sa automaticky presunie na node B. Klienti si nič nevšimnú.
  3. Eliminuje single point of failure na úrovni proxy – Aj keby OpenBao cluster bežal, bez Keepalived by výpadok jedného HAProxy znamenal výpadok API.

Pre konfiguráciu Keepalived máme tiež samostatný konfiguračný súbor (/etc/keepalived/keepalived.conf), no na rozdiel od haproxy, bude mat na každom node rôzne parametre.

bao01

vrrp_instance OPENBAO_VIP {
    state MASTER
    interface ens192
    virtual_router_id 51
    priority 150
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass 123456
    }

    virtual_ipaddress {
        10.100.1.44/24
    }
}

bao02

vrrp_instance OPENBAO_VIP {
    state BACKUP
    interface ens192
    virtual_router_id 51
    priority 100
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass 123456
    }

    virtual_ipaddress {
        10.100.1.44/24
    }
}

bao03

vrrp_instance OPENBAO_VIP {
    state BACKUP
    interface ens192
    virtual_router_id 51
    priority 90
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass 123456
    }

    virtual_ipaddress {
        10.100.1.44/24
    }
}

Po úprave konfiguračných súborov, stačí aj tu už len povoliť a naštartovať službu:

sudo systemctl enable keepalived
sudo systemctl start keepalived

Pre overenie, kde sa aktuálne nachádza VIP, použijeme príkaz: ip a | grep 10.100.1.44

Testovanie HA

Zmena premennej BAO_ADDR na VIP a vylistovanie status openbao clustra:

cytroon@bao01:~$ export BAO_ADDR=http://10.100.1.44:8200
cytroon@bao01:~$ bao status
Key                     Value
---                     -----
Seal Type               shamir
Initialized             true
Sealed                  false
Total Shares            5
Threshold               3
Version                 2.4.3
Build Date              2025-10-22T20:21:42Z
Storage Type            raft
Cluster Name            vault-cluster-10fca6aa
Cluster ID              95ccea94-6468-07cc-77c1-cdff24814aed
HA Enabled              true
HA Cluster              https://10.100.1.41:8201
HA Mode                 active
Active Since            2025-11-16T00:19:22.052223588Z
Raft Committed Index    34
Raft Applied Index      34
cytroon@bao01:~$

Presun VIP na bao02 (na bao02 preto, lebo v konfigurácii má bao02 druhé najvyššie číslo prority):

Na bao01 zastavíme službu keepalived: sudo systemctl stop keepalived a na bao02 skontrolujeme prítomnosť VIP: ip a | grep 10.100.1.44

Úplný test HA:

  1. sudo shutdown now na bao01
  2. prihásime sa na bao02 a následne skontrolujeme kto je leadrom
    cytroon@bao02:~$ export BAO_TOKEN='s.Z9Tdf...........VyscoiYR'
    cytroon@bao02:~$ bao operator raft list-peers
    Node     Address             State       Voter
    ----     -------             -----       -----
    bao01    10.100.1.41:8201    follower    true
    bao02    10.100.1.42:8201    leader      true
    bao03    10.100.1.43:8201    follower    true
  3. na bao02 skontrolujeme, či sa presunula aj VIP
    cytroon@bao02:~$ ip a | grep 10.100.1.44
     inet 10.100.1.44/24 scope global secondary proto 0x12 ens192

Po obnovení komunikácie bao01 je nutné tento node zase unseal. (Existuje možnosť, ako nody po reštarte unsealnuť automaticky, ale to si vysvetlíme v niektorom z ďalších článkov.) Po obnovení sa na bao01 presunie VIP (kvôli nastavenej priorite) ale master node (bao02) na to nemá dôvod.

A tak: HAProxy na bao01, kde je aktuálna VIP, zistí, že leaderom je bao02, a tak komunikáciu presmeruje na bao02.

Záver

Na záver by som chcel dodať, že konfiguráciu operačného systému, haproxy a keepalived si pred presunutím do prevádzky nechajte skontrolovať skúsenými linuxovými a bezpečnostnými špecialistami. Bezpečnosť je v tomto prípade obzvlašť dôležitá.

Súvisiace články:

OpenBao – centrálna správa, uchovávanie a distribúcia citlivých dát

OpenBao – vytvorenie configu a základné nastavenie

OpenBao – politiky, tokeny a reálne použitie

OpenBao – PKI

 

Author: Martin

Infrastructure engineer | virtualization & cloud enthusiast | vSphere specialist | blogger | Veeam Vanguard 2021,2022,2023 | VMware vExpert 2017 - 2025 | VMCE | VCP-VCF Architect, VCP-DCV, NV, TKO, VCAP-DCV, CompTIA Security+ | Slovak VMUG Leader | Slovak VUG Leader | husband&father