Harbor 接入 Keycloak OIDC 后,Docker CLI 和机器人账号该怎么用
把 Harbor 接进 Keycloak 以后,我一开始以为事情很简单:用户已经在 Keycloak 里了,Harbor 应该自然就能认。真动手才发现,真正容易混的不是 OIDC 本身,而是三种登录场景。
浏览器打开 Harbor Web UI,走的是 OIDC 登录。
docker login 推拉镜像时,Docker CLI 要的是普通用户名加密码这种凭证。CI/CD、定时任务、跨项目脚本又不应该绑在某个真人账号上。这三件事分开以后,Harbor 的配置会清楚很多。这篇只讲这一条线:Harbor 用 Keycloak 做 OIDC 登录以后,Docker CLI 和自动化脚本分别该怎么拿凭证。
先别急着在 Keycloak 里建用户
只在 Keycloak 里创建用户,不等于 Harbor 已经认识这个人。
Harbor 的 OIDC 登录大概是这样:用户从 Harbor 登录页跳到 Keycloak,Keycloak 验证通过后再把用户带回 Harbor。第一次登录时,Harbor 才会把这个 OIDC 用户 onboard 到自己的用户表。到了这一步,这个用户才能被加进 Harbor 项目、分配角色、生成 CLI Secret。
所以顺序应该是:
- Harbor 先切到 OIDC auth。
- Harbor 注册成 Keycloak 的 OIDC client。
- 用户通过 Harbor 登录入口完成第一次 OIDC 登录。
- Harbor 里出现这个用户记录。
少了第三步,Harbor 只知道“有一个外部身份源”,但还没有一个能被项目权限引用的 Harbor 用户。
还有一个切换限制要提前看清楚:Harbor 只有在数据库里没有额外本地用户时,才能从 database auth 切到 OIDC auth。如果已经创建过
admin 之外的本地用户,就不能直接切过去。这个限制很容易在测试环境里被忽略,等到生产环境才发现按钮是灰的。Keycloak 里需要准备什么
在 Keycloak 的目标 Realm 里新建一个 OIDC client,名字常见就叫
harbor。名字本身不重要,真正要对齐的是 Client ID:Keycloak 里填什么,Harbor 里也填什么。这个 client 至少要打开:
Client authenticationStandard flow
登录地址按 Harbor 的外部访问地址填。假设 Harbor 是
https://harbor.example.com,几个关键值通常是:Harbor 接入 Keycloak OIDC 后,Docker CLI 和机器人账号该怎么用 (text)
Root URL: https://harbor.example.com
Valid redirect URIs: https://harbor.example.com/c/oidc/callback
Web origins: https://harbor.example.com保存以后,去
Credentials 页面复制 Client Secret。Harbor 后面要用它证明自己就是这个 OIDC client。如果准备用 Keycloak group 管 Harbor 权限,还要给 client 补一个 group mapper。这里最容易填错的不是 mapper 名字,而是 claim 名。Keycloak 发给 Harbor 的 ID token 里如果叫
groups,Harbor 侧的 Group Claim Name 就填 groups;如果旧系统已经用 group,两边就都保持 group。这里别靠猜。拿一次 ID token 看里面到底有什么 claim,比在两个控制台里来回试快很多。
Harbor 里的 OIDC 配置
用 Harbor 本地管理员
admin 登录,进入:Harbor 接入 Keycloak OIDC 后,Docker CLI 和机器人账号该怎么用 (text)
Administration -> Configuration -> Authentication把
Auth Mode 改成 OIDC,然后填 OIDC provider 信息:Harbor 接入 Keycloak OIDC 后,Docker CLI 和机器人账号该怎么用 (text)
OIDC Provider Name: keycloak
OIDC Provider Endpoint: https://<keycloak-host>/realms/<realm>
OIDC Client ID: harbor
OIDC Client Secret: <Keycloak client secret>
OIDC Scope: openid,profile,email,offline_access
Username Claim: preferred_usernameOIDC Provider Endpoint 不是 Keycloak 首页,也不是某个登录页面。对 Keycloak 来说,它通常是 Realm 地址:Harbor 接入 Keycloak OIDC 后,Docker CLI 和机器人账号该怎么用 (text)
https://<keycloak-host>/realms/<realm>Harbor 会从这个地址下面的 discovery document 找 authorization、token、userinfo 等 endpoint。可以先用 curl 验证:
Harbor 接入 Keycloak OIDC 后,Docker CLI 和机器人账号该怎么用 (shell)
curl -fsSL "https://<keycloak-host>/realms/<realm>/.well-known/openid-configuration"如果这个地址在 Harbor 所在网络里访问不了,Harbor 的
Test OIDC Server 就不该通过。先看网络、证书和 Realm 地址,不要一上来就怀疑 Harbor 配错了。Primary Auth Mode 也值得停一下。开启后,Harbor 默认登录会走 OIDC;如果还想用本地 DB 登录,需要显式访问 /account/sign-in。保留 admin 做兜底账号时,这个入口很有用。OIDC Scope 至少要有 openid,通常还会带 profile 和 email。如果希望 Harbor 后续能刷新 CLI Secret 背后的 token,还要加 offline_access。要用 group claim,就把能下发 group claim 的 scope 也加进去。具体 scope 名看 Keycloak 的 client scope 配置,不要看到别人写 groups 就直接照抄。Automatic onboarding 建议开启。开启后,Harbor 会用 Username Claim 里的值自动创建 Harbor 用户名,常见值是 preferred_username。但这里有一个硬前提:Keycloak 返回给 Harbor 的 ID token 里真的有这个 claim。没有的话,第一次登录会卡在 onboarding。最后检查页面底部显示的
Redirect URI。它必须和 Keycloak client 里的 Valid redirect URIs 对得上。Web UI 登录通过,不代表 Docker CLI 能用
OIDC 登录是浏览器流程。Docker CLI 和 Helm CLI 不会跟着 Harbor 重定向到 Keycloak,登录后再跳回来。
这就是 CLI Secret 存在的原因。
用户先通过 OIDC 登录 Harbor Web UI。登录成功后,点击右上角用户名,进入
User Profile 或 Account Settings,复制或生成自己的 CLI Secret。然后用这个 secret 登录 registry:Harbor 接入 Keycloak OIDC 后,Docker CLI 和机器人账号该怎么用 (shell)
docker login harbor.example.com用户名通常是 Harbor 里的用户名,也就是
Username Claim 最终落下来的值,例如 Keycloak 的 preferred_username。密码填 Harbor 生成的 CLI Secret。不要填 Keycloak 密码。也不要把 Keycloak access token 直接塞给 Docker CLI。
一个用户只有一个 CLI Secret。重新生成或手动创建新的 CLI Secret 后,旧的会失效。官方文档里还有一个细节:CLI Secret 和 OIDC ID token 有关,Harbor 会尝试刷新 token;如果 OIDC provider 没给 refresh token,或者刷新失败,CLI Secret 也可能失效。遇到这种情况,重新走一次 OIDC 登录,让 Harbor 拿到新的 token。
这解释了很多“昨天还能 docker login,今天突然不行”的问题。
自动化脚本别用人的 CLI Secret
如果是 CI/CD、定时任务、平台脚本,我不会让它拿某个人的 CLI Secret。
人的 CLI Secret 跟这个人的 OIDC 身份绑定。人离职、权限变化、重新生成 secret、token 刷新失败,脚本都会跟着受影响。Harbor 给自动化准备的是 robot account。
Harbor 现在有两类 robot account:
- project robot account:只能在创建它的项目里操作。
- system robot account:可以覆盖多个项目,也可以按项目分配权限。
只给单个项目推拉镜像,用 project robot account 就够。要跨项目做平台自动化,比如批量创建仓库、统一推镜像、跑同步任务,用 system robot account 更合适。权限还是要收窄,尤其不要因为“省事”就 cover all projects,然后给一堆大权限。
robot account 登录方式很朴素:
Harbor 接入 Keycloak OIDC 后,Docker CLI 和机器人账号该怎么用 (shell)
docker login harbor.example.com
Username: <prefix><project_name>+<account_name>
Password: <secret>system robot account 的用户名格式通常是:
Harbor 接入 Keycloak OIDC 后,Docker CLI 和机器人账号该怎么用 (text)
<prefix><account_name>project robot account 的用户名格式通常是:
Harbor 接入 Keycloak OIDC 后,Docker CLI 和机器人账号该怎么用 (text)
<prefix><project_name>+<account_name>默认 prefix 常见是
robot$,但 Harbor 允许管理员改。最终以你环境里导出的 secret JSON 或页面展示为准。还有一个不该省略的细节:Harbor 不会在创建后继续保存 robot secret 的明文。创建完成时要下载 JSON 或复制 secret。错过了也不是世界末日,可以 refresh secret,但旧 secret 会被替换,依赖它的脚本也要一起更新。
流程总结
- 确认 Harbor 数据库里没有
admin之外的本地用户,否则先处理认证模式切换问题。 - 在 Keycloak 创建
harborclient,配好 redirect URI、client secret、必要的 group mapper。 - 在 Harbor 填 OIDC provider,
OIDC Scope从openid,profile,email,offline_access起步,需要 group 再加对应 scope。 - 开启
Automatic onboarding,Username Claim用preferred_username,前提是 ID token 里确实有它。 - 用
Test OIDC Server和 discovery endpoint 先测通。 - 用一个普通 Keycloak 用户从 Harbor 登录页走一遍,确认 Harbor 里出现用户。
- 给真人用户生成 CLI Secret,只用于个人 Docker/Helm CLI。
- 给 CI/CD 和平台脚本创建 robot account,按 project 或 system 的边界分配权限。
这条线配完以后,身份关系就清楚了:Keycloak 管人,Harbor 管项目权限和 registry 访问,CLI Secret 给真人的命令行用,robot account 给自动化用。它们相关,但不是一回事。
最容易踩的坑
- 只在 Keycloak 建用户,却没让用户从 Harbor 走过一次 OIDC 登录。
OIDC Provider Endpoint填成 Keycloak 首页,而不是 Realm 地址。- Keycloak redirect URI 和 Harbor 页面底部显示的回调地址不一致。
Group Claim Name和 ID token 里的 claim 名对不上。Username Claim填了preferred_username,但 ID token 里没有这个字段。- Docker CLI 里填 Keycloak 密码,而不是 Harbor 的 CLI Secret。
- 把个人 CLI Secret 放进 CI/CD。
- 创建 robot account 后没保存 secret。