Skip to content

Commit a9fe8d9

Browse files
committed
docs: improve gateway README
1 parent 4e50887 commit a9fe8d9

1 file changed

Lines changed: 197 additions & 51 deletions

File tree

README.md

Lines changed: 197 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,199 @@
1-
# API Gateway Service
2-
3-
이 프로젝트는 레슨 매칭 플랫폼(Lesson Matching Platform)의 진입점 역할을 하는 **Spring Cloud Gateway** 서비스입니다. 모든 클라이언트 요청은 이 게이트웨이를 거쳐 내부 마이크로서비스로 라우팅되며, 공통적인 인증 및 인가 처리를 담당합니다.
4-
5-
## 🛠️ 기술 스택 (Tech Stack)
6-
- **Java**: 21
7-
- **Framework**: Spring Boot 4.1.0, Spring Cloud 2025.1.2
8-
- **Gateway**: Spring Cloud Gateway (WebFlux 기반)
9-
- **Security**: Spring Security WebFlux, JWT (JSON Web Token)
10-
- **Build Tool**: Gradle
11-
12-
## ✨ 주요 기능 (Features)
13-
14-
### 1. API 라우팅 (Routing)
15-
`application.yml`에 정의된 라우팅 규칙에 따라 클라이언트의 요청을 적절한 백엔드 마이크로서비스로 포워딩합니다.
16-
- `/auth/**` : 인증 서비스(`AUTH_SERVICE_HOST`)로 라우팅
17-
- `/get/**` : 목업 서버(`MOCK_SERER`)로 라우팅
18-
- 요청을 전달할 때 게이트웨이를 거쳤음을 알리기 위해 `X-Request-Source: Gateway` 헤더를 추가합니다.
19-
20-
### 2. 보안 및 인증 (Security & Authentication)
21-
- **JWT 기반 인증**: 클라이언트로부터 전달받은 JWT 토큰의 유효성을 검사하여 인증을 수행합니다 (`JwtAuthenticationManager`, `JwtAuthenticationConverter`).
22-
- **권한 설정**:
23-
- `/auth/**`, `/public/**` 엔드포인트는 인증 없이 접근할 수 있습니다. (Permit All)
24-
- 그 외의 모든 요청은 인증을 거쳐야 합니다.
25-
- WebFlux 전용 Security 설정(`@EnableWebFluxSecurity`)을 사용하며, 무상태(Stateless) API 통신을 위해 CSRF, Form Login, HTTP Basic 기능은 비활성화되어 있습니다.
26-
27-
### 3. 사용자 정보 전달 필터 (UserInfoFilter)
28-
- 인가된 사용자의 요청이 게이트웨이를 통과할 때 동작하는 전역 필터(Global Filter)입니다.
29-
- SecurityContext에서 인증 객체(JWT 파싱 결과)를 가져와 `userId``role` 정보를 추출합니다.
30-
- 하위 마이크로서비스로 요청을 전달할 때, **`X-User-Id`****`X-User-Role`** HTTP 헤더에 해당 정보를 담아 전달합니다.
31-
- 이를 통해 개별 마이크로서비스는 별도의 JWT 검증 과정 없이 헤더 정보만으로 요청한 사용자를 식별할 수 있습니다.
32-
33-
## 📂 프로젝트 구조 (Project Structure)
1+
# Lesson Matching Platform API Gateway
2+
3+
Lesson Matching Platform의 외부 진입점입니다. Spring Cloud Gateway(WebFlux)를 기반으로 클라이언트 요청을 내부 서비스로 전달하고, JWT 인증·CORS·요청 추적·사용자 정보 전달을 공통 처리합니다.
4+
5+
## Role in the Platform
6+
7+
```mermaid
8+
flowchart LR
9+
Client["Client"] --> Gateway["API Gateway\nSpring Cloud Gateway"]
10+
Gateway --> Backend["Core Backend"]
11+
Gateway --> Ledger["Ledger"]
12+
Gateway --> Notice["Notice Server"]
13+
```
14+
15+
게이트웨이는 비즈니스 로직을 직접 처리하기보다 모든 서비스 요청에 공통으로 필요한 경계 책임을 담당합니다.
16+
17+
## Responsibilities
18+
19+
### 1. Service Routing
20+
21+
라우팅 대상 주소는 환경 변수로 주입합니다. 로컬에서는 기본값으로 `localhost`를 사용하고, GCP에서는 Terraform이 내부 DNS 호스트명을 전달합니다.
22+
23+
| Incoming path | Destination | Gateway behavior |
24+
| --- | --- | --- |
25+
| `/api/**` | Core Backend | `X-Request-Source: Gateway` 추가 |
26+
| `/resources/files/**` | Core Backend | 파일 리소스 전달, 인증 예외 |
27+
| `/api/v1/ledger-entry/**` | Ledger | 앞의 두 경로 세그먼트 제거 후 전달 |
28+
| `/api/v1/notification/**` | Notice Server | `X-Request-Source: Gateway` 추가 |
29+
| `/test` | Mock Server | 테스트용 경로 재작성 |
30+
31+
주요 환경 변수:
32+
33+
```text
34+
BACKEND_HOST # Core Backend host
35+
LEDGER_HOST # Ledger host
36+
NOTIFICATION_HOST # Notice Server host
37+
```
38+
39+
### 2. JWT Authentication
40+
41+
- `Authorization: Bearer <token>` 형식의 JWT를 추출합니다.
42+
- `JwtProvider`가 서명과 만료 여부를 검증합니다.
43+
- JWT claims에서 `userId`, `role`을 읽어 Reactive Security Context에 저장합니다.
44+
- 인증이 필요한 요청은 검증에 실패하면 내부 서비스로 전달하지 않습니다.
45+
- CSRF, Form Login, HTTP Basic은 stateless API 특성에 맞게 비활성화했습니다.
46+
47+
인증 없이 접근할 수 있는 주요 경로는 다음과 같습니다.
48+
49+
- `OPTIONS /**`
50+
- `GET /api/v1/categories`
51+
- `GET /api/v1/lessons/search`
52+
- `GET /api/v1/lessons/{lessonId}`
53+
- `GET /api/v1/lessons/{lessonId}/reviews`
54+
- `POST /api/v1/auth/login`
55+
- `POST /api/v1/members/signup`
56+
- `/auth/**`, `/public/**`, `/actuator/**`
57+
- `/resources/files/**`, `/test`
58+
59+
그 외 요청은 인증된 JWT가 필요합니다.
60+
61+
### 3. User Context Propagation
62+
63+
인증된 요청은 `UserInfoFilter`를 통해 아래 헤더를 내부 서비스로 전달합니다.
64+
65+
```text
66+
X-User-Id # JWT의 userId claim
67+
X-User-Role # JWT의 role claim
68+
```
69+
70+
내부 서비스가 요청마다 JWT를 다시 파싱하지 않고도 인증된 사용자의 식별자와 역할을 사용할 수 있도록 공통 경계를 제공합니다.
71+
72+
### 4. Request ID Propagation
73+
74+
`RequestIdFilter`는 모든 요청에 `X-Request-Id`를 부여합니다.
75+
76+
- 클라이언트가 유효한 `X-Request-Id`를 보내면 기존 값을 유지합니다.
77+
- 값이 없으면 UUID를 생성합니다.
78+
- 요청 헤더와 응답 헤더에 동일한 ID를 설정합니다.
79+
- MDC에 ID를 넣어 로그에서 요청 단위 추적이 가능하도록 합니다.
80+
81+
### 5. CORS and Observability
82+
83+
- 로컬 프론트엔드(`localhost:3000`, `127.0.0.1:3000`)를 CORS 허용 origin으로 설정합니다.
84+
- `Authorization`, `Content-Type`, `Accept` 등의 요청 헤더를 허용합니다.
85+
- `/actuator/health`, `/actuator/info`, `/actuator/prometheus`를 노출합니다.
86+
- Prometheus 메트릭에 애플리케이션 이름을 태그로 추가합니다.
87+
88+
## Authentication Flow
89+
90+
```mermaid
91+
sequenceDiagram
92+
participant Client
93+
participant Gateway
94+
participant Service as Internal Service
95+
Client->>Gateway: Request + Bearer JWT
96+
Gateway->>Gateway: Validate signature and claims
97+
Gateway->>Gateway: Create or preserve X-Request-Id
98+
Gateway->>Service: X-User-Id / X-User-Role / X-Request-Id
99+
Service-->>Gateway: Response
100+
Gateway-->>Client: Response + X-Request-Id
101+
```
102+
103+
## Project Structure
104+
34105
```text
35106
src/main/java/com/hwan/gateway/
36-
├── config/
37-
│ └── SecurityConfig.java # Spring Security WebFlux 설정 (경로 권한 및 필터 등록)
38-
├── controller/
39-
│ └── AuthController.java # 게이트웨이 레벨의 인증 관련 컨트롤러
40-
├── filter/
41-
│ └── UserInfoFilter.java # 인증된 사용자 정보를 헤더에 주입하는 Global Filter
42-
├── jwt/
43-
│ ├── JwtAuthenticationConverter.java # HTTP 요청에서 JWT 토큰을 추출/변환
44-
│ ├── JwtAuthenticationManager.java # JWT 토큰 검증 및 Authentication 객체 생성
45-
│ └── JwtProvider.java # JWT 토큰 생성 및 파싱 유틸리티
46-
└── GatewayApplication.java # 메인 애플리케이션 클래스
47-
```
48-
49-
## ⚙️ 주요 설정 (application.yml)
50-
- 포트: `8080`
51-
- 환경 변수 및 Secret Manager 연동 (`import: sm://`)
52-
- 라우팅 및 Predicate, Filter 설정
53-
- JWT 시크릿 키 설정 (`jwt.secret`)
107+
├── config/
108+
│ └── SecurityConfig.java # WebFlux Security, CORS, public paths
109+
├── controller/
110+
│ └── AuthController.java # Token endpoint for local/dev use
111+
├── filter/
112+
│ ├── RequestIdFilter.java # Request ID 생성·전파·MDC 기록
113+
│ └── UserInfoFilter.java # 사용자 정보 헤더 전달
114+
├── jwt/
115+
│ ├── JwtAuthenticationConverter.java # Bearer token 추출
116+
│ ├── JwtAuthenticationManager.java # JWT 검증과 Authentication 생성
117+
│ └── JwtProvider.java # JWT 생성·파싱·검증
118+
└── GatewayApplication.java
119+
```
120+
121+
## Tech Stack
122+
123+
- Java 21
124+
- Spring Boot 4.1.0
125+
- Spring Cloud Gateway 2025.1.2
126+
- Spring WebFlux
127+
- Spring Security WebFlux
128+
- JJWT 0.12.7
129+
- Spring Cloud GCP Secret Manager
130+
- Spring Boot Actuator + Micrometer Prometheus Registry
131+
- Gradle
132+
133+
## Configuration
134+
135+
JWT secret은 코드나 설정 파일에 직접 저장하지 않고 Spring Cloud GCP Secret Manager import를 통해 주입합니다.
136+
137+
```yaml
138+
spring:
139+
config:
140+
import: sm://
141+
142+
jwt:
143+
secret: ${sm://JWT_SECRET_KEY}
144+
```
145+
146+
로컬에서 Secret Manager를 사용하지 않는 경우에는 실행 환경에서 `JWT_SECRET_KEY`를 안전하게 주입하는 별도 설정이 필요합니다. 실제 운영 Secret과 테스트용 Secret을 분리해서 사용해야 합니다.
147+
148+
## Local Development
149+
150+
```bash
151+
./gradlew bootRun
152+
```
153+
154+
기본 포트는 `8080`입니다. 내부 서비스 주소를 로컬에서 지정하려면 다음과 같이 실행할 수 있습니다.
155+
156+
```bash
157+
BACKEND_HOST=localhost \
158+
LEDGER_HOST=localhost \
159+
NOTIFICATION_HOST=localhost \
160+
./gradlew bootRun
161+
```
162+
163+
`/auth/token` 엔드포인트는 `userId`와 `role`을 받아 JWT를 생성합니다. 이 기능은 로컬·개발 테스트 편의를 위한 용도로만 사용하고, 외부에 공개되는 운영 환경에서는 접근을 제한해야 합니다.
164+
165+
예시:
166+
167+
```bash
168+
curl "http://localhost:8080/auth/token?userId=user-001&role=USER"
169+
```
170+
171+
## Build and Test
172+
173+
```bash
174+
./gradlew test
175+
./gradlew build
176+
```
177+
178+
현재 테스트는 JWT 생성·파싱·검증과 Spring Boot 컨텍스트 구성을 중심으로 구성되어 있습니다.
179+
180+
## CI/CD
181+
182+
`.github/workflows/gradle.yml`은 `main` 브랜치 push를 기준으로 다음 작업을 수행합니다.
183+
184+
1. Java 21 환경 구성
185+
2. Gradle build
186+
3. GitHub Actions Workload Identity Federation으로 GCP 인증
187+
4. Docker 이미지 빌드
188+
5. Artifact Registry에 이미지 push
189+
6. `api-gateway` Compute Engine VM 재시작
190+
191+
GCP 인증 정보는 GitHub Actions Secret과 Variable로 관리하며 저장소에 직접 기록하지 않습니다.
192+
193+
## Security Notes
194+
195+
- JWT secret은 Secret Manager에서 관리합니다.
196+
- 내부 서비스는 외부에 직접 노출하지 않고 Gateway를 통해 접근하도록 구성하는 것을 전제로 합니다.
197+
- `X-User-Id`, `X-User-Role`은 내부 네트워크에서만 신뢰해야 하며, 내부 서비스 포트가 외부에 공개되지 않도록 방화벽을 제한해야 합니다.
198+
- `/auth/token`은 테스트용 토큰 발급 기능이므로 운영 환경에서 비활성화하거나 접근을 제한해야 합니다.
199+
- CORS 허용 origin은 실제 배포 도메인에 맞게 최소 범위로 설정해야 합니다.

0 commit comments

Comments
 (0)