本文记录了我怎样给 OpenBao 接上 Okta 登录,再用 Okta 的组决定登录后的权限。
前情提要
第一篇把 OpenBao 装好并解封,第二篇加固了 Caddy 入口,结尾说下一步要创建日常用户,不再一直用 root。
这篇就干这个:Okta 负责确认您是谁,OpenBao 决定您能干什么。
本文接着前两篇的环境操作,默认您有一个 Okta 组织,也会用 bao 命令行。下文的域名、Okta 组织地址和应用名都是虚构的,各种 ID 都换成了占位符;CLIENT_ID、CLIENT_SECRET 需要从自己的 Okta 应用取得。
C 目标
整条路径是这样的:
---
config:
theme: base
themeVariables:
background: "#faf4ed"
primaryColor: "#fffaf3"
primaryTextColor: "#464261"
primaryBorderColor: "#286983"
secondaryColor: "#f2e9e1"
secondaryTextColor: "#464261"
tertiaryColor: "#faf4ed"
tertiaryTextColor: "#464261"
lineColor: "#286983"
textColor: "#464261"
edgeLabelBackground: "#faf4ed"
---
flowchart TB
A["浏览器 / OpenBao CLI"] --> B["Okta OIDC 应用"]
B -- "认证通过,返回 sub 和 baogroups" --> C["OpenBao OIDC role:okta"]
C --> D["OpenBao Identity Entity"]
D --> E["Group alias:bao-admin"]
D -. "预留,尚未验证" .-> F["Group alias:bao-user"]
E --> G["External group:bao-admin"]
F --> H["External group:bao-user"]
G --> I["OpenBao Policy"]
H --> I
classDef step fill:#fffaf3,stroke:#286983,color:#464261;
classDef pending fill:#f2e9e1,stroke:#907aa9,color:#464261;
class A,B,C,D,E,G,I step;
class F,H pending;
这里分三层:
- Okta Group:控制谁能访问这个应用,并通过 claim 告诉 OpenBao 用户属于哪些组。
- OpenBao OIDC role:规定怎样校验登录信息,用哪个字段当用户、哪个字段当组,以及默认给什么策略。
- OpenBao Identity Group 和 Policy:根据外部组成员身份,给出真正的资源权限。

配置里会有 default_role=okta,它只表示没指定 role 时用哪个登录配置,不代表所有人都是管理员。危险的是把 admin 策略直接配给一个不限制用户和组的公共 role,所以下面的 role 只给 default。
Dm Okta 这边
先用 Okta 管理员建这几样东西:
| 对象 | 名称 | 用途 |
|---|---|---|
| 用户 | baoadmin |
OpenBao 日常管理账号 |
| 组 | bao-admin |
OpenBao 管理员组 |
| 组 | bao-user |
普通用户组,目前是空的 |
| OIDC Web 应用 | OpenBao Prod |
OpenBao 的登录入口 |
操作路径如下,页面名称可能随版本变化:
Directory → Groups:创建bao-admin、bao-user。Directory → People:创建用户baoadmin,加入bao-admin。Applications → Applications → Create App Integration:选择OIDC - OpenID Connect和Web Application。- 应用名填
OpenBao Prod,使用Authorization Code,并分配给上面两个组。

Sign-in redirect URI 填:
https://openbao.miyunda.com/ui/vault/auth/oidc/oidc/callback
Sign-out redirect URIs :
https://openbao.miyunda.com/ui
光把组分配给应用还不够,OpenBao 并不知道用户属于哪个组,还要在 Okta 的 token claims 里加一条:
Name: baogroups
Value: user.getGroups({'group.profile.name': 'bao-', 'operator': 'STARTS_WITH'}).![profile.name]
bao- 这个前缀让它只返回跟 OpenBao 有关的组。语法见 Okta 表达式语言文档。管理员登录时,token 里应该是这样:
{
"sub": "<OKTA_USER_ID>",
"baogroups": ["bao-admin"]
}
Em OpenBao 这边
先指定地址,启用 OIDC 认证:
export BAO_ADDR='https://openbao.miyunda.com'
bao auth enable oidc
然后写 OIDC 配置,oidc_discovery_url 填自己的 Okta 组织地址:
bao write auth/oidc/config \
oidc_discovery_url='https://<okta-org>.okta.com' \
oidc_client_id="$CLIENT_ID" \
oidc_client_secret="$CLIENT_SECRET" \
default_role='okta'
再建一个中性的 role:
bao write auth/oidc/role/okta \
role_type='oidc' \
bound_audiences="$CLIENT_ID" \
allowed_redirect_uris='https://openbao.miyunda.com/ui/vault/auth/oidc/oidc/callback' \
user_claim='sub' \
groups_claim='baogroups' \
oidc_scopes='openid,profile,email' \
policies='default'
这样谁通过这个 role 登录,都只有 default 策略,管理员身份留给后面的组映射决定。
各参数的含义见 OpenBao 的 JWT/OIDC 文档,Okta 专门的说明在这里。
F 第一次登录失败

打开 https://openbao.miyunda.com,已经出现 Sign in with Okta。点进去也跳到了 Okta,可就是登录不了,OpenBao 还提示 provider window 在认证结束前关闭了。
跳转成功,不代表 Okta 同意放行。去 Okta 后台 Reports → System Log 找到了这条:
{
"eventType": "application.policy.sign_on.deny_access",
"displayMessage": "Access has been denied because the policy requirements could not be satisfied by the users’ current set of available authenticator enrollments",
"outcome": {
"result": "SUCCESS",
"reason": "The policy requirements could not be satisfied by the users’ current set of available authenticator enrollments"
}
}
注意 result 是 SUCCESS。这个成功说的是拒绝访问这件事执行成功了,不是 Bao Admin 登录成功了。
账号其实已经注册了 Okta Verify、Push 和 FastPass,所以不是没有认证器,而是这个应用的登录策略要求的条件,当前环境满足不了。

最后我在这个应用对应的 Authentication Policy 里,把要求的两项认证改成一项,同时禁止只用密码登录。这下能登录了。
再说一次,我这是过家家,不是正经生产环境,在我这里我就喜欢“手机上点一下确认就能用了”这种流畅体验。想要严肃 MFA 策略的请自行研究。
正经企业的组通常是 Active Directory 与 Okta 映射, 然后 Okta 与 HashiCorp Vault 映射。
G 登录之后
登录成功后,用这个身份执行 bao token lookup,关键信息如下:
token_policies [default]
identity_policies []
policies [default]
token_meta_role okta
认证通了,role 是 okta,组策略还没有。
在网页的 Identity 页面能看到新建的 Entity,别名是一串 Okta User ID:
<OKTA_USER_ID>
因为 role 里写了 user_claim='sub'。这个 ID 不会变,比可以修改的邮箱地址稳妥。

两个终端
调试的时候我在同一台 LXC 里开了两个终端,一个操作 root,另一个用 baoadmin 登录。这样是不行的。
同一个系统用户下的多个终端,共用默认 token helper 保存的凭据。后一个窗口登录时换掉了凭据,前一个窗口下次请求读到的就是新 token,root 就这样被顶掉了。
调试时可以给每个 shell 单独设 BAO_TOKEN,或者用不同的系统用户。想看当前是谁,执行 bao token lookup,不需要打印 token 本身。
要么干脆用两个不同的 Linux 机器当客户端。
Am 映射外部组
OpenBao 这边要建 external group,不用手工维护成员列表:
用 root 运行
bao write identity/group \
name='bao-admin' \
type='external'
记下返回的 Group ID,再找到 OIDC 认证的 accessor:
bao auth list -format=json
建立 group alias:
bao write identity/group-alias \
name='bao-admin' \
mount_accessor='<OIDC_ACCESSOR>' \
canonical_id='<GROUP_ID>'
检查一下:
bao list identity/group-alias/id
bao read identity/group/id/<GROUP_ID>
alias 的关键字段:
canonical_id <GROUP_ID>
mount_accessor <OIDC_ACCESSOR>
mount_path auth/oidc/
mount_type oidc
name bao-admin
namespace_id root
name 必须和 Okta baogroups 传来的组名一致。mount_accessor 绑定的是这一处认证挂载,以后重建这个挂载,accessor 会变,映射也要重新检查。

验证整条链
先写一个几乎没有权限的策略 bao-admin-test.hcl:
path "sys/health" {
capabilities = ["read"]
}
挂到组上:
bao policy write bao-admin bao-admin-test.hcl
bao write identity/group/id/<GROUP_ID> \
policies='bao-admin'
这时 bao-admin 策略只是个测试用的名字。重新用 Okta 登录:
identity_policies [bao-admin]
policies [default]
通了。policies 是 token 自己的策略,identity_policies 是通过组继承来的,两个列表不需要一样。
折腾这么久,我的“管理员”目前能做的只有看健康状态,不过从 Okta 用户到 OpenBao 策略这条链算是验证过了。
bao-user 组还是空的,普通用户登录、权限边界,以及离组后权限多久收回,这些我都还没试过。
Bdim 管理员策略
接下来要把测试策略换成真正的管理员策略。我一开始写的是这样:
# 权限过宽,不要照抄
path "auth/*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
path "identity/*" {
capabilities = ["create", "read", "update", "delete", "list", "patch"]
}
path "sys/policies/acl/*" {
capabilities = ["create", "read", "update", "delete", "list"]
}
看着不是 root,实际上差不多。能改策略、改 role、改组和别名,就能给自己扩权。这个策略没有叫 root,但它能把自己变成 root。排除 sys/raw/*、sys/generate-root* 这些路径也解决不了这个问题。反正只有我自己用,无所谓了。
人多的可以按职责拆开,没试过,只是想象:
| 策略 | 范围 |
|---|---|
bao-operator |
健康状态、审计信息、有限的运维操作 |
bao-secrets-admin |
指定 KV 挂载的管理,不是所有秘密 |
bao-pki-admin |
指定 PKI 挂载的管理 |
bao-iam-admin |
严格限制的身份与认证配置管理,单独授权和审计 |
| 应急账号 | 极少使用的高风险操作,单独保管 |
小结
baoadmin 已经能通过 Okta 登录 OpenBao,bao-admin 组也映射到了 OpenBao 中的我们自定义的管理员策略。
评论