처음부터 OIDC 제공자
info
출처: 문서
본문
info
이 문서는 새 Backstage 앱에서 기본값인 새 프론트엔드 시스템을 위해 작성됐어요. Backstage 앱이 여전히 구 프론트엔드 시스템을 사용한다면 대신 이 가이드의 구 프론트엔드 시스템 버전 을 읽으세요.
이 섹션은 Backstage OIDC 제공자를 활성화하고 사용하는 방법을 보여줘요.
요약
OIDC는 수많은 구현을 가진 프로토콜이에요. 사용자 중 상당수가 OIDC 프로토콜이 무엇인지 모를 가능성이 높지만, 여러분의 OIDC 구현은 알아볼 거예요. Backstage는 범용적인 oidc 인가 전략을 제공해요. 이를 여러분의 OIDC 구현 이름과 브랜딩으로 다시 배지(re-badge)하여 사용자가 Backstage sign-in 페이지에서 알아볼 수 있게 해야 해요.
예를 들어 조직에서 Keycloak을 사용한다면 OIDC 제공자를 Keycloak으로 다시 배지하고 사용자에게 Sign In using Keycloak으로 로그인하라고 알려주면 돼요.
단계
Backstage OIDC 제공자는 기본적으로 활성화돼 있지 않아요. 다음을 해야 해요:
-
OIDC 백엔드 모듈을 설치하고 구성.
-
app-config.yaml에서 제공자를 구성. -
sign-in resolver 구성.
-
제공자를 Backstage sign-in 페이지에 추가.
단순하게 하기 위해 Backstage 설치에 OIDC 제공자가 하나만 있다고 가정해요.
다음에서 각 단계를 자세히 설명할 거예요.
백엔드 설치
제공자를 백엔드에 추가하려면 제공자 모듈을 설치하세요:
from your Backstage root directory
yarn --cwd packages/backend add @backstage/plugin-auth-backend-module-oidc-provider
그런 다음 packages/backend/src/index.ts의 백엔드에 추가하세요:
packages/backend/src/index.ts
backend.add(import('@backstage/plugin-auth-backend'));backend.add(import('@backstage/plugin-auth-backend-module-oidc-provider'));
구성
여러분의 OIDC 제공자(예: Keycloak)에 Backstage용 OIDC 클라이언트 애플리케이션을 등록하세요. 그런 다음 app-config.yaml에 제공자 구성을 추가하세요:
app-config.yaml
auth: environment: development session: secret: ${AUTH_SESSION_SECRET} providers: oidc: development: metadataUrl: https://example.com/.well-known/openid-configuration clientId: ${AUTH_OIDC_CLIENT_ID} clientSecret: ${AUTH_OIDC_CLIENT_SECRET} signIn: resolvers: - resolver: emailMatchingUserEntityProfileEmail
${}로 둘러싸인 것은 YAML에서 직접 대체하거나 환경 변수로 제공할 수 있어요.
필수 매개변수
이 매개변수는 항상 설정해야 해요.
-
clientId: OIDC 제공자의 클라이언트 ID. -
clientSecret: 클라이언트 ID에 묶인 클라이언트 시크릿. -
metadataUrl: OpenID Connect 메타데이터 문서 URL, 예:https://example.com/.well-known/openid-configuration.
OIDC 제공자는 auth.session.secret이 설정되는 것도 요구해요.
선택 매개변수
이 매개변수에는 암시적 기본값이 있어요. 무엇을 하고 있는지 알지 못하면 재정의하지 마세요.
-
callbackUrl: OIDC 제공자가 사용하는 기본 콜백 URL을 재정의. -
timeout: OIDC 제공자 호출의 기본 타임아웃을 재정의. -
tokenEndpointAuthMethod -
tokenSignedResponseAlg -
additionalScopes: 기본openid profile email스코프 위에 추가 스코프를 요청. OIDC 제공자가 포함된 구성을 거부하므로scope를 직접 구성하지 마세요. -
prompt: 사용자에게 활성 세션이 없으면 브라우저가 ID 공급자에 sign-in을 요청하도록auto를 사용하는 것이 권장됨. -
sessionDuration: 사용자 세션의 수명. -
startUrlSearchParams: OIDC 인가 시작 URL을 위한 검색(쿼리) 매개변수 사전. ID 공급자의 동작을 바꾸고 싶지 않으면 정의하지 마세요. (예를 들어 조직이 선호하는 특정 sign-in 옵션으로 사용자를 안내하도록organization매개변수를 설정할 수 있어요.) 참고: 시작 URL은 브라우저가 제어하므로 이 기능은 Backstage 사용자 경험을 개선하기 위한 것뿐이에요.
Config Reloading
Backstage는 아직 auth 제공자 구성의 핫 리로딩을 지원하지 않아요. 이 YAML 파일의 변경 사항은 Backstage를 다시 시작해야 합니다.
Resolver
Resolver는 OIDC 제공자의 사용자 ID를 Backstage 사용자 ID로 매핑해요.
기본 OIDC 제공자는 app-config.yaml의 auth.providers.oidc.<environment>.signIn.resolvers 아래에 구성하는 선택 가능한 내장 resolver가 있어요:
app-config.yaml
auth: providers: oidc: development: # ... signIn: resolvers: - resolver: emailMatchingUserEntityProfileEmail
내장 resolver 중 어느 것도 적합하지 않으면 커스텀 resolver를 작성할 수 있어요. 자세한 내용은 Building Custom Resolvers를 참고하세요.
다음 예시는 사용자의 OIDC sub 클레임으로 사용자를 매핑하는 커스텀 resolver를 보여줘요:
packages/backend/src/index.ts
import { createBackendModule } from '@backstage/backend-plugin-api';import { authProvidersExtensionPoint, createOAuthProviderFactory,} from '@backstage/plugin-auth-node';import { oidcAuthenticator } from '@backstage/plugin-auth-backend-module-oidc-provider';import { stringifyEntityRef, DEFAULT_NAMESPACE,} from '@backstage/catalog-model';const myAuthProviderModule = createBackendModule({ pluginId: 'auth', moduleId: 'custom-oidc-provider', register(reg) { reg.registerInit({ deps: { providers: authProvidersExtensionPoint }, async init({ providers }) { providers.registerProvider({ providerId: 'oidc', factory: createOAuthProviderFactory({ authenticator: oidcAuthenticator, async signInResolver(info, ctx) { const userRef = stringifyEntityRef({ kind: 'User', name: info.result.fullProfile.userinfo.sub, namespace: DEFAULT_NAMESPACE, }); return ctx.issueToken({ claims: { sub: userRef, ent: [userRef], }, }); }, }), }); }, }); },});// ...backend.add(import('@backstage/plugin-auth-backend'));// Use the custom module instead of the default OIDC modulebackend.add(myAuthProviderModule);
resolver에 대한 더 자세한 설명은 Identity Resolver 페이지를 참고하세요.
제공자를 sign-in 페이지에 추가
마지막 단계는 프론트엔드의 sign-in 페이지가 OIDC 제공자를 사용하도록 구성하는 것이에요.
OIDC는 @backstage/core-plugin-api에 내장된 auth API ref가 없으므로 커스텀 ref를 만들고 SignInPageBlueprint로 배선해야 해요. 다음 예시는 packages/app/src/App.tsx에서 Keycloak 브랜딩 OIDC 제공자를 위해 이를 설정하는 방법을 보여줘요:
packages/app/src/App.tsx
import { createApp } from '@backstage/frontend-defaults';import { OpenIdConnectApi, ProfileInfoApi, BackstageIdentityApi, SessionApi,} from '@backstage/core-plugin-api';import { OAuth2 } from '@backstage/core-app-api';import { SignInPageBlueprint } from '@backstage/plugin-app-react';import { SignInPage } from '@backstage/core-components';import { createApiRef, createFrontendModule, configApiRef, discoveryApiRef, oauthRequestApiRef, ApiBlueprint,} from '@backstage/frontend-plugin-api';const keycloakAuthApiRef = createApiRef< OpenIdConnectApi & ProfileInfoApi & BackstageIdentityApi & SessionApi>().with({ id: 'auth.keycloak',});const keycloakAuthApi = ApiBlueprint.make({ name: 'keycloak', params: defineParams => defineParams({ api: keycloakAuthApiRef, deps: { discoveryApi: discoveryApiRef, oauthRequestApi: oauthRequestApiRef, configApi: configApiRef, }, factory: ({ discoveryApi, oauthRequestApi, configApi }) => OAuth2.create({ configApi, discoveryApi, oauthRequestApi, environment: configApi.getOptionalString('auth.environment'), provider: { id: 'oidc', title: 'Keycloak', icon: () => null, }, defaultScopes: ['openid', 'profile', 'email'], }), }),});const signInPage = SignInPageBlueprint.make({ params: { loader: async () => props => ( <SignInPage {...props} provider={{ id: 'keycloak-auth-provider', title: 'Keycloak', message: 'Sign In using Keycloak', apiRef: keycloakAuthApiRef, }} /> ), },});export default createApp({ features: [ // ... createFrontendModule({ pluginId: 'app', extensions: [keycloakAuthApi, signInPage], }), ],});
API ref의 id(예: 'auth.keycloak')와 SignInPage 제공자 구성에 사용된 id(예: 'keycloak-auth-provider')는 사용자 지정할 수 있어요. 그러나 OAuth2.create에 전달되는 provider.id는 백엔드의 Backstage 범용 OIDC auth 전략과 일치하도록 'oidc'로 유지해야 해요.
참고
app-config.yaml의 루트에 enableExperimentalRedirectFlow: true를 추가하면 팝업 없이 리다이렉트 흐름으로 sign-in을 구성할 수 있습니다.
sign-in 구성에 대한 자세한 내용은 Sign-in Configuration을 참고하세요.