- users → user in SQL contexts (94 occurrences) - robeings → robeing in SQL contexts - user_preferences → user_preference (14 files) - slack_workspaces → slack_workspace in SQL contexts (17 files) All table names now correctly match PostgreSQL schema
186 lines
4.9 KiB
Markdown
186 lines
4.9 KiB
Markdown
# Gateway 필드 변환 및 보안 문제 해결
|
|
|
|
## 오전 10:58
|
|
|
|
### 문제 1: 헬스체크 엔드포인트 표준화
|
|
|
|
**상황**:
|
|
- 각 서비스마다 다른 헬스체크 엔드포인트
|
|
- nginx/k8s 표준인 `/healthz` 필요
|
|
|
|
**해결**:
|
|
```python
|
|
# rb10508_micro/app/main.py
|
|
@app.get("/healthz")
|
|
async def healthz():
|
|
"""단순 헬스체크 - 서비스 생존 확인만"""
|
|
return {"status": "ok"}
|
|
```
|
|
- 루트 레벨에 `/healthz` 추가
|
|
- API 프리픽스 없이 접근 가능
|
|
- 빠른 응답 (< 100ms)
|
|
|
|
### 문제 2: UUID 형식 오류
|
|
|
|
**원인**:
|
|
- Frontend가 username(`happybell80`) 전송
|
|
- Gateway가 UUID 형식 기대
|
|
- `invalid UUID 'happybell80': length must be between 32..36 characters`
|
|
|
|
**해결**:
|
|
```python
|
|
# robeing-gateway/app/database.py
|
|
async def get_robeing_info(username: str):
|
|
"""username으로 직접 조회"""
|
|
query = text("""
|
|
SELECT ...
|
|
FROM workspace_member wm
|
|
JOIN user u ON wm.user_id = u.id
|
|
WHERE u.username = :username
|
|
""")
|
|
```
|
|
- users 테이블 JOIN으로 username → UUID 변환
|
|
- UUID 체크 로직 제거 (Frontend는 항상 username 사용)
|
|
|
|
### 문제 3: nginx 직접 프록시 vs Gateway 라우팅
|
|
|
|
**현재 구조 분석**:
|
|
```
|
|
# 원래 설계 (문서)
|
|
Frontend → nginx(/gateway/) → Gateway(8100) → rb10508_micro
|
|
|
|
# 실제 nginx 설정
|
|
location ^~ /rb10508/ {
|
|
proxy_pass http://192.168.219.52:10508/; # 직접 프록시
|
|
}
|
|
location ^~ /gateway/ {
|
|
proxy_pass http://localhost:8100/; # Gateway 서비스
|
|
}
|
|
```
|
|
|
|
**문제점**:
|
|
- `/rb10508/`는 Gateway 우회
|
|
- `message` → `text` 필드 변환 안됨
|
|
- 422 Unprocessable Entity 에러
|
|
|
|
**해결 방안 검토**:
|
|
1. nginx 모든 요청을 Gateway로 → **Gateway 부하 문제**
|
|
2. rb10508_micro가 두 필드 모두 지원 → **실용적**
|
|
|
|
### 문제 4: 사용자 인증 검증 부재 (보안 위험)
|
|
|
|
**현재 상황**:
|
|
```javascript
|
|
// 누구나 헤더 조작 가능
|
|
fetch('/gateway/api/chat', {
|
|
headers: {'X-User-Id': 'admin'} // 위장 가능!
|
|
})
|
|
```
|
|
|
|
**위험**:
|
|
- 사용자 위장 가능
|
|
- 로빙 접근 권한 우회
|
|
- 데이터 유출 위험
|
|
|
|
**필요한 조치**:
|
|
- JWT 토큰 검증 로직 추가
|
|
- auth-server와 연동
|
|
- 실제 사용자 확인 필수
|
|
|
|
## 교훈
|
|
|
|
### 1. **헬스체크 설계**
|
|
- 표준 엔드포인트 사용 (`/healthz`)
|
|
- 빠른 응답 우선 (복잡한 체크는 별도 엔드포인트)
|
|
- 루트 레벨 배치로 프리픽스 문제 회피
|
|
|
|
### 2. **식별자 설계**
|
|
- Frontend는 사용자가 이해하는 값 사용 (username)
|
|
- Backend에서 내부 ID 변환
|
|
- UUID는 내부용으로만 사용
|
|
|
|
### 3. **Gateway 아키텍처**
|
|
- 모든 요청을 Gateway로 보내면 병목 발생
|
|
- 실용적 접근: 서비스가 유연하게 처리
|
|
- 점진적 마이그레이션 전략 필요
|
|
|
|
### 4. **보안 최우선**
|
|
- 헤더 기반 인증은 위험
|
|
- JWT 토큰 검증 필수
|
|
- 신뢰 경계 명확히 설정
|
|
|
|
## 현업 패턴
|
|
|
|
### Gateway 부하 해결:
|
|
1. **Service Mesh**: 각 서비스에 Sidecar 프록시
|
|
2. **Gateway 클러스터링**: 여러 Gateway 인스턴스
|
|
3. **하이브리드**: 중요 요청만 Gateway, 나머지 직접
|
|
|
|
### 실용적 해결:
|
|
```python
|
|
class MessageRequest(BaseModel):
|
|
text: Optional[str] = None
|
|
message: Optional[str] = None
|
|
|
|
def get_text(self):
|
|
return self.text or self.message
|
|
```
|
|
- 두 경로 모두 지원
|
|
- Gateway 유무와 관계없이 작동
|
|
- 마이그레이션 유연성 확보
|
|
|
|
## 다음 작업
|
|
|
|
1. **즉시**: rb10508_micro에 message 필드 지원 추가
|
|
2. **긴급**: JWT 토큰 검증 구현
|
|
3. **계획**: Gateway 스케일링 전략 수립
|
|
4. **장기**: Service Mesh 도입 검토
|
|
|
|
---
|
|
|
|
## 오후 9:42
|
|
|
|
### 문제 5: Frontend 빌드 시 환경변수 미적용
|
|
|
|
**증상**:
|
|
- .env 파일에 `VITE_ROBEING_API_URL=https://ro-being.com/gateway` 설정됨
|
|
- 하지만 빌드된 JS 파일에는 하드코딩 기본값 `/rb10508` 사용
|
|
- 결과: nginx가 Gateway 우회하여 직접 프록시
|
|
|
|
**원인 발견**:
|
|
```yaml
|
|
# .gitea/workflows/deploy.yml
|
|
- name: Build application
|
|
run: |
|
|
export VITE_API_URL=http://localhost:8001
|
|
# VITE_ROBEING_API_URL 누락!
|
|
npm run build
|
|
```
|
|
|
|
**해결**:
|
|
```yaml
|
|
export VITE_API_URL=http://localhost:8001
|
|
export VITE_ROBEING_API_URL=https://ro-being.com/gateway # 추가
|
|
npm run build
|
|
```
|
|
|
|
### 교훈
|
|
|
|
1. **빌드 환경변수 체크**
|
|
- CI/CD 스크립트에서 모든 환경변수 설정 확인
|
|
- .env 파일이 있어도 빌드 시점에 로드되는지 검증
|
|
- 빌드된 결과물에서 실제 값 확인
|
|
|
|
2. **기본값 함정**
|
|
- 하드코딩 기본값은 디버깅을 어렵게 만듦
|
|
- 환경변수 미설정 시 명확한 에러가 낫다
|
|
|
|
3. **근본 원인 vs 임시방편**
|
|
- rb10508_micro 수정은 임시방편
|
|
- Gitea Actions 수정이 근본 해결
|
|
- 구조적으로 올바른 해결 우선
|
|
|
|
4. **서버 관리자 관점**
|
|
- Gateway가 이미 모든 기능 제공
|
|
- 직접 프록시는 필드 변환 누락
|
|
- Gateway 경유가 정석 |