Backstage 集成 OpenShift OAuth 认证提供者:从 OAuth 客户端配置到 Kubernetes 插件免密接入
【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage
OpenShift 认证提供者是 Backstage 内置在core-plugin-api/frontend-plugin-api中的一套 OAuth 认证方案,它允许用户通过 OpenShift 集群的 OAuth 服务完成登录,并进一步利用用户身份访问 OpenShift/Kubernetes 集群资源。本文以仓库中的官方文档 docs/auth/openshift/provider.md 为主体,结合 plugins/auth-backend-module-openshift-provider 的源码实现,完整讲解 OAuth 客户端的创建、app-config.yaml配置、后端模块安装、前端KubernetesAuthProviders接线,以及底层认证器的工作原理。读完本文,你将能够在自己的 Backstage 应用中启用 OpenShift 登录,并让 Kubernetes 插件以"用户本人权限"(On-Behalf-Of)方式访问 OpenShift 集群。
使用场景:让 Kubernetes 插件使用用户自己的 OpenShift 权限
OpenShift 认证提供者的典型用途是与 Kubernetes 插件 联动:当用户通过 OpenShift OAuth 登录 Backstage 后,Kubernetes 插件可以利用 OAuth 2.0 的On-Behalf-Of(OBO)流程,通过 Kubernetes Client Side Provider 以该用户的身份和权限访问 OpenShift 集群,而不是以服务账号的统一身份访问。
在 docs/features/kubernetes/authentication.md 中可以看到,Kubernetes 插件的认证分为两类:
- Server Side Providers(如
aws、azure、googleServiceAccount、serviceAccount):以应用整体身份访问集群,所有登录用户共享同一权限; - Client Side Providers(如
aks、google、oidc):以每个登录用户的身份访问集群,用户在集群中被授权到什么范围,就能看到什么资源。
OpenShift 的接入方式走的是 Client Side 路线:把 OpenShift 当作一个oidc客户端侧提供者接入KubernetesAuthProviders,从而让每个 Backstage 用户以其 OpenShift 账户身份访问集群。
要让这套流程成立,还需要满足一个前提:Backstage catalog 中必须存在对应的User实体,且实体名称与 OpenShift 用户名完全一致。这一点会在后面的displayNameMatchingUserEntityName登录解析器中再次体现。
前端接线:将 OpenShift 注册为 KubernetesAuthProviders 的 OIDC 提供者
虽然 OpenShift 认证提供者本身不原生支持 OIDC,但你可以在KubernetesAuthProviders配置中把它当作 OIDC 提供者来使用。仓库文档给出了packages/app/src/apis.ts中的标准写法:
import { KubernetesAuthProviders, kubernetesAuthProvidersApiRef, } from '@backstage/plugin-kubernetes'; import { googleAuthApiRef, microsoftAuthApiRef, openshiftAuthApiRef, } from '@backstage/core-plugin-api'; export const apis: AnyApiFactory[] = [ // ... createApiFactory({ api: kubernetesAuthProvidersApiRef, deps: { microsoftAuthApi: microsoftAuthApiRef, googleAuthApi: googleAuthApiRef, openshiftAuthApi: openshiftAuthApiRef, }, factory({ microsoftAuthApi, googleAuthApi, openshiftAuthApi }) { return new KubernetesAuthProviders({ microsoftAuthApi, googleAuthApi, oidcProviders: { openshift: { async getIdToken(_) { return await openshiftAuthApi.getAccessToken('user:full'); }, }, }, }); }, }), //... ];其中openshiftAuthApiRef定义在@backstage/core-plugin-api中,并从 packages/core-plugin-api/src/apis/definitions/auth.ts 导出。
需要特别强调一个容易被忽视的差异(原文档中的 note):
OpenShift 认证 API不实现
OpenIdConnectApi接口,也就是说它不返回 ID token。它返回的是access token,Kubernetes 集成会将这个 access token 当作 ID token 使用。这是它与标准 OIDC 认证流程唯一的功能性区别。
因此在上面的getIdToken(_)中,实际调用的是openshiftAuthApi.getAccessToken('user:full'),请求的 scope 必须是user:full(这一点在源码的 scopes 定义中也被强制要求,见下文)。
在 OpenShift 中创建 OAuth 客户端
在开始配置 Backstage 之前,请确认 OpenShift 集群中存在可用的 OAuth 客户端。OpenShift 的配置方式是创建一个OAuthClient自定义资源。
创建时必须设置回调地址(redirect URI),格式如下:
https://<fqdn>/api/auth/openshift/handler/frame其中<fqdn>是你的 Backstage 应用对外暴露的域名,路径/api/auth/openshift/handler/frame由认证提供者的回调处理器约定,不能随意更改。改好域名后,OAuth 授权码流程的回调就会落在 Backstage 后端的 OpenShift 处理器上。
应用配置:app-config.yaml 中的 provider 配置
将 provider 配置添加到app-config.yaml根级auth配置下:
auth: environment: development providers: openshift: development: clientId: ${AUTH_OPENSHIFT_CLIENT_ID} clientSecret: ${AUTH_OPENSHIFT_CLIENT_SECRET} authorizationUrl: ${AUTH_OPENSHIFT_AUTHORIZATION_URL} tokenUrl: ${AUTH_OPENSHIFT_TOKEN_URL} openshiftApiServerUrl: ${OPENSHIFT_API_SERVER_URL} ## uncomment to set lifespan of user session # sessionDuration: { hours: 24 } # supports `ms` library format (e.g. '24h', '2 days'), ISO duration, "human duration" as used in code # sessionDuration: 1d signIn: resolvers: - resolver: displayNameMatchingUserEntityNameOpenShift provider 是一个包含以下配置键的结构:
| 配置键 | 说明 | 格式示例 |
|---|---|---|
clientId | OpenShift OAuth 客户端的 Client ID | my-backstage |
clientSecret | 与该 OAuth 客户端绑定的 Client Secret | 从环境变量注入 |
authorizationUrl | OpenShift OAuth 客户端授权端点 | https://<oauth-client-route>/oauth/authorize |
tokenUrl | OpenShift OAuth 客户端令牌端点 | https://<oauth-client-route>/oauth/token |
openshiftApiServerUrl | OpenShift API 服务器端点 | https://<openshift-api> |
sessionDuration | (可选)用户会话的存活时长 | 支持ms库格式(如'24h'、'2 days')、ISO 时长、代码中使用的 "human duration" |
signIn | 登录流程配置,含用于将认证提供者用户与 Backstage catalog 中用户实体匹配的resolvers(通常一个 resolver 就足够) | 见下方说明 |
这些键的类型约束在 plugins/auth-backend-module-openshift-provider/config.d.ts 中有精确声明:
clientId、authorizationUrl、tokenUrl、openshiftApiServerUrl均为必填字符串;clientSecret标记为@visibility secret,应从环境变量注入,避免明文入库;callbackUrl为可选字段(未配置时由提供者根据运行时环境推导);signIn.resolvers目前仅支持displayNameMatchingUserEntityName,可附带布尔选项dangerouslyAllowSignInWithoutUserInCatalog;sessionDuration的类型为HumanDuration | string。
关于 scope 的强制要求
OpenShift provider 需要使用的 scope 为user:full。这不仅是前端调用getAccessToken('user:full')的约定,在底层认证器createOAuthAuthenticator的声明中也被固化为必选 scope,见 plugins/auth-backend-module-openshift-provider/src/authenticator.ts:
scopes: { required: ['user:full'], },后端安装:注册 auth-backend 模块
OpenShift 认证提供者的后端实现位于独立的 npm 包@backstage/plugin-auth-backend-module-openshift-provider中。在 Backstage 根目录执行:
yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-openshift-provider然后在packages/backend/src/index.ts中注册该模块:
backend.add(import('@backstage/plugin-auth-backend')); /* highlight-add-start */ backend.add(import('@backstage/plugin-auth-backend-module-openshift-provider')); /* highlight-add-end */该模块在源码层面通过新后端系统注册为auth插件的子模块,plugins/auth-backend-module-openshift-provider/src/module.ts 中的createBackendModule将openshiftprovider 注册到authProvidersExtensionPoint,并把认证器与登录解析器工厂组装为createOAuthProviderFactory。
源码剖析:认证器如何与 OpenShift API 交互
OpenShift 认证器基于passport-oauth2实现标准 OAuth 2.0 授权码流程,其核心逻辑全部位于 plugins/auth-backend-module-openshift-provider/src/authenticator.ts。以下要点可以帮助你理解它的底层行为。
用户资料通过 user.openshift.io API 获取
初始化时,认证器读取clientId、clientSecret、authorizationUrl、tokenUrl和openshiftApiServerUrl五个必填配置,构造OAuth2Strategy。其中自定义的userProfile方法会携带 access token 请求 OpenShift API:
GET {openshiftApiServerUrl}/apis/user.openshift.io/v1/users/~返回体按照user.openshift.io/v1的User结构用 zod 校验(见 authenticator.ts),并把metadata.name作为displayName提供给上层——这正是"catalog 中 User 实体名必须与 OpenShift 用户名一致"这一前提的来源。
启动、认证与刷新流程
start:跳转到授权端点,附加accessType: 'offline'与prompt: 'consent'参数;authenticate:完成授权码交换后,将refreshToken覆盖为 access token、刷新有效期对齐 access token 的expiresInSeconds——这是针对 OpenShift OAuth 不签发独立刷新令牌的变通处理;refresh:由于登录时刷新令牌实际就是 access token,此处直接用refreshToken作为 access token 重新拉取用户资料,遇到 401 则抛出 "Invalid access token";logout:登出时会先校验 token 是否仍有效,若有效则根据oauth.openshift.io/v1的OAuthAccessToken命名规则,对 token 去掉sha256~前缀后做 SHA-256 并 Base64URL 编码得到 token 名,再调用:
DELETE {openshiftApiServerUrl}/apis/oauth.openshift.io/v1/oauthaccesstokens/sha256~{tokenName}从而在 OpenShift 侧真正吊销该访问令牌(返回 401 则抛出unauthorized)。
登录解析器:将 OpenShift 用户匹配到 catalog 中的 User 实体
signIn.resolvers中使用的displayNameMatchingUserEntityName由模块自带的解析器工厂实现,见 plugins/auth-backend-module-openshift-provider/src/resolvers.ts。其行为如下:
- 从认证结果 profile 中取出
displayName(即 OpenShift 用户名),缺少时抛出 "OpenShift user profile does not contain a displayName"; - 用
stringifyEntityRef构造kind: User、namespace: default、name: displayName的实体引用; - 调用
ctx.signInWithCatalogUser完成 catalog 登录。
配套的可选参数dangerouslyAllowSignInWithoutUserInCatalog若置为true,当 catalog 中不存在对应用户实体时,会降级使用仅含用户名的entityRef回退登录,适用于尚未完成目录同步的过渡环境。因此,最稳妥的实践仍然是:确保 Backstage catalog 中存在与 OpenShift 用户同名(default命名空间下)的User实体,这样登录与 Kubernetes 插件按用户授权访问才能闭环。
完整落地检查清单
- 在 OpenShift 集群创建
OAuthClient,回调地址为https://<fqdn>/api/auth/openshift/handler/frame; - 将
clientId、clientSecret、authorizationUrl、tokenUrl、openshiftApiServerUrl通过环境变量注入app-config.yaml的auth.providers.openshift.<env>; - 按需设置
sessionDuration(如{ hours: 24 }或1d),并配置signIn.resolvers为displayNameMatchingUserEntityName; - 执行
yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-openshift-provider,并在packages/backend/src/index.ts注册模块; - 在
packages/app/src/apis.ts中把openshiftAuthApiRef接入KubernetesAuthProviders的oidcProviders,scope 固定为user:full; - 确保 catalog 中存在与 OpenShift 用户名一致的
User实体(default命名空间); - 重启前后端后,使用 OpenShift 账户登录,并在 Kubernetes 插件的集群配置中将
authProvider指向oidc类型的客户端侧提供者(对应 OpenShift 集群)。
按上述步骤完成后,用户即可用自己的 OpenShift 身份访问集群资源,而无需在 Backstage 中为 Kubernetes 插件配置任何服务账号或静态凭据。
【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考