Skip to main content

Backstage身份验证

Backstage 中的身份验证系统有两个不同的用途:用户登录和身份验证,以及授权访问第三方资源。 可以将 Backstage 配置为任意数量的身份验证提供程序,但其中通常只有一个用于登录,其余的用于提供对外部资源的访问。

注意:Backstage的身份管理和登录页面并非阻止未经授权用户访问的方法。 身份系统仅用于提供个性化的 > 体验和访问Backstage身份令牌,该令牌可传递给后端插件。 > 这也意味着您的Backstage后端应用程序接口默认情况下未经身份验证。 > 因此,如果您的Backstage实例暴露在互联网上,任何人都可以访问Backstage中的 > 信息。 您可以 [在此] 了解更多信息(../overview/threat-model.md#integrator-responsibilities)。

内置认证提供商

Backstage 核心库中有许多常用的身份验证提供程序:

这些内置提供程序会处理特定服务的验证流程,包括所需的作用域、回调等。

配置身份验证提供程序

每个内置提供程序都有一个配置块,位于auth部分app-config.yaml例如,GitHub 提供商:

auth:
environment: development
providers:
github:
development:
clientId: ${AUTH_GITHUB_CLIENT_ID}
clientSecret: ${AUTH_GITHUB_CLIENT_SECRET}

请参阅特定提供商的文档,了解需要进行哪些配置。

providers如果支持多种身份验证方法,key 可以有多个身份验证提供程序。 每个提供程序还可以为不同的身份验证环境(开发环境、生产环境等)提供配置。 这样,单个身份验证后端就可以为多个环境提供服务,例如针对已部署的后端运行本地前端。 提供程序配置与本地auth.environment将选择设置。

登录配置

使用身份验证提供程序登录,需要在前端应用程序和auth有关如何配置后端应用程序的信息,请参阅登录身份和解析器本节其余部分将重点介绍如何为前台应用程序配置登录。

通过提供自定义的SignInPage它将在应用程序中的其他路由之前呈现,并负责提供当前用户的身份信息。SignInPage可以呈现任意数量的页面和组件,也可以只是在Backstage运行逻辑的空白空间。 不过,最终它必须通过onSignInSuccess回调道具,此时应用程序的其余部分将被渲染。

如果您愿意,可以使用SignInPage组件,该组件由@backstage/core-components,其中任取一个providerprovidersSignInProviderConfig定义。

下面的 GitHub 示例显示了对packages/app/src/App.tsx并可适用于任何内置提供商:

packages/app/src/App.tsx
import { githubAuthApiRef } from '@backstage/core-plugin-api';
import { SignInPage } from '@backstage/core-components';

const app = createApp({
components: {
SignInPage: props => (
<SignInPage
{..props}
auto
provider={{
id: 'github-auth-provider',
title: 'GitHub',
message: 'Sign in using GitHub',
apiRef: githubAuthApiRef,
}}
/>
),
},
// ..
});

您还可以使用providers道具来启用多种登录方法,例如

  • 允许访客访问:
packages/app/src/App.tsx
const app = createApp({
components: {
SignInPage: props => (
<SignInPage
{..props}
providers={[
'guest',
{
id: 'github-auth-provider',
title: 'GitHub',
message: 'Sign in using GitHub',
apiRef: githubAuthApiRef,
},
]}
/>
),
},
// ..
});

注意:您可以在 app-config.yaml 根目录下添加 > enableExperimentalRedirectFlow: true 来配置登录,以使用无弹出窗口的重定向流程。

使用代理提供商登录

有些认证提供程序是所谓的 "代理 "提供程序,这意味着它们需要在认证代理后面使用。 例如亚马逊应用负载平衡器,Azure EasyAuth,Cloudflare 访问,谷歌身份感知代理OAuth2 代理.

使用代理提供商时,您最终会希望使用不同的登录页面,因为一旦您通过代理登录,就不需要进一步的用户交互。 登录页面需要做的就是调用/refresh的端点来获取现有会话,这正是ProxiedSignInPage您唯一需要做的就是配置ProxiedSignInPage就是像这样传递提供商的 ID:

packages/app/src/App.tsx
const app = createApp({
components: {
SignInPage: props => <ProxiedSignInPage {..props} provider="awsalb" />,
},
// ..
});

如果 auth 后端中的提供程序需要额外的报头,如x-provider-token现在可以在ProxiedSignInPage使用可选的headers托。

例如

<ProxiedSignInPage
{..props}
provider="my-custom-provider"
headers={{ 'x-some-key': someValue }}
/>

头信息也可以以异步方式返回:

<ProxiedSignInPage
{..props}
provider="my-custom-provider"
headers={async () => {
const someValue = await someFn();
return { 'x-some-key': someValue };
}}
/>

这种方法的一个缺点是本地开发时设置起来比较麻烦。 作为一种变通方法,可以根据应用程序的运行环境动态选择登录页面,然后在本地开发时使用不同的登录方法(如果需要的话)。 根据具体设置,可以选择基于以下内容的登录方法process.env.NODE_ENV环境变量,通过检查hostname例如,通过访问配置 API 来读取配置值:

packages/app/src/App.tsx
const app = createApp({
components: {
SignInPage: props => {
const configApi = useApi(configApiRef);
if (configApi.getString('auth.environment') === 'development') {
return (
<SignInPage
{..props}
provider={{
id: 'google-auth-provider',
title: 'Google',
message: 'Sign In using Google',
apiRef: googleAuthApiRef,
}}
/>
);
}
return <ProxiedSignInPage {..props} provider="gcpiap" />;
},
},
// ..
});

在使用类似的多个验证提供程序时,重要的是要配置不同的登录解析器,以便无论使用哪种方法,它们都能解析到相同的身份。

Scaffolder 配置(软件模板)

如果您想使用存储库选择器您需要在软件模板中配置ScmAuthApi这是一个应用程序接口,用于根据所访问的资源,以通用方式对不同的 SCM 系统进行身份验证。

要进行设置,您需要在packages/app/src/apis.ts下面的示例设置了ScmAuthApi已配置的 GitLab 身份验证提供程序:

packages/app/src/apis.ts
createApiFactory({
api: scmAuthApiRef,
deps: {
gitlabAuthApi: gitlabAuthApiRef,
},
factory: ({ gitlabAuthApi }) => ScmAuth.forGitlab(gitlabAuthApi),
});

如果您使用的是自定义身份验证提供程序,您可能需要添加一个风俗.

面向插件开发人员

Backstage 前端核心应用程序接口提供了一套实用程序接口,供插件开发人员使用,既可以访问用户身份,也可以访问第三方资源。

###插件开发人员的身份

对于插件开发人员来说,有一个主要的接触点可以访问用户身份:即IdentityApi@backstage/core-plugin-api通过identityApiRef.

IdentityApi它可以访问用户的实体引用、轻量级配置文件信息和Backstage令牌,以便在Backstage进行身份验证调用时识别用户。

在调用后端插件时,我们建议使用FetchApi使用,它通过fetchApiRef@backstage/core-plugin-api....。FetchApi将自动在请求中包含Backstage令牌,这意味着无需直接与IdentityApi.

访问第三方资源

在 Backstage 中与第三方服务对话的常见模式是用户对服务器请求,插件会请求短时 OAuth 访问令牌,以验证对外部服务的调用。 这些调用可以直接对服务进行,也可以通过后端插件或服务进行。

通过依赖用户对服务器的调用,我们保持了前端和后端之间较低的耦合度,并为插件使用第三方服务提供了更低的门槛。 与基于会话的系统(访问令牌存储在服务器端)相比,这种解决方案需要认证后端插件、其会话存储和其他后端插件或独立服务之间有更深的耦合度。 Backstage 的一个目标是让创建新插件变得尽可能简单,而基于用户对服务器 OAuth 的认证解决方案有助于实现这一目标。

前端插件请求访问第三方服务的方法是通过实用 API这些后缀均为*AuthApiRef例如githubAuthApiRef有关提供商的完整列表,请参见@backstage/core-plugin-api参考文献

自定义身份验证提供程序

OAuth2 和 SAML 有通用的身份验证提供程序,这些程序可以减少实施符合这些标准的自定义身份验证提供程序所需的代码量。

Backstage用途Passport在引擎盖下有一个针对不同提供商的广泛的身份验证策略库。 请参见添加身份验证提供程序以了解添加新的支持 passport 的身份验证方法的详情。

自定义 ScmAuthApi 实现

默认值ScmAuthAPi提供以下集成github,gitlab,azurebitbucket并通过以下代码在packages/app/src/apis.ts:

ScmAuth.createDefaultApiFactory();

如果您只需要这些集成的一个子集,则需要自定义实现ScmAuthApi这是一个 API,用于根据所访问的资源对不同的 SCM 系统进行通用验证,例如,Scaffolder(软件模板)和目录导入插件就使用了该 API。

第一步是删除创建默认提供程序的代码。

packages/app/src/apis.ts
import {
ScmIntegrationsApi,
scmIntegrationsApiRef,
ScmAuth,
} from '@backstage/integration-react';

export const apis: AnyApiFactory[] = [
ScmAuth.createDefaultApiFactory(),
// ..
];

然后将其替换为如下内容,这样就可以创建一个ApiFactory只需一个 Github 提供商。

packages/app/src/apis.ts
export const apis: AnyApiFactory[] = [
createApiFactory({
api: scmAuthApiRef,
deps: {
githubAuthApi: githubAuthApiRef,
},
factory: ({ githubAuthApi }) =>
ScmAuth.merge(
ScmAuth.forGithub(githubAuthApi),
),
});

如果使用任何自定义身份验证集成,可以在ApiFactory.

第一步是创建一个新的身份验证 ref,其命名规则为xxxAuthApiRef下面的示例是一个新的 GitHub 企业集成,如果仅用于此目的,可以在应用程序本身中定义,或者在一个通用的内部 API 包中定义,例如:"...."。@internal/apis:

const gheAuthApiRef: ApiRef<OAuthApi & ProfileInfoApi & SessionApi> =
createApiRef({
id: 'internal.auth.ghe',
});

这个新的 API ref 只有在您为其定义了一个 API 工厂后才能使用。 例如

createApiFactory({
api: gheAuthApiRef,
deps: {
discoveryApi: discoveryApiRef,
oauthRequestApi: oauthRequestApiRef,
configApi: configApiRef,
},
factory: ({ discoveryApi, oauthRequestApi, configApi }) =>
GithubAuth.create({
configApi,
discoveryApi,
oauthRequestApi,
provider: { id: 'ghe', title: 'GitHub Enterprise', icon: () => null },
defaultScopes: ['read:user'],
environment: configApi.getOptionalString('auth.environment'),
}),
});

然后,新的 API ref 将用于向 ApiFactory 添加新的提供程序:

createApiFactory({
api: scmAuthApiRef,
deps: {
gheAuthApi: gheAuthApiRef,
githubAuthApi: githubAuthApiRef,
},
factory: ({ githubAuthApi, gheAuthApi }) =>
ScmAuth.merge(
ScmAuth.forGithub(githubAuthApi),
ScmAuth.forGithub(gheAuthApi, {
host: 'ghe.example.com',
}),
),
});

最后,您还需要将另一个提供程序添加并配置到auth-backend使用提供程序 ID,在本例中为ghe:

import { providers } from '@backstage/plugin-auth-backend';

// Add the following options to `createRouter` in packages/backend/src/plugins/auth.ts
providerFactories: {
ghe: providers.github.create(),
},

配置令牌发行者

默认情况下,Backstage 身份验证后端会为任何已签发的 Backstage 令牌自动生成和管理自己的签名密钥。 不过,这些密钥的有效期很短,在实例重启后不会持续存在。

另外,用户也可以提供自己的公钥和私钥文件,以签署已签发的令牌。 在令牌验证实施会主动缓存密钥列表,即使遇到未知密钥 ID 也不会尝试获取新密钥的情况下,这样做很有好处。 要启用此功能,请在配置文件中添加以下配置:

auth:
keyStore:
provider: 'static'
static:
keys:
# Must be declared at least once and the first one will be used for signing
- keyId: 'primary'
publicKeyFile: /path/to/public.key
privateKeyFile: /path/to/private.key
algorithm: # Optional, algorithm used to generate the keys, defaults to ES256
# More keys can be added so with future key rotations caches already know about it
- keyId: ..

私钥应以 PKCS#8 格式存储。 公钥应以 SPKI 格式存储。 可以通过以下步骤使用 openssl 和 ES256 算法生成公钥/私钥对:

使用 ES256 算法生成私人密钥

openssl ecparam -name prime256v1 -genkey -out private.ec.key

将其转换为 PKCS#8 格式

openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private.ec.key -out private.key

提取公开密钥

openssl ec -inform PEM -outform PEM -pubout -in private.key -out public.key