docs: Email Skill 인증 오류 및 Cron 토큰 문제 트러블슈팅
- Email Skill HTTP 500 오류 분석 (3명 사용자 영향)
- gmail_token vs gmail_tokens 테이블명 불일치 문제 파악
- Cron 인증 취약점 확인 (401 에러 주석 처리됨)
- 해결방안 제시: 테이블명 수정, Cron 인증 강화
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
2ddacfa877
commit
d82404229b
@ -0,0 +1,94 @@
|
||||
# Email Skill 인증 오류 및 Cron 토큰 문제
|
||||
|
||||
**작성일**: 2025-09-13
|
||||
**작성자**: happybell80 & Claude
|
||||
**영향 서비스**: skill-email, rb8001
|
||||
**심각도**: 높음
|
||||
|
||||
## 1. 문제 상황
|
||||
|
||||
### Email Skill HTTP 500 오류
|
||||
- **증상**: skill_email 서비스가 HTTP 500 반환
|
||||
- **에러**: `No credentials found for user: 0914eagle@gmail.com`
|
||||
- **영향**: 3명 사용자 이메일 동기화 실패 (매분 재시도 중)
|
||||
- happybell80 (goeun2dc@gmail.com)
|
||||
- 0914eagle (0914eagle@gmail.com)
|
||||
- cdctfm (cdctfm@gmail.com)
|
||||
|
||||
### Cron 트리거 권한 오류
|
||||
- **증상**: `Unauthorized cron trigger attempt` 경고 발생
|
||||
- **위치**: rb8001/main.py:558
|
||||
- **문제**: 인증 실패에도 요청 처리 계속됨 (보안 취약)
|
||||
|
||||
## 2. 원인 분석
|
||||
|
||||
### Email 인증 실패 원인
|
||||
```python
|
||||
# skill-email/services/gmail_service.py:49
|
||||
if creds_result is None:
|
||||
return Err(EmailError(f"No credentials found for user: {user_id}"))
|
||||
|
||||
# skill-email/services/db_credentials_provider.py:63
|
||||
SELECT token_data->>'refresh_token' as refresh_token
|
||||
FROM gmail_token # 테이블명 문제: 실제 DB는 gmail_tokens (복수형)
|
||||
WHERE slack_user_id = %s AND is_equipped = true
|
||||
```
|
||||
|
||||
1. **테이블명 불일치**: 코드는 `gmail_token`, DB는 `gmail_tokens`
|
||||
2. **토큰 데이터 구조**: token_data JSONB 내부에 저장 (250909 문서 확인)
|
||||
3. **is_equipped 조건**: 토큰이 있어도 장착되지 않으면 조회 실패
|
||||
|
||||
### Cron 인증 취약점
|
||||
```python
|
||||
# rb8001/main.py:556-560
|
||||
expected_token = settings.CRON_TOKEN if hasattr(settings, 'CRON_TOKEN') else "cron-secret-2024"
|
||||
|
||||
if auth_header != f"Bearer {expected_token}":
|
||||
logger.warning("Unauthorized cron trigger attempt")
|
||||
# raise HTTPException(status_code=401, detail="Unauthorized") # 주석 처리됨!
|
||||
```
|
||||
|
||||
- 하드코딩된 기본 토큰 사용
|
||||
- 인증 실패시 경고만 기록, 요청은 계속 처리
|
||||
|
||||
## 3. 관련 문서 참조
|
||||
|
||||
- **250909**: gmail_refresh_token 컬럼/JSONB 불일치 해결
|
||||
- **250825**: Gmail 토큰 만료 문제 (동일 사용자 3명)
|
||||
- **250801**: 크론잡 로그 동기화 설정
|
||||
|
||||
## 4. 해결 방안
|
||||
|
||||
### 즉시 조치 (로컬 개발자)
|
||||
```python
|
||||
# 1. skill-email 테이블명 수정
|
||||
# services/db_credentials_provider.py:67
|
||||
- FROM gmail_token
|
||||
+ FROM gmail_tokens # 복수형으로 수정
|
||||
|
||||
# 2. Cron 인증 강화
|
||||
# rb8001/main.py:560
|
||||
- # raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
+ raise HTTPException(status_code=401, detail="Unauthorized")
|
||||
```
|
||||
|
||||
### 서버 작업 필요 (서버 관리자)
|
||||
```sql
|
||||
-- 토큰 상태 확인
|
||||
SELECT slack_user_id, is_equipped,
|
||||
token_data->>'refresh_token' IS NOT NULL as has_token
|
||||
FROM gmail_tokens
|
||||
WHERE slack_user_id IN ('0914eagle', 'happybell80', 'cdctfm');
|
||||
|
||||
-- is_equipped 설정
|
||||
UPDATE gmail_tokens
|
||||
SET is_equipped = true
|
||||
WHERE slack_user_id IN ('0914eagle', 'happybell80', 'cdctfm');
|
||||
```
|
||||
|
||||
## 5. 교훈
|
||||
|
||||
1. **테이블명 일관성**: 단수/복수형 통일 필요 (250911 문서 참조)
|
||||
2. **보안 우선**: 인증 실패시 반드시 요청 차단
|
||||
3. **환경변수 사용**: 하드코딩 대신 .env 파일 활용
|
||||
4. **토큰 관리**: JSONB 구조로 일원화 완료, 테이블명만 수정 필요
|
||||
Loading…
x
Reference in New Issue
Block a user