# 멀티 IDP 아키텍처 및 마이그레이션 전략 본 문서는 Primary IDP 변경(예: Descope → Hydra/Authentik) 시 시스템의 유연성을 보장하기 위한 아키텍처 설계 전략을 기술합니다. ## 핵심 전략 1. **Broker 패턴 고도화**: 백엔드가 모든 인증 요청을 중계하며, 클라이언트는 특정 IDP에 종속되지 않습니다. 2. **추상화 계층 (Abstraction Layer)**: 비즈니스 로직은 `IdentityProvider` 인터페이스에만 의존하며, 구체적인 구현체(Descope, Hydra 등)는 알 필요가 없습니다. 3. **식별자 분리 (Identifier Decoupling)**: 외부 IDP의 `sub` 값과 내부 시스템의 `user_id`를 분리하여 매핑합니다. ## 상세 설계 ### 1. IdentityProvider 인터페이스 확장 단순 메타데이터 조회를 넘어, 인증의 핵심 라이프사이클을 모두 포함하도록 인터페이스를 확장해야 합니다. ```go type IdentityProvider interface { // 메타데이터 및 스키마 검증 Name() string GetMetadata() (*IDPMetadata, error) // 핵심 인증/인가 기능 SignUp(ctx context.Context, user *BrokerUser, password string) (*AuthResult, error) Login(ctx context.Context, loginID, password string) (*AuthResult, error) VerifyToken(ctx context.Context, token string) (*TokenInfo, error) // 사용자 관리 GetUser(ctx context.Context, id string) (*BrokerUser, error) UpdateUser(ctx context.Context, user *BrokerUser) error DeleteUser(ctx context.Context, id string) error } ``` ### 2. Provider Factory 패턴 설정(`config.yaml` 또는 환경변수)에 따라 사용할 IDP 구현체를 런타임에 결정합니다. ```go func NewIdentityProvider(config Config) (domain.IdentityProvider, error) { switch config.IDPType { case "descope": return service.NewDescopeProvider(config.Descope) case "hydra": return service.NewHydraProvider(config.Hydra) case "authentik": return service.NewAuthentikProvider(config.Authentik) default: return nil, fmt.Errorf("unsupported IDP type: %s", config.IDPType) } } ``` ### 3. 식별자 매핑 (ID Mapping) IDP 변경 시 가장 큰 문제는 사용자 고유 ID(`sub`)가 바뀌는 것입니다. 이를 해결하기 위해 Baron SSO 내부 전용 UUID를 사용하고 매핑 테이블을 둡니다. * **User Table (Baron Internal)**: `id` (UUID), `email`, ... * **IDP Link Table**: `baron_user_id`, `idp_provider` (e.g., descope), `idp_subject_id` (e.g., U12345) ## 구현 예시 (Descope) 현재 단계에서 즉시 사용 가능한 `DescopeProvider`의 구현 예시입니다. ```go // DescopeProvider는 IdentityProvider 인터페이스를 구현합니다. type DescopeProvider struct { Client *client.DescopeClient } func (d *DescopeProvider) SignUp(ctx context.Context, user *domain.BrokerUser, password string) (*domain.AuthResult, error) { // BrokerUser를 Descope User 객체로 변환 descopeUser := &descope.User{ Name: user.Name, Email: user.Email, Phone: user.PhoneNumber, CustomAttributes: user.Attributes, } // SDK 호출 authInfo, err := d.Client.Auth.Password().SignUp(ctx, user.Email, descopeUser, password) if err != nil { return nil, err\n } // 결과 반환 return &domain.AuthResult{ UserID: authInfo.User.UserID, Token: authInfo.SessionToken.JWT, }, nil } ``` ## 향후 지원 후보 (Candidates) * **Ory Hydra**: 자체적인 OAuth2/OIDC 서버 구축이 필요할 때 적합. 높은 커스터마이징 가능. * **Authentik**: 오픈소스 IDP로, 설치형(Self-hosted) 환경에서 강력한 기능을 제공.