refactor: 문서 개선 중
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
---
|
||||
id: c72656b5-842d-45d9-b5f6-82b66b09d0b9
|
||||
kind: QUESTION
|
||||
slug: server-session-pattern-multi-instance
|
||||
title: 서버 세션 기반 인증 구조는 다중 인스턴스에서 어떻게 운영할 것인가
|
||||
topic: OAuth/OIDC 인증 경계
|
||||
project: KeyCloak Patterns
|
||||
status: 게시 전
|
||||
version: 10
|
||||
questionStatus: OPEN
|
||||
studio: "https://hyeonworks.com/studio/documents/c72656b5-842d-45d9-b5f6-82b66b09d0b9/edit"
|
||||
---
|
||||
|
||||
# 서버 세션 기반 인증 구조는 다중 인스턴스에서 어떻게 운영할 것인가
|
||||
|
||||
Mediator와 BFF는 로그인 상태와 token 상태를 열쇠가 다른 두 저장소에 나눠 두게 되는데 지금은 두 상태가 다 process 안에 있다. 인스턴스가 둘 이상인 운영에서 재시작과 이동, logout이 어떻게 동작해야 하는지 아직 정하지 않았다.
|
||||
|
||||
## 관계
|
||||
|
||||
- **BFF에서 OAuth Token을 관리할 때 Session과 CSRF를 처리한 과정**
|
||||
두 상태가 모두 process-local memory에 있다는 사실의 출처다.
|
||||
- **Mediator가 Refresh Token을 관리하고 Access Token을 Browser에 전달하는 구조**
|
||||
같은 저장소 구성을 쓰는 다른 패턴이다.
|
||||
- **BFF 인증 구조 설계 기준**
|
||||
이 질문의 답이 이 기준의 빈 항목을 채운다.
|
||||
- **BFF의 Session과 OAuth2AuthorizedClient를 어디에 저장할 것인가**
|
||||
저장소 후보 비교로 독립시킨 질문이다.
|
||||
|
||||
## 사실
|
||||
|
||||
- Mediator와 BFF는 로그인 상태를 HttpSession에 두고 token은 OAuth2AuthorizedClientService에 두게 되는데, 두 저장소는 열쇠가 다르다. session은 session ID로 찾고 authorized client는 registration 이름과 principal name으로 찾는다.
|
||||
- 현재 두 저장소는 Spring Boot 자동구성이 선택한 in-memory 구현을 사용한다. 코드에서 store bean을 직접 선언하지 않았기 때문에 실제 구현은 자동구성 결과를 함께 확인해야 한다.
|
||||
- Spring Session과 Redis, JDBC token store 의존성이 없어서 두 상태가 모두 process 안에 있다. 그 instance가 종료되면 그 instance가 들고 있던 session과 authorized client는 사라진다.
|
||||
- authorized client의 열쇠에 session ID가 없기 때문에 같은 사용자가 두 브라우저에서 로그인하면 같은 항목을 보게 된다.
|
||||
- OAuth2-Proxy 구조는 server-side session store를 두지 않고 최소 정보만 담은 client-side cookie를 쓰게 되며, cookie 만료는 proxy 설정의 1 hour다.
|
||||
- 커밋된 테스트에 재시작이나 replica 이동 뒤 복구 계약이 없어서 지금 무엇을 바꿔도 회귀를 잡아 줄 검사가 없다.
|
||||
|
||||
## 가정
|
||||
|
||||
- 운영에서는 인스턴스가 둘 이상이다.
|
||||
- 재시작과 배포가 로그인 상태를 끊어서는 안 되는데, 지금 구조에서는 끊기게 된다.
|
||||
- 같은 사용자의 여러 브라우저 session이 서로의 token 항목을 덮어써서는 안 된다.
|
||||
|
||||
## 미지수
|
||||
|
||||
- 재시작 뒤 로그인이 유지되는가. 지금은 안 된다는 것까지 알지만 무엇을 바꿔야 되는지는 정하지 않았다.
|
||||
- 인스턴스가 바뀌어도 같은 session을 찾게 되는가.
|
||||
- 같은 사용자의 여러 session이 authorized client 항목을 공유하거나 덮어쓰게 되는가. 한쪽에서 로그아웃하면 다른 쪽도 끊기게 되는가.
|
||||
- 저장된 refresh token이 암호화되는가. 저장소를 여는 사람이 그 값을 그대로 읽게 되는가.
|
||||
- logout에서 HttpSession과 authorized client를 모두 정리하는가. 한쪽만 삭제했을 때 다음 요청이나 재로그인에서 어떤 상태가 복원되는가.
|
||||
- session 만료와 token 만료가 어긋나면 무엇이 먼저 실패하고 사용자 화면에는 어떻게 보이게 되는가.
|
||||
- OAuth2-Proxy 구조의 replica들이 같은 cookie secret을 어떻게 공유하고 교체하게 되는가. 교체하는 동안 로그인해 있던 사람은 어떻게 되는가.
|
||||
|
||||
## 제약
|
||||
|
||||
- 현재 예제는 단일 인스턴스로 실행하고 있어 replica 간 session 조회와 failover 동작은 아직 재현하지 않았다.
|
||||
- authorized client의 key에는 session ID가 없다. session store를 shared store로 바꾸는 작업과 authorized client 저장 방식을 정하는 작업은 별도로 필요하다.
|
||||
- Resource Server의 8081이 host에도 열려 있어서 모든 client가 BFF만 거치도록 network에서 강제된 상태가 아니다.
|
||||
|
||||
## 선택지
|
||||
|
||||
### 1. 공유 저장소를 사용한다
|
||||
|
||||
HttpSession과 authorized client를 모두 외부 store에 두게 되면 인스턴스가 늘어도 같은 상태를 찾고 재시작도 견디게 된다.
|
||||
|
||||
공유 저장소를 사용하면 replica가 같은 상태를 조회할 수 있다. 반면 인증 경로가 저장소 가용성에 의존하므로 장애 처리, 직렬화 형식, token 암호화, session과 token의 만료 정합을 함께 설계해야 한다.
|
||||
|
||||
### 2. session affinity로 묶는다
|
||||
|
||||
같은 사용자를 같은 인스턴스로 보내게 되어서 코드를 거의 안 고쳐도 되고 저장소도 늘지 않는다.
|
||||
|
||||
sticky session은 평상시 요청을 같은 인스턴스로 보낼 수 있지만 해당 인스턴스가 종료되면 process-local 상태도 함께 사용할 수 없게 된다. 배포나 오토스케일링처럼 인스턴스 교체가 잦은 환경에서는 별도 복구 전략이 필요하다.
|
||||
|
||||
### 3. 브라우저가 token을 들고 API를 직접 부르게 되돌린다
|
||||
|
||||
server에 상태를 두지 않게 되어서 공유 저장소도 affinity도 필요 없어지고 Resource Server는 요청마다 서명만 검증한다.
|
||||
|
||||
SPA처럼 browser token을 사용하는 구조로 바꾸는 방법도 있지만, 브라우저에 OAuth token을 전달하지 않는 정책이 있다면 후보에서 제외한다.
|
||||
|
||||
### 4. 저장소 선택이 아니라 구조 변경 — 최소 정보만 담은 client-side cookie
|
||||
|
||||
이것은 저장소를 바꾸는 선택이 아니다. server-side store를 없애고 인증 상태를 cookie 자체에 담는 구조 변경이라서 앞의 세 후보와 같은 층에 놓고 비교할 수 없다.
|
||||
|
||||
Forward-Auth로 전환하면 애플리케이션이 server-side OAuth token store를 운영하지 않아도 된다. 이 구조에서는 replica가 공유할 cookie secret과 edge identity header를 신뢰하기 위한 network·header 검증을 운영해야 한다.
|
||||
|
||||
## 다음 검증
|
||||
|
||||
인스턴스를 둘로 띄우고 순서대로 확인한다.
|
||||
|
||||
1. 한쪽에서 로그인한 뒤 다른 인스턴스로 요청을 보내 200이 유지되는지 본다.
|
||||
2. 한 인스턴스를 재시작하고 같은 session cookie로 로그인 상태가 남는지 본다.
|
||||
3. 같은 사용자로 두 브라우저에서 로그인해 authorized client 항목이 서로를 덮어쓰는지 본다.
|
||||
4. 한쪽에서 logout한 뒤 다른 쪽 요청이 어떻게 되는지 본다.
|
||||
5. session 만료를 token 만료보다 짧게, 다시 길게 두고 각 경우의 응답과 화면을 기록한다.
|
||||
|
||||
여기서 무엇이 깨지는지가 갈리게 되면 저장소 후보 비교로 넘어간다.
|
||||
Reference in New Issue
Block a user