Skip to content

Commit f3ca5e7

Browse files
committed
docs: 비밀번호 복구 정책과 Mode 1 CLI 복구 절차 추가
1 parent 9bd6d93 commit f3ca5e7

3 files changed

Lines changed: 170 additions & 73 deletions

File tree

docs/v2_FINANCIAL-LEDGER/deployment/00-overview.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ CLI는 이를 대체하지 않는다.
137137
- 초기 설치/재설정
138138
- 상태 점검
139139
- 백업/복구
140+
- Mode 1 계정 복구 (Local CLI reset)
140141
- 무인 환경 자동화
141142

142143
### CLI 역할 제한
@@ -177,4 +178,4 @@ CLI는 이를 대체하지 않는다.
177178
## 비고
178179
- 기능 분기는 존재하지 않는다.
179180
- 차이는 오직 **배포 방식과 운영 도구**에만 존재한다.
180-
- 사용자는 환경을 선택할 뿐, 제품을 다시 배울 필요가 없다.
181+
- 사용자는 환경을 선택할 뿐, 제품을 다시 배울 필요가 없다.

docs/v2_FINANCIAL-LEDGER/roadmap/01-development-plan.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,16 @@ Fieldstack/
3737
#### 1.2 Core Layer 개발
3838
**예상 기간: 6주**
3939

40-
**Auth (인증):**
41-
- [ ] Google OAuth 2.0 통합
42-
- [ ] Whitelist 시스템
43-
- [ ] JWT 세션 관리
44-
- [ ] 관리자 비밀번호 시스템
40+
**Auth (인증):**
41+
- [ ] 이메일 + 비밀번호 로그인 (기본)
42+
- [ ] TOTP 2FA (Google Authenticator 등)
43+
- [ ] Passkey(WebAuthn) 로그인 (선택)
44+
- [ ] Google OAuth 2.0 통합 (선택)
45+
- [ ] Whitelist 시스템
46+
- [ ] JWT 세션 관리
47+
- [ ] 관리자 PIN 시스템
48+
- [ ] 비밀번호 분실 복구 (SMTP self-service + Admin-assisted)
49+
- [ ] Mode 1 Local CLI reset 명령
4550

4651
**Database (DB 추상화):**
4752
- [ ] Provider 인터페이스 정의
@@ -535,4 +540,4 @@ Fieldstack/
535540
**하지만:**
536541
- 여전히 완전 무료
537542
- 여전히 Self-hosted 우선
538-
- 여전히 커뮤니티 중심
543+
- 여전히 커뮤니티 중심

docs/v2_FINANCIAL-LEDGER/technical/02-authentication.md

Lines changed: 157 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,82 @@
11
# 인증 및 접근 제어
22

3-
> 📌 **핵심 결정:**
4-
> `architecture/decisions.md § 결정 #2: 관리자 인증 (OAuth + PIN)`
3+
> 📌 **핵심 결정:**
4+
> `architecture/01-decisions.md § 결정 #2: 로컬 로그인 우선 + 선택 OAuth + 관리자 PIN`
55
6-
**최종 업데이트:** 2025-01-29
6+
**최종 업데이트:** 2026-02-22
77

88
---
99

10-
## 인증 방식
11-
12-
### Google OAuth 2.0
13-
14-
**일반 로그인:**
15-
- Google 계정으로 로그인
16-
- 일상적인 사용
17-
- Whitelist 기반 접근 제어
18-
19-
**설정 방법:**
20-
1. Google Cloud Console 접속
21-
2. OAuth 2.0 클라이언트 ID 생성
22-
3. 리다이렉트 URI 등록: `{YOUR_DOMAIN}/auth/callback`
23-
4. Client ID와 Secret을 설정에 입력
10+
## 인증 방식
11+
12+
### 인증 우선순위
13+
14+
1. **이메일 + 비밀번호 로그인 (기본/필수)**
15+
2. **TOTP 2차 인증 (권장, 관리자 필수 권장)**
16+
3. **Passkey (선택, Passwordless 지원)**
17+
4. **Google OAuth (선택, 편의 로그인)**
18+
19+
### 계정 복구 우선순위
20+
21+
1. **Self-service 복구 (SMTP 활성화 시)**
22+
2. **Admin-assisted 복구 (1회용 토큰 발급)**
23+
3. **Mode 1 복구 (Local CLI reset, 최후 수단)**
24+
25+
> ⚠️ **범위 명시:**
26+
> Synology Account와 같은 외부 계정 복구는 Fieldstack 기본 범위에서 제외합니다.
27+
> Fieldstack는 로컬 인스턴스 기준 복구(웹/관리자/CLI)만 제공합니다.
28+
29+
### 1) 이메일 + 비밀번호 (기본)
30+
31+
**일반 로그인 기본값:**
32+
- 사용자 식별자는 이메일 사용
33+
- 비밀번호는 Argon2id 해시로 저장
34+
- Whitelist 기반 접근 제어
35+
36+
### 2) TOTP 2차 인증 (Google Authenticator 등)
37+
38+
**적용 방식:**
39+
- 로그인 1차 성공 후 OTP 6자리 입력 (Step-up)
40+
- 2FA 등록은 계정 설정에서 ON/OFF
41+
- 관리자 계정은 2FA 필수 권장
42+
43+
### 3) Passkey (Passwordless)
44+
45+
**지원 목표:**
46+
- WebAuthn 기반 로그인 지원
47+
- 비밀번호 없이 기기 인증(지문/Face ID/보안키) 가능
48+
- 필요 시 2차 인증 정책과 병행 가능
49+
50+
### 4) Google OAuth 2.0 (선택)
51+
52+
**역할:**
53+
- 기본 로그인 수단이 아닌 추가 편의 로그인
54+
- 로컬 계정과 연결(Link)하여 사용
55+
56+
**설정 방법:**
57+
1. Google Cloud Console 접속
58+
2. OAuth 2.0 클라이언트 ID 생성
59+
3. 리다이렉트 URI 등록: `{YOUR_DOMAIN}/auth/callback`
60+
4. Client ID와 Secret을 설정에 입력
2461

2562
---
2663

2764
## 관리자 인증 (PIN)
2865

2966
> 💡 **왜 PIN을 선택했나요?**
30-
> `architecture/decisions.md § 결정 #2` - 설계 근거 참고
67+
> `architecture/01-decisions.md § 결정 #2` - 설계 근거 참고
3168
3269
### 개념
3370

3471
**이중 인증 구조:**
3572
```
36-
일반 사용:
37-
Google OAuth → 앱 접근
38-
39-
관리자 설정 접근:
40-
Google OAuth → 앱 접근
41-
+
42-
4~6자리 PIN → 관리자 설정 접근
73+
일반 사용:
74+
1차 로그인(이메일+비밀번호 또는 Passkey/OAuth) → 앱 접근
75+
76+
관리자 설정 접근:
77+
1차 로그인(이메일+비밀번호 또는 Passkey/OAuth) → 앱 접근
78+
+
79+
4~6자리 PIN → 관리자 설정 접근
4380
```
4481

4582
### 용도
@@ -60,7 +97,8 @@
6097
### 사용 시나리오
6198

6299
```
63-
1. Google로 이미 로그인된 상태
100+
1. 1차 로그인 완료 상태
101+
(이메일+비밀번호 또는 Passkey/OAuth)
64102
65103
2. 관리자 설정 페이지 접근 시도
66104
(예: 사용자 관리, DB 설정, 시스템 설정)
@@ -103,7 +141,8 @@
103141

104142
**작동 방식:**
105143
```
106-
1. 사용자가 Google로 로그인
144+
1. 사용자가 1차 로그인
145+
(이메일+비밀번호 또는 Passkey/OAuth)
107146
108147
2. 이메일 주소 확인
109148
@@ -127,31 +166,41 @@ admin_sessions 테이블은 관리자 PIN 인증 후 생성되는 임시 세션
127166

128167
## 인증 플로우
129168

130-
### 1. 로그인 프로세스
131-
132-
```
133-
사용자 → "Google로 로그인" 버튼 클릭
134-
135-
Google OAuth 페이지로 리다이렉트
136-
137-
사용자가 Google 계정으로 로그인
138-
139-
권한 승인 (프로필, 이메일)
140-
141-
Callback URL로 리다이렉트 (Authorization Code)
142-
143-
Backend에서 Code → Access Token 교환
144-
145-
Google API로 사용자 정보 조회
146-
147-
이메일 주소 Whitelist 확인
148-
149-
JWT 토큰 발급 → 클라이언트에 전달
150-
151-
메인 화면으로 이동
152-
```
153-
154-
### 2. 세션 관리
169+
### 1. 로그인 프로세스 (기본: 이메일 + 비밀번호 + 선택 2FA)
170+
171+
```
172+
사용자 → 이메일/비밀번호 입력
173+
174+
Backend에서 비밀번호 검증 (Argon2id)
175+
176+
계정의 2FA 활성 여부 확인
177+
178+
[2FA OFF] JWT 발급 → 메인 화면 이동
179+
180+
[2FA ON] OTP 6자리 입력 화면 표시
181+
182+
TOTP 검증 성공
183+
184+
JWT 발급 → 메인 화면 이동
185+
```
186+
187+
### 1-1. Google OAuth 로그인 (선택)
188+
189+
```
190+
사용자 → "Google로 로그인" 버튼 클릭
191+
192+
Google OAuth 페이지 리다이렉트
193+
194+
Callback 처리 후 이메일 확인
195+
196+
로컬 계정과 연결된 사용자 매핑
197+
198+
(2FA 활성 계정이면 OTP 추가 검증)
199+
200+
JWT 발급 → 메인 화면 이동
201+
```
202+
203+
### 2. 세션 관리
155204

156205
**JWT 기반:**
157206

@@ -163,7 +212,46 @@ JWT 토큰의 내부 구조(Payload)는 다음과 같습니다. 사용자의 고
163212

164213
**만료 시간:**
165214
- Access Token: 7일
166-
- Refresh Token: 30일 (선택)
215+
- Refresh Token: 30일 (선택)
216+
217+
### 3. 비밀번호 분실 복구 프로세스
218+
219+
```
220+
[경로 A] SMTP 활성화
221+
사용자 → "비밀번호를 잊으셨나요" 요청
222+
223+
서버 → 계정 존재 여부와 무관하게 동일 응답
224+
225+
단일 사용 토큰(만료 15분) 발급 및 이메일 전송
226+
227+
사용자 → 새 비밀번호 설정
228+
229+
모든 기존 세션/리프레시 토큰 무효화
230+
231+
[경로 B] SMTP 비활성화
232+
사용자 → 관리자에게 복구 요청
233+
234+
관리자 → 1회용 복구 토큰 발급 (짧은 만료)
235+
236+
사용자 → 토큰으로 비밀번호 재설정
237+
238+
모든 기존 세션/리프레시 토큰 무효화
239+
240+
[경로 C] Mode 1 (최후 수단)
241+
관리자(서버 로컬 접근 가능) → Local CLI reset 실행
242+
243+
대상 계정 비밀번호 재설정/강제 변경
244+
245+
모든 기존 세션/리프레시 토큰 무효화
246+
```
247+
248+
### 4. Mode 1 (Local CLI reset) 정의
249+
250+
- Synology Mode 1 개념을 Fieldstack 운영에 맞게 적용한 비상 복구 절차
251+
- 서버 로컬 접근 권한이 있는 운영자만 실행 가능
252+
- 데이터는 유지하고 인증 정보만 복구
253+
- 실행 후 대상 계정은 다음 로그인에서 비밀번호 변경을 강제할 수 있음
254+
- 감사 로그에 실행자, 대상 계정, 실행 시간, 실행 IP를 기록
167255

168256
---
169257

@@ -176,7 +264,7 @@ authMiddleware는 모든 보호된 API 요청에 적용되는 인증 미들웨
176264
### 관리자 PIN 인증
177265

178266
> 💡 **구현 상세:**
179-
> `architecture/decisions.md § 결정 #2: 기술 구현`
267+
> `architecture/01-decisions.md § 결정 #2: 기술 구현`
180268
181269
AdminAuthService 클래스가 관리자 PIN 인증의 전체 흐름을 담당합니다.
182270

@@ -203,7 +291,7 @@ verifySession 메서드는 세션 ID로 세션을 조회한 후, 존재하지
203291
### PIN 입력 컴포넌트
204292

205293
> 💡 **UI 구현 예시:**
206-
> `architecture/decisions.md § 결정 #2: UI 구현`
294+
> `architecture/01-decisions.md § 결정 #2: UI 구현`
207295
208296
PinInput 컴포넌트는 사용자가 PIN을 입력하는 화면을 제공합니다. length 속성으로 PIN 자릿수(4 또는 6)를 설정할 수 있습니다.
209297

@@ -226,7 +314,7 @@ ProtectedAdminRoute 컴포넌트는 관리자 전용 페이지를 보호하는
226314
## 보안 고려사항
227315

228316
> 📖 **전체 보안 정책:**
229-
> `architecture/decisions.md § 결정 #2: 보안`
317+
> `architecture/01-decisions.md § 결정 #2: 보안`
230318
231319
### Rate Limiting
232320

@@ -246,7 +334,7 @@ logFailedAttempt 함수는 PIN 인증 실패 시 사용자 ID, 실패 액션, IP
246334

247335
---
248336

249-
## Google OAuth 콜백 처리
337+
## Google OAuth 콜백 처리 (선택 기능)
250338

251339
GET /auth/google 엔드포인트는 사용자를 Google의 OAuth 인증 페이지로 리다이렉트합니다. 프로필과 이메일 정보에 대한 권한을 요청합니다.
252340

@@ -264,27 +352,30 @@ GET /auth/callback 엔드포인트는 Google에서 돌아온 콜백을 처리합
264352

265353
## 📚 관련 문서
266354

267-
- 📌 `architecture/decisions.md § 결정 #2` - PIN 방식 선택 근거
268-
- 📖 `deployment/setup-wizard.md` - 초기 관리자 설정
355+
- 📌 `architecture/01-decisions.md § 결정 #2` - PIN 방식 선택 근거
356+
- 📖 `deployment/02-setup-wizard.md` - 초기 관리자 설정
269357
- 📖 `community/02-github-policy.md` - 보안 정책
270358

271359
---
272360

273361
## FAQ
274362

275-
### Q1. 왜 비밀번호가 아니라 PIN인가요?
276-
**A:** 홈서버 환경에서는 스마트폰 잠금처럼 간단한 PIN이 더 적합합니다. 복잡한 비밀번호는 자주 입력해야 하는 관리자 설정에 부담이 됩니다.
363+
### Q1. 왜 관리자 비밀번호가 아니라 PIN인가요?
364+
**A:** 일반 로그인은 이메일+비밀번호(또는 Passkey)를 사용하고, 관리자 설정 접근만 추가 단계로 PIN을 요구합니다. 홈서버 환경에서 관리자 설정 진입 시 빠른 입력 UX를 유지하기 위한 선택입니다.
277365

278-
> 📖 상세 이유: `architecture/decisions.md § 결정 #2`
366+
> 📖 상세 이유: `architecture/01-decisions.md § 결정 #2`
279367
280368
### Q2. PIN이 안전한가요?
281369
**A:** PBKDF2 + Rate Limiting으로 충분히 안전합니다. 5회 실패 시 5분 잠금되므로 브루트포스 공격이 어렵습니다.
282370

283-
### Q3. PIN을 잊어버렸어요!
284-
**A:** 데이터베이스에서 직접 초기화해야 합니다. 백업 관리자 계정을 미리 만들어두는 것을 권장합니다.
371+
### Q3. PIN을 잊어버렸어요!
372+
**A:** Mode 1(Local CLI reset)으로 복구합니다. 서버 로컬 접근 권한이 있는 운영자가 CLI로 PIN 또는 비밀번호를 재설정하고, 이후 세션을 무효화합니다.
285373

286374
### Q4. 세션이 자주 만료돼요
287375
**A:** 30분 타임아웃은 보안을 위한 것입니다. 설정에서 조정 가능합니다 (권장하지 않음).
288376

289-
### Q5. 일반 사용자도 PIN이 필요한가요?
290-
**A:** 아니요. PIN은 관리자 설정에만 필요합니다. 일반 사용자는 Google OAuth만으로 충분합니다.
377+
### Q5. 일반 사용자도 PIN이 필요한가요?
378+
**A:** 아니요. PIN은 관리자 설정 접근에만 필요합니다. 일반 사용자는 이메일+비밀번호(기본) 또는 선택 로그인(OAuth/Passkey)으로 사용합니다.
379+
380+
### Q6. 비밀번호를 잊어버렸어요!
381+
**A:** SMTP가 활성화된 경우 self-service 재설정 링크를 사용합니다. SMTP가 없으면 관리자 발급 1회용 토큰으로 복구하고, 마지막 수단은 Mode 1(Local CLI reset)입니다.

0 commit comments

Comments
 (0)