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

새 공급자 모듈 기여하기

원문 보기 위키 갱신

참고

출처: 문서

본문

참고

이 문서의 주요 대상은 새 인증 공급자에 대한 지원을 추가하려는 기여자입니다. 이를 따라 자신만의 커스텀 공급자를 구현할 수 있지만, 내장 공급자를 사용하는 것보다 훨씬 더 고급입니다.

인증은 어떻게 작동하나요?

Backstage 애플리케이션은 인증을 위해 다양한 외부 인증 공급자를 사용할 수 있습니다. 외부 공급자는 인증을 처리하기 위한 AuthProviderRouteHandlers 인터페이스로 래핑됩니다. 이 인터페이스는 네 가지 메서드로 구성됩니다. 각 메서드는 (기본적으로) /api/auth/[provider]/method 엔드포인트에서 호스팅되며, 여기서 method는 다음과 같이 특정 작업을 수행합니다.

/auth/[provider]/start -> Initiate a login from the web page  /auth/[provider]/handler/frame -> Handle a finished authentication operation  /auth/[provider]/refresh -> Refresh the validity of a login  /auth/[provider]/logout -> Log out a logged-in user

흐름은 다음과 같습니다.

  • 사용자가 로그인을 시도합니다.

  • 팝업 창이 열리고 auth 엔드포인트를 가리킵니다. 그 엔드포인트는 초기 준비를 한 다음, 여전히 팝업 안에서 사용자를 외부 인증자(auth)로 리다이렉트합니다.

  • 인증자가 사용자를 검증하고 검증 결과(성공 또는 실패)를 래퍼의 엔드포인트(handler/frame)에 반환합니다.

  • handler/frame이 렌더링한 웹페이지는 팝업 창을 연 웹페이지에 적절한 응답을 발행하고, 팝업이 닫힙니다.

  • 사용자가 UI 인터페이스를 클릭해 로그아웃하고, 웹페이지가 사용자를 로그아웃시키는 요청을 합니다.

자신의 Auth 래퍼 구현하기

모든 auth 래퍼의 핵심 인터페이스는 AuthProviderRouteHandlers 인터페이스입니다. 이 인터페이스는 처음 섹션에서 설명한 API에 대응하는 네 가지 메서드를 가집니다. 모든 auth 래퍼는 이 인터페이스를 구현해야 합니다.

로그인을 시작할 때 프론트엔드에 의해 팝업 창이 생성되어 사용자가 로그인을 시작할 수 있게 합니다. 이 로그인 요청은 start 메서드가 처리하는 /start 엔드포인트로 이루어집니다.

start 메서드는 요청을 인증하는 외부 auth 공급자로 리다이렉트하고, 요청을 frameHandler 메서드가 처리하는 /handler/frame 엔드포인트로 리다이렉트합니다.

frameHandler는 요청의 결과를 포함해 프론트엔드 창에 postMessage를 하는 스크립트가 포함된 HTML 응답을 반환합니다. WebMessageResponse 타입은 postMessage가 프론트엔드로 보내는 메시지입니다.

postMessageResponse 유틸리티 함수는 CORS가 성공적으로 처리되도록 보장하는 postMessage 응답을 생성하는 로직을 래핑합니다. 이 함수는 express.Response, WebMessageResponse, 프론트엔드 URL(appOrigin)을 매개변수로 받아 스크립트와 메시지가 있는 HTML 페이지를 반환합니다.

Auth 환경 분리

env 개념은 auth 백엔드가 작동하는 방식의 핵심입니다. env 쿼리 매개변수를 사용해 애플리케이션이 실행 중인 환경(development, staging, production 등)을 식별합니다. 각 런타임은 동시에 여러 환경을 지원할 수 있으며, 각 요청에 대한 올바른 핸들러가 env 매개변수에 기반해 식별되고 배치됩니다.

OAuthEnvironmentHandler는 AuthProviderRouteHandlers 인터페이스를 구현하면서 여러 env를 지원하는 OAuthHandlers용 유틸리티 래퍼입니다.

OAuth 공급자(다른 환경에 대해 동일하지만)를 인스턴스화하려면 OAuthEnvironmentHandler.mapConfig를 사용하세요. 환경 대 구성의 맵인 구성 객체를 반복하는 헬퍼입니다. 사용 예는 기존 OAuth 공급자 중 하나를 참조하세요.

다음 구성을 고려하세요.

development:  clientId: abc  clientSecret: secretproduction:  clientId: xyz  clientSecret: supersecret

OAuthEnvironmentHandler.mapConfig(config, envConfig => ...) 호출은 구성을 최상위 development와 production 키로 나누고 각 블록을 envConfig로 전달합니다.

편의를 위해 AuthProviderFactory는 구현해야 하는 팩토리 함수이며, 주어진 공급자에 대한 AuthProviderRouteHandlers를 생성할 수 있습니다.

지원되는 모든 공급자는 여러 환경에 대한 인증을 처리할 수 있는 OAuthEnvironmentHandler를 반환하는 AuthProviderFactory를 제공합니다.

Passport

우리는 지원되는 인증 전략의 포괄적인 세트 때문에 Passport를 인증 플랫폼으로 선택했습니다.

새 전략 공급자를 추가하는 방법

빠른 가이드

  1. 필요에 따라 새 auth 공급자 모듈을 만들거나 프록시 auth 기반 공급자를 추가합니다.

  2. 공급자를 백엔드에 추가합니다.

새 auth 공급자 모듈 만들기

이 예시에서는 가상의 foobar라는 서비스에 대한 auth 모듈을 만듭니다.

yarn new를 사용해 새 모듈을 만들고, backend-module을 선택하고, 플러그인 ID로 auth-backend를, 모듈 ID로 foobar-provider를 제공하세요.

모듈이 적절한 passport 공급자를 의존성으로 갖는지 확인하세요.

cd plugins/auth-backend-backend-module-foobar-provideryarn add passport-provider-ayarn add @types/passport-provider-a

OAuth 기반 공급자 추가하기

그런 다음 authProvidersExtensionPoint를 사용해 Auth 백엔드를 확장할 수 있는 새 모듈을 만듭니다.

plugins/auth-backend-foobar-provider/src/module.ts

import { createBackendModule } from '@backstage/backend-plugin-api';import {  authProvidersExtensionPoint,  commonSignInResolvers,  createOAuthProviderFactory,} from '@backstage/plugin-auth-node';import { providerAuthenticator } from './authenticator';/** @public */export const authModuleFoobarProvider = createBackendModule({  pluginId: 'auth',  moduleId: 'foobar',  register(reg) {    reg.registerInit({      deps: {        providers: authProvidersExtensionPoint,      },      async init({ providers }) {        providers.registerProvider({          providerId: 'foobar',          factory: createOAuthProviderFactory({            authenticator: providerAuthenticator,            signInResolverFactories: {              ...commonSignInResolvers,            },          }),        });      },    });  },});

이제 passport 패키지의 Strategy를 사용해 공급자에 대한 실제 authenticator를 구현해 보겠습니다. authenticator는 passport 전략을 생성하고 구성 파일의 시크릿을 사용해 인증 흐름을 처리하는 책임이 있습니다.

plugins/auth-backend-foobar-provider/src/authenticator.ts

import { Strategy as ProviderStrategy } from 'passport-provider-a';import {  createOAuthAuthenticator,  PassportOAuthAuthenticatorHelper,  PassportOAuthDoneCallback,  PassportProfile,} from '@backstage/plugin-auth-node';/** @public */export const providerAuthenticator = createOAuthAuthenticator({  defaultProfileTransform:    PassportOAuthAuthenticatorHelper.defaultProfileTransform,  scopes: {    // Scopes required by the provider    required: ['openid', 'email', 'profile', 'offline_access'],  },  initialize() {    return new ProviderStrategy(      {        clientID: this.options.clientId,        clientSecret: this.options.clientSecret,      },      (      accessToken: string,      refreshToken: string,      profile: PassportProfile,      done: PassportOAuthDoneCallback,    ) => {      if (!profile.emails || !profile.emails.length) {        done(new Error('Profile contains no emails'));        return;      }      done(        undefined,        {          fullProfile: profile,          accessToken,          refreshToken,          params: { id_token: profile.id },        },        {},      );    },  );},

이미 코드베이스에 구현된 authenticator의 몇 가지 예는 다음과 같습니다.

  • Google

  • GitHub

  • Okta

프록시 auth 기반 공급자 만들기

프록시 auth 공급자는 Google IAP 또는 AWS ALB 같은 다른 공급자를 사용해 인증하는 공급자입니다. 이러한 공급자는 이미 Backstage에서 지원된다는 점에 유의하세요.

구현은 OAuth 공급자와 비슷하지만 authenticator 함수가 다릅니다. 코드베이스에는 이미 프록시 공급자를 구현하는 예가 있습니다. 예를 들어 auth-backend-module-gcp-iap-provider와 auth-backend-module-aws-alb-provider가 있습니다.

검증 콜백(Verify Callback)

전략은 소위 검증 콜백이 필요합니다. 검증 콜백의 목적은 자격 증명 집합을 소유한 사용자를 찾는 것입니다. Passport가 요청을 인증할 때, 요청에 포함된 자격 증명을 파싱합니다. 그런 다음 그 자격 증명을 인자로 검증 콜백을 호출합니다[...]. 자격 증명이 유효하면 검증 콜백은 done을 호출해 Passport에 인증된 사용자를 제공합니다.

자격 증명이 유효하지 않으면(예: 비밀번호가 잘못된 경우), done은 사용자 대신 false로 호출되어 인증 실패를 나타내야 합니다.

http://www.passportjs.org/docs/configure/

공급자를 백엔드에 추가하기

새 모듈을 추가하는 프로세스는 다른 유형의 모듈이나 백엔드 플러그인과 동일합니다.

이 공급자가 설치 내부 전용이라면 packages/backend/src/index.ts에 추가하는 import 경로는 다음과 같을 것입니다.

backend.add(import('@internal/plugin-auth-backend-module-foobar-provider'));

그러나 이 모듈이 Backstage에 직접 기여된다면 모듈은 다음과 같이 import됩니다.

backend.add(import('@backstage/plugin-auth-backend-module-foobar-provider'));

이렇게 하면 auth-backend가 자동으로 다음 엔드포인트를 추가합니다.

router.get('/auth/providerA/start');router.get('/auth/providerA/handler/frame');router.post('/auth/providerA/handler/frame');router.post('/auth/providerA/logout');router.get('/auth/providerA/refresh'); // if supportedrouter.post('/auth/providerA/refresh'); // if supported

보시다시피 각 엔드포인트는 /auth와 그 공급자 이름으로 접두사가 붙습니다.

새 공급자 테스트하기

curl -i localhost:7007/api/auth/providerA/start를 실행하면 Location 헤더가 있는 302 리다이렉트가 제공되어야 합니다. 그 헤더의 URL을 웹 브라우저에 붙여 넣으면 인증 흐름을 트리거할 수 있어야 합니다.

더 알아보기 (Learn more)