본문 바로가기
WIKI 기술 지식 베이스

처음부터 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을 참고하세요.

더 알아보기 (Learn more)