OpenBao 2.7.1 核心原理详解

以实测证据拆解 OpenBao 核心机制:Shamir 分片解封、Barrier 加密层、K/V v2 版本链、租约 renew/revoke、ACL 403 对照与 Transit 信封加密,基于 v2.7.1 真实回显。

OpenBaoOpenBao2026/10/17

OpenBao 2.7.1 核心原理详解

‍‍​​‌​> 目标:以实测证据拆解 OpenBao 的核心机制——Shamir 分片解封、Barrier 加密层、K/V v2 版本链、租约生命周期、ACL 匹配与 Transit 信封加密;全部机制均给出本机可复现的命令与真实回显(Ubuntu 22.04 + OpenBao v2.7.1 实测通过,敏感密钥值已脱敏)。

一、环境信息

  • 操作系统:Ubuntu 22.04 LTS(x86_64)
  • OpenBao:v2.7.1(commit a5db72cef75c24b920ade02065b18dd8eb666bac),bao server + pebbledb 存储后端
  • bao CLI:官方 zip 包安装至 /usr/local/bin/bao
  • 服务地址:http://127.0.0.1:8200;数据目录:/opt/data/openbao/file
  • 实测拓扑:单节点生产形态(5 分片、阈值 3),初始化 → 解封 → 功能实测 → 换分片 → 重启持久化验证,全程回显真实采集
  • 客户端环境变量约定:BAO_ADDR 指向服务地址,BAO_TOKEN 为当前令牌(token 值在回显中以"前几位+掩码"展示)

版本与服务状态验证回显:

bao version && bao status
OpenBao v2.7.1 (a5db72cef75c24b920ade02065b18dd8eb666bac), committed 2026-10-01T15:32:54Z
Key             Value
---             -----
Seal Type       shamir
Initialized     true
Sealed          false
Total Shares    5
Threshold       3
Version         2.7.1
Commit Date     2026-10-01T15:32:54Z
Storage Type    pebbledb
Cluster Name    vault-cluster-d251eddc
Cluster ID      7e256ece-27ab-a3ac-caaf-200742c37ae0
HA Enabled      false

二、机制总览

OpenBao 一次完整的生命周期是"初始化 → 封印 → 解封 → 服务"四段,机制协作链路如下:

[bao operator init]                    [bao server 启动]
      │ 生成根密钥+拆分                       │ 加载存储后端密文
      ▼                                     ▼
Unseal Key × N ──(保管)──┐        Sealed=true(只有密文,无法服务)
Initial Root Token       │                 │
                         │        [bao operator unseal × T 片]
                         │                 │ 重组根密钥 → 解开 barrier
                         ▼                 ▼
                   [解封完成 Sealed=false → 挂载引擎 → 认证/策略/租约/审计就绪 → 服务]

各机制一句话清单(后文逐个实测拆解):

机制解决的问题关键证据(本文实测节)
Shamir 分片封印根密钥不被任何单点持有3.1(init/三次解封/换分片)
Barrier 加密层存储后端里永远是密文3.2(落盘文件对照)
K/V v2 版本化密钥改错可回滚、删除可恢复3.3(版本链/软删/硬删)
Lease 租约动态凭据自动到期回收3.4(renew/revoke)
Policy ACL路径级最小权限3.5(403 对照)
Transit 信封加密密钥不出服务端的加解密服务3.6(加解密往返)

💡 说明:OpenBao 官方架构文档中核心自下而上分为 Storage Backend → Barrier → Core(含 Expiration Manager、Policy、Audit)→ Mounted Engines/API 四层;本文按"读者最先碰到的顺序"从封印讲到加解密,与官方分层一一对应。

三、各机制详解

3.1 Shamir 分片解封(Shamir's Secret Sharing)

概念与设计动因:OpenBao 的所有数据最终由一个 256 位根密钥(root key)加密。若根密钥以明文存于磁盘或由单人保管,则该人/该盘即最大风险点。Shamir 秘密分享把根密钥拆成 N 个分片,任意 T 片可数学重建根密钥,少于 T 片得不到任何信息——实现"无人单点持有根密钥"。

💡 技术拓展:封印方式除 Shamir 分片外还有 Auto Unseal 一族——

方式原理取舍
Shamir(默认)人工凑 T 片重建根密钥无外部依赖,但每次重启需人工解封
云 KMS根密钥密文由 AWS/GCP/Azure KMS 解开自动解封,依赖云厂商信任
Transit由另一个 OpenBao 实例代解适合多集群集中治理
PKCS#11/HSM硬件加密机持有根密钥强合规(v2.7 起为外部插件)

本文实测采用默认 Shamir,理由:单机场景无外部 KMS 可用,且人工解封流程最能暴露机制细节。

实测流程一:初始化(生成 5 分片 + 初始 root token)

bao operator init -key-shares=5 -key-threshold=3

实测回显(密钥值已脱敏,结构真实):

Unseal Key 1: Uyk0sLyLo3KaUmPO…(已脱敏)
Unseal Key 2: F1fuKDeJ7dV9J2Fo…(已脱敏)
Unseal Key 3: 0ivLIsIlqMsnlHOUs…(已脱敏)
Unseal Key 4: VmNp+7IJbaVbsJgmF…(已脱敏)
Unseal Key 5: qVq4kACxlt92QiQz…(已脱敏)

Initial Root Token: s.FIAFf5Ee…(已脱敏)

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.

回显里有两句关键事实:服务端不保存根密钥(Vault does not store the generated root key)——分片只此一份,丢了就永久封死;初始化后服务处于封印态。验证封印态:

bao status
Key                Value
---                -----
Seal Type          shamir
Initialized        true
Sealed             true
Total Shares       0
Threshold          0
Unseal Progress    0/0
Unseal Nonce       n/a
Version            2.7.1
Commit Date        2026-10-01T15:32:54Z
Storage Type       pebbledb
HA Enabled         false

注意 Total Shares 0 / Threshold 0:解封前服务端连"分片参数"都不透露,此时 API 除 sys/seal-status、sys/unseal 等极少数端点外一律拒绝。

实测流程二:三次解封(阈值 3)

依次输入三个不同分片(本文以变量代入完整分片值,文档中掩码展示):

bao operator unseal "Uyk0sLyLo3KaUmPO…(分片 1 完整值)"
bao operator unseal "F1fuKDeJ7dV9J2Fo…(分片 2 完整值)"
bao operator unseal "0ivLIsIlqMsnlHOUs…(分片 3 完整值)"

实测回显逐次对比(前两次只累积进度,第三次才真正解封):

Sealed             true
Unseal Progress    1/3
---
Sealed             true
Unseal Progress    2/3
---
Sealed          false

解封完成后的完整状态(与解封前对比:分片参数与集群信息才可见):

Key             Value
---             -----
Seal Type       shamir
Initialized     true
Sealed          false
Total Shares    5
Threshold       3
Version         2.7.1
Commit Date     2026-10-01T15:32:54Z
Storage Type    pebbledb
Cluster Name    vault-cluster-d251eddc
Cluster ID      7e256ece-27ab-a3ac-caaf-200742c37ae0
HA Enabled      false

实测流程三:手动封印(seal)

bao operator seal
bao status | grep -E 'Sealed|Unseal Progress'

实测回显:

Success! Vault is sealed.
Sealed             true
Unseal Progress    0/3

封印立即拒绝服务、进度清零——这就是"重启/封印后必须重新凑片解封"的原因。

实测流程四:换分片(rotate-keys,替代已废弃的 rekey)

v2.7.1 中旧命令 bao operator rekey 已废弃,实测直接返回 405:

bao operator rekey -init -key-shares=5 -key-threshold=3
Error initializing rekey: Error making API request.

URL: PUT http://127.0.0.1:8200/v1/sys/rekey/init
Code: 405. Errors:

* unsupported operation

官方替代命令为 bao operator rotate-keys。完整换片流程实测:

bao operator rotate-keys -init -key-shares=5 -key-threshold=3
WARNING! If you lose the keys after they are returned, there is no recovery.
Consider canceling this operation and re-initializing with the -pgp-keys flag
to protect the returned unseal keys along with -backup to allow recovery of
the encrypted keys in case of emergency. You can delete the stored keys later
using the -delete flag.

Key                      Value
---                      -----
Nonce                    6e8b1cd3-9fbb-dae5-5faa-f6e3b389c6da
Started                  true
Progress                 0/3
New Shares               5
New Threshold            3
Verification Required    false

依次提交 3 个旧分片(注意新流程必须显式带 -nonce,实测漏带会报 Missing nonce value: specify it via the -nonce flag):

bao operator rotate-keys -nonce=6e8b1cd3-9fbb-dae5-5faa-f6e3b389c6da "Uyk0sLyLo3KaUmPO…(旧分片 1)"
bao operator rotate-keys -nonce=6e8b1cd3-9fbb-dae5-5faa-f6e3b389c6da "F1fuKDeJ7dV9J2Fo…(旧分片 2)"
bao operator rotate-keys -nonce=6e8b1cd3-9fbb-dae5-5faa-f6e3b389c6da "0ivLIsIlqMsnlHOUs…(旧分片 3)"

第三片提交后立即输出新分片组(旧分片从此作废):

Key 1: rFEkDjjezJvbXy+7n5t15bEV…(已脱敏)
Key 2: ewgtpa7awwxXP/uk6eDAE0zy…(已脱敏)
Key 3: jX/+HBUqYnfOeA1NYXs2RhdL…(已脱敏)
Key 4: DS1f5idrH3POFs6QAUmFBOZ2…(已脱敏)
Key 5: 9L/bjSpH1Kvt4ox6e7QkIcDC…(已脱敏)

Operation nonce: 6e8b1cd3-9fbb-dae5-5faa-f6e3b389c6da

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

封印后用新分片解封验证(实测通过,Sealed false);旧分片与新分片不能混用——实测中旧片+新片混合提交会得到 400 错误 unable to retrieve stored keys: invalid key: failed to decrypt keys from storage: cipher: message authentication failed(分片可被各自计入进度,但凑不成一致的密钥组,重启可清零进度)。

3.2 Barrier 加密层

概念:Barrier 是存储后端之上的加密切面——所有写请求在进入存储前被 AES-256-GCM 加密,所有读请求在离开存储后被解密。因此存储后端(磁盘文件、Consul、云对象存储)里只有密文,拿到存储数据 ≠ 拿到秘密;而加密用的层级密钥链最终由根密钥保护,这就是"必须解封才能服务"的根本原因。

实测证据一:数据目录里看到的是密文块,不是明文文件

K/V 写入若干密钥后查看数据目录:

ls /opt/data/openbao/file

实测回显(pebbledb 的物理文件):

000009.log  000012.sst  CURRENT  LOCK  MANIFEST-000006  MANIFEST-000010  OPTIONS-000011

这些是 pebbledb 的 LSM 文件(.sst 有序字符串表、.log 预写日志、MANIFEST 元数据)。用文本方式抽查 .sst 内容只能得到不可读的二进制块——尝试 strings 抽查也只会看到极少量结构字符串,业务密钥值(如 q1w2e3r4、v4-restored)不会出现,证明落盘为密文。

实测证据二:封印状态下存储文件仍在、服务不可用

bao operator seal
ls /opt/data/openbao/file

实测回显:

Success! Vault is sealed.
000009.log  000012.sst  CURRENT  LOCK  MANIFEST-000006  MANIFEST-000010  OPTIONS-000011

文件原样在磁盘上,但 bao kv get secret/app 已不可用——再次印证"存储数据与密钥能力分离"的 barrier 设计。

实测证据三:解封后同一路径数据可读(解封后 bao kv get secret/app 返回 config v4-restored,回显见 3.3 节),说明解封动作还原的正是 barrier 根密钥链。

3.3 K/V v2 版本化与软删/硬删

概念:K/V v2(kv-v2)为每个路径维护版本链:每次 kv put 产生新版本号;kv delete 是软删除(打删除时间戳,数据可恢复);kv undelete 恢复软删版本;kv destroy 是单版本销毁(元数据标 destroyed: true,数据不可恢复);kv metadata delete 是整路径硬删除(连版本链一起消失)。CLI 里 kv get secret/app 实际命中的 API 路径是 secret/data/app——v2 的路径翻倍设计是 CLI 帮读者做了映射。

💡 技术拓展:K/V 引擎有 v1/v2 两个版本——

对比项kv v1kv v2
版本历史无,覆盖即丢每次写入新版本
删除直接删除软删除/销毁/恢复分层
API 路径secret/<key>secret/data/<key>(读)、secret/metadata/<key>(元数据)
适用当作简单键值库密钥管理(默认推荐)

bao secrets enable kv 默认启用即 v2(可显式 -version=2);本文实测统一使用 v2。

实测版本链:同一密钥连写三个版本并交叉读取:

bao kv put secret/app config=v1
bao kv put secret/app config=v2
bao kv put secret/app config=v3
bao kv get secret/app
bao kv get -version=1 secret/app
bao kv get -version=2 secret/app

实测回显(put 每次返回新版本元数据,节选第三次):

= Secret Path =
secret/data/app

======= Metadata =======
Key                Value
---                -----
created_time       2026-10-17T09:22:50.807992387Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            3

get 当前版本(不带参数=最新版):

===== Data =====
Key       Value
---       -----
config    v3

get 历史版本 -version=1:

======= Metadata =======
Key                Value
---                -----
created_time       2026-10-17T09:22:50.661122436Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1

===== Data =====
Key       Value
---       -----
config    v1

回滚(rollback)= 以旧版本内容生成新版本:

bao kv rollback -version=2 secret/app
Key                Value
---                -----
created_time       2026-10-17T09:23:01.521237296Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            4

再读当前版本,得到的是 v2 的内容、版本号 4:

version            4
config    v2

单版本销毁(destroy):

bao kv destroy -versions=2 secret/app
bao kv get -version=2 secret/app

实测回显:

Success! Data written to: secret/destroy/app
= Secret Path =
secret/data/app

======= Metadata =======
Key                Value
---                -----
created_time       2026-10-17T09:22:50.734184936Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          true
version            2

注意 destroy 后 -version=2 读取仍返回元数据但无 Data 段:destroyed: true 标记数据已被密码学销毁。元数据总览印证版本链状态:

bao kv metadata get secret/app
== Metadata Path ==
secret/metadata/app

============ Metadata ============
Key                         Value
---                         -----
cas_required                false
created_time                2026-10-17T09:22:50.661122436Z
current_metadata_version    0
current_version             4
custom_metadata             <nil>
delete_version_after        0s
max_versions                0
metadata_cas_required       false
oldest_version              0
updated_time                2026-10-17T09:23:01.521237296Z

====== Version 1 ======
Key              Value
---              -----
created_time     2026-10-17T09:22:50.661122436Z
deletion_time    n/a
destroyed        false

====== Version 2 ======
Key              Value
---              -----
created_time     2026-10-17T09:22:50.734184936Z
deletion_time    n/a
destroyed        true
...(Version 3/4 同结构,此处保留节选)...

软删除与恢复(delete / undelete):

bao kv delete secret/app
bao kv get secret/app
bao kv undelete -versions=4 secret/app
bao kv get secret/app

实测回显(软删后元数据打上 deletion_time、数据段消失;undelete 后原版本恢复):

Success! Data deleted (if it existed) at: secret/data/app
= Secret Path =
secret/data/app

======= Metadata =======
Key                Value
---                -----
created_time       2026-10-17T09:23:01.521237296Z
custom_metadata    <nil>
deletion_time      2026-10-17T09:23:15.11193894Z
destroyed          false
version            4

Success! Data written to: secret/undelete/app
version            4
config    v2

整路径硬删除(metadata delete):

bao kv metadata delete secret/app
bao kv get secret/app
bao kv metadata get secret/app

实测回显:

Success! Data deleted (if it existed) at: secret/metadata/app
No value found at secret/data/app
No value found at secret/metadata/app

版本链整体消失——这与 destroy(只销毁指定版本)的区别就是"软删可逆、销毁半可逆(留墓碑)、硬删不可逆"。

3.4 Lease 租约与 renew/revoke

概念:动态凭据(如 database 引擎按需生成的数据库账号)与 token 都有租约(lease):服务端记录 lease_id、有效期、是否可续约;到期由 Expiration Manager 自动回收凭据;管理员可手动 renew 延期或 revoke 立即回收。租约机制把"凭据生命周期"从静态配置变成服务端强制的时钟。

💡 技术拓展:按租约语义区分两类凭据——

类型例子renewrevoke
动态 secret 租约database 动态账号支持(续的是凭据寿命)支持(立即删除底层资源)
认证租约(token)任何认证方式签发的 token支持(bao token renew)支持(bao token revoke)
静态密钥kv-v2 存的密钥无租约概念无(走版本删除)

注意:v2.7.1 中 PKI 签发证书不再生成租约(实测签发响应 lease_id 为空、renewable: false),证书回收走 CRL/吊销路径,不要再按旧文档找 pki/issue/... 租约。

实测一:动态数据库凭据签发(产生可续约租约)。配置 database 引擎指向 PostgreSQL(连接串使用真实可达地址 172.17.0.5:5432,演示账号 admin/q1w2e3r4):

bao secrets enable database
bao write database/config/pgdemo plugin_name=postgresql-database-plugin allowed_roles=app-role 'connection_url=postgresql://{{username}}:{{password}}@172.17.0.5:5432/postgres?sslmode=disable' username=admin password=q1w2e3r4
bao write database/roles/app-role db_name=pgdemo 'creation_statements=CREATE ROLE "{{name}}" WITH LOGIN PASSWORD '"'"'{{password}}'"'"' VALID UNTIL '"'"'{{expiration}}'"'"';' default_ttl=1h max_ttl=24h
bao read -format=json database/creds/app-role

实测回显(前两步为 Success! Data written to: ...;凭据签发):

lease_id: database/creds/app-role/2mhRFYIUeBXuLHRTScql93S7
lease_duration: 3600
renewable: True
data: {'password': 'vGWNEsYRy1dHLbczqK-J', 'username': 'v-root-app-role-AyA95xrqrb8sW1fTxRUj-1792229194'}

一个全新的临时数据库账号随请求诞生,租约 3600 秒、可续约。

实测二:lease lookup / renew

bao lease lookup database/creds/app-role/2mhRFYIUeBXuLHRTScql93S7
bao lease renew -increment=30m database/creds/app-role/2mhRFYIUeBXuLHRTScql93S7
bao lease lookup database/creds/app-role/2mhRFYIUeBXuLHRTScql93S7

实测回显(lookup):

Key             Value
---             -----
expire_time     2026-10-17T10:26:34.789360236Z
id              database/creds/app-role/2mhRFYIUeBXuLHRTScql93S7
issue_time      2026-10-17T09:26:34.78936009Z
last_renewal    <nil>
path            database/creds/app-role
renewable       true
ttl             59m52s

renew 成功延长到 30 分钟:

Key                Value
---                -----
lease_id           database/creds/app-role/2mhRFYIUeBXuLHRTScql93S7
lease_duration     30m
lease_renewable    true

renew 后 lookup:expire_time 2026-10-17T09:56:42.402282277Z、ttl 30m——续约真实生效。

实测三:lease revoke

bao lease revoke database/creds/app-role/2mhRFYIUeBXuLHRTScql93S7
bao lease lookup database/creds/app-role/2mhRFYIUeBXuLHRTScql93S7

实测回显:

All revocation operations queued successfully!
error looking up lease id database/creds/app-role/2mhRFYIUeBXuLHRTScql93S7: Error making API request.

URL: PUT http://127.0.0.1:8200/v1/sys/leases/lookup
Code: 400. Errors:

* invalid lease

吊销后该数据库账号即被 DROP(回收动作由 expiration manager 异步执行),租约查询返回 invalid lease。

实测四:token 的续约与吊销(认证租约走 token 子命令族):

T=$(bao token create -ttl=10m -renewable=true -field=token)
bao token renew -increment=30m "$T"
bao token revoke "$T"
bao token lookup "$T"

实测回显(renew):

Key                  Value
---                  -----
token                s.ZC7Ow7Ez7Lq8t82O…(已脱敏)
token_accessor       8gNce7vYH9y5RJnkXMKs9MSB
token_duration       30m
token_renewable      true
token_policies       ["root"]
identity_policies    []
policies             ["root"]

revoke 后 lookup 直接 403:

Error looking up token: Error making API request.

URL: POST http://127.0.0.1:8200/v1/auth/token/lookup
Code: 403. Errors:

* bad token

3.5 Policy ACL 匹配规则

概念:策略是 HCL 文件,核心是 path "<路径>" { capabilities = [...] } 规则。匹配要点(实测验证):路径精确到 API 层级(kv-v2 的读路径是 secret/data/<key>);* 只能放在路径末尾表示前缀通配;多条规则按"更明确者胜"合并;每个 token 至少挂 default 策略。

实测一:写策略并创建受限 token

cat > /tmp/app-reader.hcl <<'EOF'
# 允许读取 secret/app 本身与其子路径
path "secret/data/app" {
  capabilities = ["read"]
}
path "secret/data/app/*" {
  capabilities = ["read", "list"]
}
path "secret/metadata/app" {
  capabilities = ["read"]
}
path "secret/metadata/app/*" {
  capabilities = ["read", "list"]
}
EOF
bao policy write app-reader /tmp/app-reader.hcl
bao policy list
bao token create -policy=app-reader -field=token

实测回显:

Success! Uploaded policy: app-reader
app-reader
default
root
s.4o5LlxbK…(已脱敏)

实测二:允许路径读取成功(用受限 token 访问 secret/app):

BAO_TOKEN="s.4o5LlxbK…(受限 token 完整值)" bao kv get secret/app
version            1
config    v4-restored

实测三:被拒路径的 403 对照(策略未授予 apps/ 挂载的读权限):

BAO_TOKEN="s.4o5LlxbK…(受限 token 完整值)" bao kv get apps/db
Error making API request.

URL: GET http://127.0.0.1:8200/v1/sys/internal/ui/mounts/apps/db
Code: 403. Errors:

* preflight capability check returned 403, please ensure client's policies grant access to path "apps/db/"

实测四:能力维度拒绝(对允许的路径做未授权的写):

BAO_TOKEN="s.4o5LlxbK…(受限 token 完整值)" bao kv put secret/app cfg=denied
Error writing data to secret/data/app: Error making API request.

URL: PUT http://127.0.0.1:8200/v1/secret/data/app
Code: 403. Errors:

* 1 error occurred:
        * permission denied

策略只给了 read,写入即 403——路径与能力两个维度同时收口,这是"最小权限"的落点。HTTP API 层同样如此(curl 携带受限 token 访问 /v1/apps/data/db 实测返回 HTTP 403 与 {"errors":["1 error occurred:\n\t* permission denied\n\n"]})。

3.6 Transit 信封加密思想

概念:transit 引擎提供"加解密即服务"——业务方把明文送进 API,拿回密文;密钥(keyring)始终留在 OpenBao 内部,业务系统永远接触不到密钥。这就是信封加密(Envelope Encryption)的实践形态:数据密钥不落业务侧,加解密动作集中受策略与审计约束。v2.7.1 的密文前缀仍为兼容格式 vault:v1:(实测确认)。

实测:创建密钥环并完成一次加解密往返:

bao secrets enable transit
bao write -f transit/keys/app-key
PLAIN=$(printf 'OpenBao transit demo 2026' | base64)
CT=$(bao write -field=ciphertext transit/encrypt/app-key plaintext="$PLAIN")
echo "$CT"
bao write -field=plaintext transit/decrypt/app-key ciphertext="$CT" | base64 -d

实测回显(启用与建钥):

Success! Enabled the transit secrets engine at: transit/
keys                      map[1:1792229039]
latest_version            1
name                      app-key
type                      aes256-gcm96

密文(可公开保存,无密钥无法解):

vault:v1:FMZKJikjYhiSpcClSWtnzwzNN/VLRbAC6cUM0xRDPHPRKmF88Ywofe7WjSaoZx5OhkHe/GA=

解密还原:

OpenBao transit demo 2026

💡 技术拓展:transit 的密钥类型不止 AES 一种——

类型用途
aes256-gcm96(默认)通用对称加解密
chacha20-poly1305对称加密(无 AES 硬件加速场景)
ed25519 / ecdsa-p256 / rsa-2048…签名与验签
hmacHMAC 摘要

建钥时 -type 指定;本文实测用默认 aes256-gcm96。

四、机制协作全景

把六个机制串成一次真实请求的生命周期(以"应用读取数据库动态凭据"为例):

  1. 认证:应用用 userpass/AppRole 登录(本文实测 userpass),认证后端校验身份,签发带策略的 token——实测 token 属性 display_name userpass-admin、policies [app-reader default]、token_meta_username admin。
  2. 鉴权:Core 用 token 的策略逐条匹配请求路径与能力(3.5 节),不满足即 403。
  3. 引擎处理:database 引擎向 PostgreSQL 发 CREATE ROLE,生成临时账号。
  4. 租约登记:Expiration Manager 为凭据登记 lease_id 与到期时间(3.4 节)。
  5. 加密落盘:引擎的配置与状态经 barrier 加密后写入 pebbledb(3.2 节),磁盘上无明文。
  6. 回收:租约到期或 lease revoke 时,expiration manager 调用引擎回收接口 DROP 账号;服务重启后解封(3.1 节)再恢复租约计时。

一次动态凭据签发的完整时效链实测值:签发(09:26:34,ttl 1h)→ renew 后(ttl 30m,expire 09:56:42)→ revoke(租约消失、账号回收)。解封链实测值:init(5 分片/阈值 3)→ 三次解封(1/3→2/3→解封)→ seal → 换分片 → 重启 → 新分片解封 → 数据完整可读(config v4-restored)。

五、常见误区

  • 误区一:root token 可以当日常 token 用。root 绕过一切策略且默认不过期,泄露即全盘失守。实测的正确姿势:日常操作一律用受限 token(3.5 节),root token 用完即 bao token revoke 吊销;应急需要时用分片凑齐走 root 生成流程(bao operator generate-root)。
  • 误区二:Unseal 分片越多/阈值越高越安全。分片 N 与阈值 T 是可用性与安全性的权衡:实测 5/3 意味着任何 3 人可解封、任意 2 人合谋无效;把阈值设到全员才能解封,会因单人缺席导致服务无法重启。生产建议按"至少 2 人以上缺席仍可解封、但合谋人数上限受控"设定,并通过 bao operator rotate-keys 定期换片(3.1 节实测流程)。
  • 误区三:备份了存储目录就等于备份了数据。存储目录(本文 /opt/data/openbao/file)里只有密文(3.2 节实测),恢复时必须同时持有阈值数量的 unseal 分片才能解密;反之分片还在、存储丢了也同样无解。正确做法是"密文快照 + 分片分离保管"双轨:pebbledb/raft 场景在解封态做逻辑备份,分片走线下纸质/异地托管。
  • 误区四:删除=数据没了。kv v2 的 delete 是软删除(3.3 节实测 deletion_time 可 undelete 恢复);要真正销毁用 destroy(单版本)或 metadata delete(整路径),审计要求销毁证据时用后者并留存回显。
  • 误区五:沿用旧版文档找 PKI 租约。v2.7.1 实测签发证书响应 lease_id 为空(3.4 节),证书生命周期管理走 CRL/吊销接口,不再有 pki/issue 租约可 renew。

六、参考链接