diff --git a/Baron SSO 로그인 화면 3가지 방식 절차 및 흐름.md b/Baron SSO 로그인 화면 3가지 방식 절차 및 흐름.md index 5539d1f..267bf07 100644 --- a/Baron SSO 로그인 화면 3가지 방식 절차 및 흐름.md +++ b/Baron SSO 로그인 화면 3가지 방식 절차 및 흐름.md @@ -28,44 +28,45 @@ Baron SSO 로그인 페이지에는 사용자가 선택할 수 있는 로그인 ## 3. 공통 운영 경로 -운영 환경에서는 사용자의 요청이 Backend, Kratos, Hydra로 직접 들어가지 않는다. 일반적으로 앞단의 L7 또는 Traefik, Baron Gateway Nginx, Oathkeeper를 거쳐 내부 서비스로 라우팅된다. +운영 환경에서는 사용자의 요청이 Backend, Kratos, Hydra로 직접 들어가지 않는다. 일반적으로 Baron Gateway Nginx와 Oathkeeper를 거쳐 내부 서비스로 라우팅된다. + +실제 운영 환경에서는 Baron Gateway Nginx 앞에 Traefik, 외부 L7 로드밸런서, Ingress, ALB 같은 장비가 더 있을 수 있다. 다만 이 문서는 로그인 흐름 이해가 목적이므로, 그림에서는 이를 모두 `Baron Gateway Nginx` 진입 계층으로 통합해서 표현한다. 각 구성요소를 간단히 설명하면 다음과 같다. | 구성요소 | 쉬운 역할 | 로그인 흐름에서 하는 일 | | --- | --- | --- | -| L7 또는 Traefik | 외부 출입구 / 1차 교통정리 | 사용자가 접속한 도메인과 HTTPS 요청을 받아 Baron SSO 쪽으로 넘긴다. 운영 환경에 따라 Traefik, 외부 L7 로드밸런서, Ingress, ALB 같은 장비가 이 역할을 한다. | -| Baron Gateway Nginx | Baron SSO 내부 안내 데스크 | 들어온 URL 경로를 보고 UserFront, Backend, Oathkeeper 중 어디로 보낼지 나눈다. 예를 들어 `/api/*`는 Backend, `/oidc/*`는 Oathkeeper/Hydra 쪽으로 보낸다. | +| Baron Gateway Nginx | Baron SSO 진입 계층 / 내부 안내 데스크 | 들어온 URL 경로를 보고 UserFront, Backend, Oathkeeper 중 어디로 보낼지 나눈다. 예를 들어 `/api/*`는 Backend, `/oidc/*`는 Oathkeeper/Hydra 쪽으로 보낸다. 실제 운영의 외부 L7/Traefik 역할도 그림에서는 이 항목에 통합해 표현한다. | | Oathkeeper | Ory 앞단 보안 게이트 | `/oidc/*`, `/auth/*`처럼 Ory로 가는 요청을 받아 정책에 맞게 통과시키고, 내부 Ory 주소로 전달한다. 현재 흐름에서는 Hydra/Kratos 앞단의 보호 프록시 역할을 한다. | | Ory Hydra | OIDC/OAuth2 인가 서버 | RP의 `client_id`, `redirect_uri`, `scope`, `state`, `code_challenge`를 확인하고, 로그인 필요 시 `login_challenge`를 만들어 UserFront 로그인 화면으로 보낸다. | | UserFront | Baron SSO 로그인 화면 | 사용자가 보는 비밀번호, 로그인 링크, QR 코드 탭 화면이다. | -따라서 L7, Nginx, Oathkeeper는 사용자를 인증하는 주체라기보다 "요청을 올바른 내부 서비스로 안전하게 전달하는 앞단 계층"에 가깝다. 실제 로그인 요청 접수와 OIDC 판단은 Hydra가 하고, 비밀번호 검증과 세션 발급은 Backend와 Kratos가 처리한다. +따라서 Baron Gateway Nginx와 Oathkeeper는 사용자를 인증하는 주체라기보다 "요청을 올바른 내부 서비스로 안전하게 전달하는 앞단 계층"에 가깝다. 실제 로그인 요청 접수와 OIDC 판단은 Hydra가 하고, 비밀번호 검증과 세션 발급은 Backend와 Kratos가 처리한다. -중요한 점은 모든 요청이 Oathkeeper를 거치는 것은 아니라는 것이다. Oathkeeper는 주로 Ory Public endpoint 앞단에 붙어 있다. UserFront 화면 요청과 Baron Backend API 요청은 Nginx에서 각각 UserFront와 Backend로 직접 라우팅된다. +중요한 점은 모든 요청이 Oathkeeper를 거치는 것은 아니라는 것이다. Oathkeeper는 주로 Ory Public endpoint 앞단에 붙어 있다. UserFront 화면 요청과 Baron Backend API 요청은 Baron Gateway Nginx에서 각각 UserFront와 Backend로 직접 라우팅된다. 요청 종류별 경로는 다음과 같이 구분된다. | 요청 종류 | 예시 | 실제 경로 | Oathkeeper 경유 여부 | | --- | --- | --- | --- | -| 로그인 화면 요청 | `/`, `/ko/login?login_challenge=...` | 브라우저 -> L7 -> Nginx -> UserFront | 경유하지 않음 | -| Baron Backend API 요청 | `/api/v1/auth/password/login`, `/api/v1/auth/qr/init` | UserFront -> L7 -> Nginx -> Backend | 경유하지 않음 | -| Ory Public 요청 | `/oidc/oauth2/auth`, `/auth/*` | 브라우저/RP -> L7 -> Nginx -> Oathkeeper -> Hydra/Kratos Public | 경유함 | +| 로그인 화면 요청 | `/`, `/ko/login?login_challenge=...` | 브라우저 -> Baron Gateway Nginx -> UserFront | 경유하지 않음 | +| Baron Backend API 요청 | `/api/v1/auth/password/login`, `/api/v1/auth/qr/init` | UserFront -> Baron Gateway Nginx -> Backend | 경유하지 않음 | +| Ory Public 요청 | `/oidc/oauth2/auth`, `/auth/*` | 브라우저/RP -> Baron Gateway Nginx -> Oathkeeper -> Hydra/Kratos Public | 경유함 | | Backend 내부 백채널 | `GetLoginRequest`, `AcceptLoginRequest`, Kratos 세션 발급 | Backend -> Hydra Admin/Kratos API/Redis | 경유하지 않음 | -즉 로그인 화면이 표시될 때의 UserFront 요청은 Oathkeeper를 거치지 않는다. 반면 RP가 처음 보낸 `/oidc/oauth2/auth` 요청은 Ory Public endpoint이므로 Nginx에서 Oathkeeper로 보내고, Oathkeeper가 Hydra로 전달한다. +즉 로그인 화면이 표시될 때의 UserFront 요청은 Oathkeeper를 거치지 않는다. 반면 RP가 처음 보낸 `/oidc/oauth2/auth` 요청은 Ory Public endpoint이므로 Baron Gateway Nginx에서 Oathkeeper로 보내고, Oathkeeper가 Hydra로 전달한다. 헷갈리기 쉬운 두 경로를 분리하면 다음과 같다. ```text 로그인 화면 요청: -사용자 브라우저 -> L7 -> Baron Gateway Nginx -> UserFront +사용자 브라우저 -> Baron Gateway Nginx -> UserFront OIDC 인증 요청: -사용자 브라우저/RP -> L7 -> Baron Gateway Nginx -> Oathkeeper -> Hydra +사용자 브라우저/RP -> Baron Gateway Nginx -> Oathkeeper -> Hydra 로그인 버튼/API 요청: -UserFront -> L7 -> Baron Gateway Nginx -> Baron Backend +UserFront -> Baron Gateway Nginx -> Baron Backend Backend 내부 완료 처리: Baron Backend -> Hydra Admin API @@ -89,7 +90,7 @@ Baron Backend -> Hydra Admin API RP가 브라우저에게 Baron SSO OIDC 인증 URL로 이동하라고 응답한다. 예: /oidc/oauth2/auth?client_id=...&redirect_uri=...&scope=...&state=... -4. 사용자 브라우저 -> L7 -> Baron Gateway Nginx +4. 사용자 브라우저 -> Baron Gateway Nginx 브라우저가 Baron SSO의 /oidc/oauth2/auth 주소로 이동한다. 5. Baron Gateway Nginx -> Oathkeeper -> Hydra @@ -107,7 +108,7 @@ Baron Backend -> Hydra Admin API Hydra가 브라우저에게 UserFront 로그인 화면으로 이동하라고 리다이렉트한다. 예: /login?login_challenge=... -9. 사용자 브라우저 -> L7 -> Baron Gateway Nginx -> UserFront +9. 사용자 브라우저 -> Baron Gateway Nginx -> UserFront 브라우저가 실제 로그인 화면 URL을 다시 요청한다. 이 요청은 / 또는 /login 화면 요청이므로 Oathkeeper를 거치지 않고 UserFront로 간다. @@ -120,13 +121,13 @@ Baron Backend -> Hydra Admin API 첫 번째 이동은 RP가 Baron SSO의 OIDC endpoint로 보내는 이동이다. ```text -사용자 브라우저 -> L7 -> Nginx -> Oathkeeper -> Hydra +사용자 브라우저 -> Baron Gateway Nginx -> Oathkeeper -> Hydra ``` 두 번째 이동은 Hydra가 UserFront 로그인 화면으로 보내는 이동이다. ```text -사용자 브라우저 -> L7 -> Nginx -> UserFront +사용자 브라우저 -> Baron Gateway Nginx -> UserFront ``` 따라서 "로그인 화면 요청은 Oathkeeper를 거치지 않는다"는 말은 두 번째 이동에 대한 설명이다. 반대로 "RP의 OIDC 인증 요청은 Oathkeeper를 거친다"는 말은 첫 번째 이동에 대한 설명이다. @@ -183,7 +184,7 @@ Baron Backend = 두 시스템을 연결해서 완료 처리하는 중계자 flowchart TD U[사용자 브라우저] RP[RP/업무시스템] - EDGE[L7/Traefik + Baron Gateway Nginx] + GW[Baron Gateway Nginx] OK[Oathkeeper] UF[UserFront] BE[Baron Backend] @@ -192,15 +193,15 @@ flowchart TD R[Redis] U -->|RP 보호 페이지 접근| RP - RP -->|/oidc/oauth2/auth| EDGE - EDGE -->|/oidc/*, /auth/*| OK + RP -->|/oidc/oauth2/auth| GW + GW -->|/oidc/*, /auth/*| OK OK --> HY OK --> KR HY -->|login_challenge로 화면 이동| U - U -->|로그인 화면 요청 /| EDGE - EDGE --> UF - UF -->|/api/v1/*| EDGE - EDGE --> BE + U -->|로그인 화면 요청 /| GW + GW --> UF + UF -->|/api/v1/*| GW + GW --> BE BE --> KR BE --> HY BE --> R @@ -210,9 +211,9 @@ flowchart TD | 구분 | 경로 | 의미 | | --- | --- | --- | -| 화면 진입 | `사용자 -> L7 -> Nginx -> UserFront` | 로그인 페이지를 보여주는 경로 | -| Baron API | `UserFront -> L7 -> Nginx -> Backend` | 로그인 버튼 클릭, 링크 발송, QR 생성, 폴링 요청 | -| Ory Public | `브라우저 또는 Nginx -> Oathkeeper -> Kratos/Hydra` | Ory public API 또는 OIDC public endpoint | +| 화면 진입 | `사용자 -> Baron Gateway Nginx -> UserFront` | 로그인 페이지를 보여주는 경로 | +| Baron API | `UserFront -> Baron Gateway Nginx -> Backend` | 로그인 버튼 클릭, 링크 발송, QR 생성, 폴링 요청 | +| Ory Public | `브라우저 또는 Baron Gateway Nginx -> Oathkeeper -> Kratos/Hydra` | Ory public API 또는 OIDC public endpoint | | 내부 백채널 | `Backend -> Kratos/Hydra/Redis` | 세션 발급, OIDC accept, 대기 상태 저장 | ### 3.3 공통 토큰 저장 위치 @@ -263,7 +264,6 @@ sequenceDiagram autonumber actor User as 사용자 participant RP as RP/업무시스템 - participant L7 as L7/Traefik participant GW as Baron Gateway Nginx participant OK as Oathkeeper participant HY as Ory Hydra @@ -272,15 +272,13 @@ sequenceDiagram User->>RP: 업무시스템 접속 또는 보호 페이지 접근 RP->>RP: RP 자체 세션 확인 RP-->>User: RP 세션 없음, /oidc/oauth2/auth로 브라우저 리다이렉트 - User->>L7: GET /oidc/oauth2/auth?client_id=...&redirect_uri=... - L7->>GW: 요청 전달 + User->>GW: GET /oidc/oauth2/auth?client_id=...&redirect_uri=... GW->>OK: /oidc/* 경로 전달 OK->>HY: strip_path 후 Hydra /oauth2/auth 전달 HY->>HY: client_id, redirect_uri, scope, state, PKCE 검증 alt 기존 Baron SSO 로그인 세션 없음 HY-->>User: login_challenge 포함 UserFront 로그인 화면으로 리다이렉트 - User->>L7: UserFront 로그인 화면 요청 - L7->>GW: 화면 요청 전달 + User->>GW: UserFront 로그인 화면 요청 GW->>UF: / 경로 UserFront로 전달 UF-->>User: 비밀번호/로그인 링크/QR 코드 화면 표시 else 기존 Baron SSO 로그인 세션 있음 @@ -292,7 +290,7 @@ sequenceDiagram 1. 사용자가 RP에 접속한다. 2. RP가 `client_id` 등을 담아 Baron SSO의 `/oidc/oauth2/auth`로 브라우저를 보낸다. -3. 요청은 L7, Baron Gateway Nginx, Oathkeeper를 거쳐 Hydra로 간다. +3. 요청은 Baron Gateway Nginx, Oathkeeper를 거쳐 Hydra로 간다. 4. Hydra는 RP 요청이 정상인지 확인하고, 기존 SSO 세션이 있는지 본다. 5. 로그인 세션이 없으면 `login_challenge`를 발급하고 UserFront 로그인 화면으로 보낸다. 6. 그 다음에야 사용자가 비밀번호/로그인 링크/QR 코드 중 하나를 선택한다. @@ -354,7 +352,7 @@ sequenceDiagram autonumber actor User as 사용자 participant RP as RP/업무시스템 - participant Edge as L7/Nginx + participant GW as Baron Gateway Nginx participant OK as Oathkeeper participant HY as Ory Hydra participant UF as UserFront @@ -362,13 +360,13 @@ sequenceDiagram User->>RP: 업무시스템 접속 RP->>RP: RP 세션 확인 RP-->>User: /oidc/oauth2/auth로 리다이렉트 - User->>Edge: GET /oidc/oauth2/auth?client_id=... - Edge->>OK: /oidc/* 전달 + User->>GW: GET /oidc/oauth2/auth?client_id=... + GW->>OK: /oidc/* 전달 OK->>HY: Hydra /oauth2/auth 전달 HY->>HY: RP 요청 검증, login_challenge 생성 HY-->>User: UserFront 로그인 화면으로 리다이렉트 - User->>Edge: UserFront 화면 요청 - Edge->>UF: / 경로 전달 + User->>GW: UserFront 화면 요청 + GW->>UF: / 경로 전달 UF-->>User: 로그인 화면 표시 ``` @@ -379,13 +377,13 @@ sequenceDiagram autonumber 12 actor User as 사용자 participant UF as UserFront - participant Edge as L7/Nginx + participant GW as Baron Gateway Nginx participant BE as Baron Backend participant KR as Ory Kratos User->>UF: 이메일/휴대폰 + 비밀번호 입력 - UF->>Edge: POST /api/v1/auth/password/login - Edge->>BE: /api/v1/auth/password/login + UF->>GW: POST /api/v1/auth/password/login + GW->>BE: /api/v1/auth/password/login BE->>KR: Kratos password 인증 KR-->>BE: session_token, cookie alt 일반 UserFront 로그인(login_challenge 없음) @@ -403,19 +401,27 @@ sequenceDiagram participant UF as UserFront participant BE as Baron Backend participant HY as Ory Hydra + participant GW as Baron Gateway Nginx + participant OK as Oathkeeper participant RP as RP/업무시스템 BE->>HY: AcceptLoginRequest(login_challenge, subject) HY-->>BE: redirectTo BE-->>UF: sessionJwt + redirectTo UF->>RP: OIDC callback 이동(code 포함) - RP->>HY: /oauth2/token에서 code 교환 + RP->>GW: /oidc/oauth2/token에서 code 교환 + GW->>OK: /oidc/oauth2/token 전달 + OK->>HY: Hydra Public /oauth2/token 전달 HY->>HY: code 검증, client 검증, token 생성 - HY-->>RP: access_token, id_token, refresh_token 반환 + HY-->>OK: access_token, id_token, refresh_token 반환 + OK-->>GW: token 응답 전달 + GW-->>RP: token 응답 전달 ``` 비밀번호 로그인에서도 토큰 저장 위치는 `3.3 공통 토큰 저장 위치`를 따른다. 즉 Kratos가 발급한 `session_token`은 UserFront 로그인 상태용으로 사용되고, RP에서 시작된 OIDC 흐름이면 Hydra가 후속으로 authorization code 및 RP용 `access_token`, `id_token`, `refresh_token`을 발급한다. Hydra 토큰은 UserFront가 아니라 RP가 자기 정책에 따라 저장한다. +운영 공개 주소를 사용하는 RP는 `/oidc/oauth2/token` 요청도 보통 Baron Gateway Nginx와 Oathkeeper를 거쳐 Hydra Public endpoint로 전달된다. 같은 내부망에서 Hydra Public endpoint를 직접 쓰는 특수 구성이 아니라면, RP token 교환 경로는 `RP -> Baron Gateway Nginx -> Oathkeeper -> Hydra`로 이해하는 것이 자연스럽다. + ## 5. 로그인 링크 ### 5.1 사용자가 보는 절차 @@ -532,7 +538,7 @@ sequenceDiagram autonumber actor User as 사용자 participant UF as 요청 브라우저(UserFront) - participant Edge as L7/Nginx + participant GW as Baron Gateway Nginx participant BE as Baron Backend participant KA as Ory Kratos/Admin participant KR as Ory Kratos/Courier @@ -540,8 +546,8 @@ sequenceDiagram participant Channel as Email/SMS User->>UF: 로그인 링크 탭에서 이메일/휴대폰 입력 - UF->>Edge: POST /api/v1/auth/enchanted-link/init - Edge->>BE: init 요청 + UF->>GW: POST /api/v1/auth/enchanted-link/init + GW->>BE: init 요청 BE->>BE: 입력값 정리 및 전화번호 정규화 BE->>KA: IdpProvider.UserExists(loginId)로 identity 조회 KA-->>BE: 사용자 존재 여부 반환 @@ -584,6 +590,8 @@ sequenceDiagram participant Redis as Redis participant KR as Ory Kratos participant HY as Ory Hydra + participant GW as Baron Gateway Nginx + participant OK as Oathkeeper participant RP as RP/업무시스템 BE->>KR: Kratos 코드 검증/세션 발급 요청 @@ -594,9 +602,13 @@ sequenceDiagram HY-->>BE: redirectTo 반환 BE-->>UF: sessionJwt + redirectTo UF->>RP: redirectTo 따라 RP callback 이동(code 포함) - RP->>HY: /oauth2/token에서 code 교환 + RP->>GW: /oidc/oauth2/token에서 code 교환 + GW->>OK: /oidc/oauth2/token 전달 + OK->>HY: Hydra Public /oauth2/token 전달 HY->>HY: code 검증, client 검증, token 생성 - HY-->>RP: access_token, id_token, refresh_token 반환 + HY-->>OK: access_token, id_token, refresh_token 반환 + OK-->>GW: token 응답 전달 + GW-->>RP: token 응답 전달 else UserFront 일반 로그인(login_challenge 없음) BE-->>UF: sessionJwt 필드로 Kratos session_token 전달 end @@ -683,22 +695,22 @@ Redis 저장 예시: ### 6.4 흐름도 -QR 흐름도는 화면 폭을 줄이기 위해 L7과 Nginx를 `L7/Nginx`로 묶어 표현한다. +QR 흐름도에서도 앞단 진입 계층은 `Baron Gateway Nginx`로 통일해서 표현한다. ```mermaid sequenceDiagram autonumber actor User as 사용자 participant PC as 요청 PC(UserFront) - participant Edge as L7/Nginx + participant GW as Baron Gateway Nginx participant BE as Baron Backend participant Redis as Redis participant Mobile as 이미 로그인된 승인 기기 participant KR as Ory Kratos User->>PC: QR 코드 탭 선택 - PC->>Edge: POST /api/v1/auth/qr/init - Edge->>BE: QR init + PC->>GW: POST /api/v1/auth/qr/init + GW->>BE: QR init BE->>Redis: pendingRef/status=pending 저장 BE->>Redis: qrRef -> pendingRef 매핑 저장 BE-->>PC: qrCode URL, pendingRef, expiresIn