forked from baron/baron-sso
450 lines
17 KiB
Markdown
450 lines
17 KiB
Markdown
# Baron SSO
|
|
|
|
**Baron 로그인**은 화이트 라벨링된 가족사의 모든 소프트웨어 Auth를 총괄하는 사용자 인증/인가 허브입니다.
|
|
|
|
## 버그 대응 대원칙 (필수)
|
|
- 모든 버그 수정은 반드시 **재현 테스트를 먼저 작성**합니다. (Failing test first)
|
|
- 재현 테스트 없이 코드만 먼저 고치는 행위를 금지합니다.
|
|
- 수정 후에는 **해당 재현 테스트가 통과할 때까지 반복**해서 원인 분석/수정/검증을 수행합니다.
|
|
- “테스트 통과”는 최소 기준입니다. 실제 재현 시나리오(로그인, 새로고침, 리다이렉트 등)까지 확인한 뒤에만 이슈를 종료합니다.
|
|
- 관련 변경이 발생하면 테스트 문서(`docs/test-plan/*`, `docs/trouble-shooting/*`)를 함께 업데이트합니다.
|
|
|
|
* Ory Stack으로 모든 구성요소를 self-hosting 합니다.
|
|
* Backend는 Go (Fiber)로 구성된 Ory Stack의 유일한 Command 전송 포인트입니다. 모든 Command는 ClickHouse로 강제 전송되며 Audit Log 시스템을 구성합니다.
|
|
* Front는 Backend를 통해서만 연동하며 자체가 Ory Stack의 RP기도 합니다. 크게 3개 계층으로 분리됩니다.
|
|
* UserFront: Flutter로 구현된 커스텀 UI를 통해 매끄러운 사용자 경험을 보장합니다.
|
|
* 로그인 : 비밀번호, SMS, QR 스캔 등의 수단으로 로그인 가능
|
|
* 향후 모바일 앱 지원으로 인증 Push 승인 등 MFA 확장 (예정)
|
|
* 정보변경, 앱 연동 이력 확인 등 개인화 기능
|
|
* 사용 가능한 앱 리스트 (예정)
|
|
* AdminFront: 사용자 관리 등 Admin 기능
|
|
* DevFront: RP 관리 등 개발자 기능
|
|
|
|
## 🏗 아키텍처 (Architecture)
|
|
|
|
### 0. Ory Stack
|
|
- Ory Kratos: 사용자 인증/계정 관리(Identity).
|
|
- Ory Hydra: OAuth2/OIDC 발급 및 토큰 관리.
|
|
- Ory Keto: 권한/정책 기반 접근 제어.
|
|
- Oathkeeper: 인증/인가 프록시 및 라우팅 게이트웨이.
|
|
|
|
```mermaid
|
|
flowchart
|
|
subgraph Edge
|
|
OK["Oathkeeper<br/>(Only Public Entry)"]
|
|
end
|
|
|
|
subgraph App
|
|
BE["Backend<br/>(Only Upstream)"]
|
|
end
|
|
|
|
subgraph OryStack
|
|
KR[Kratos]
|
|
HY[Hydra]
|
|
KE[Keto]
|
|
KR --- HY --- KE
|
|
end
|
|
BE -->|Command| OryStack
|
|
OK -->|Query| KR
|
|
OK -->|Query| HY
|
|
OK -->|Query| KE
|
|
```
|
|
|
|
### 1. Backend (Go Fiber)
|
|
- **Language**: Go 1.25+
|
|
- **Framework**: Fiber v2.25+
|
|
- **Database**:
|
|
- **ClickHouse**: 감사 로그 (고성능 데이터 수집)
|
|
- **PostgreSQL**: 메타데이터 저장소 (Primary)
|
|
- **Features**:
|
|
- 인증용 SMS 발송 등 Ory-Stack으로 구현 어려운 부분 직접 구현
|
|
- `POST /api/v1/audit`: 감사 로그 수집 API
|
|
- userfront가 바라보는 backend
|
|
|
|
### 2. UserFront(Flutter Web/App)
|
|
- **Framework**: Flutter 3.38.0+
|
|
- **Key Packages**: `flutter_riverpod`, `go_router`
|
|
- **Features**:
|
|
- 탭 기반 로그인 UI (비밀번호 기반 / 링크 기반 / QR 기반 등)
|
|
|
|
### 3. adminfront(Web)
|
|
- **Framework**: Vite, React 19+, Shadcn/ui 등
|
|
- **Features**:
|
|
- 사용자 관리, 권한 부여 등 관리자 기능
|
|
- 앱 별 사용량(호출량) 등 통계
|
|
- 핵심 Audit 대상
|
|
|
|
### 4. devfront(Web)
|
|
- **Framework**: Vite, React 19+, Shadcn/ui 등
|
|
- **Features**:
|
|
- RP 등록 및 관리
|
|
- RP별 Consent 관리
|
|
|
|
|
|
### 4. 주요 시나리오 (Core Scenarios)
|
|
1. **Same Browser SSO**: Baron 로그인 서비스에 로그인된 상태에서 런처를 통해 타 앱/서비스로 이동 (자동 로그인).
|
|
1.1. 단 약관동의(Consent) 이력이 없으면 Consent 단계로 이동
|
|
2. **Cross-Device Auth**: 이메일 SMS 등의 수단으로 링크를 전달받고 해당 링크를 사용자가 클릭하면 최초 로그인 요청한 세션이 활성화
|
|
2.1 향후 App Push 등 2차 인증 강화수단 검토 필요
|
|
3. **QR Login**: 최초 진입 시 사전 로그인되어 있는 웹/앱을 이용해 QR 코드를 스캔하여, QR코드가 로딩된 Device를 로그인 상태로 전환
|
|
|
|
|
|
### 전체 연결 구조도
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
subgraph Clients ["External Clients"]
|
|
AF[adminfront]
|
|
DF[devfront]
|
|
UF["userfront"]
|
|
DS["일반SW"]
|
|
end
|
|
|
|
subgraph AppService ["Control Plane"]
|
|
BE["Backend (Command/Audit Controller)"]
|
|
end
|
|
|
|
subgraph OryBundle ["Ory Deployment Stack"]
|
|
direction TB
|
|
OK["Oathkeeper (Public Proxy/OIDC)"]
|
|
|
|
subgraph OryEngines ["Ory Services"]
|
|
direction LR
|
|
HY["Hydra"]
|
|
KR["Kratos"]
|
|
KE["Keto"]
|
|
end
|
|
|
|
ICH[(Internal Clickhouse)]
|
|
|
|
%% Internal Flow within Bundle
|
|
OK -->|Routing/Queries| OryEngines
|
|
OK -.->|Access/Usage Log| ICH
|
|
end
|
|
|
|
subgraph AuditDB ["Audit Storage"]
|
|
ECH[(External Clickhouse)]
|
|
end
|
|
|
|
%% Key Command Path
|
|
AF & DF & UF & DS ==>|Actions / Commands| BE
|
|
|
|
%% Backend Responsibilities
|
|
BE -->|Admin/State Control| OryEngines
|
|
BE -.->|Mandatory Audit Log| ECH
|
|
|
|
%% Connection Note (Hidden flow mentioned in logic)
|
|
%% OK is technically the entry for OIDC, but removed as per request
|
|
|
|
%% Styles
|
|
style OryBundle fill:#f8f9fa,stroke:#333,stroke-width:2px
|
|
style BE fill:#bbf,stroke:#333,stroke-width:2px
|
|
style ECH fill:#fdd,stroke:#333
|
|
style ICH fill:#dfd,stroke:#333
|
|
style OK fill:#f9f,stroke:#333
|
|
style OryEngines fill:#fff,stroke:#999,stroke-dasharray: 5 5
|
|
```
|
|
|
|
|
|
Kratos가 사용자 SoT이며 Hydra는 순수 OIDC 토큰 엔진입니다. 비지니스로직은 Backend를 통해서, 기본 인증 로직은 Ory Stack을 통해 진행됩니다.
|
|
|
|
---
|
|
|
|
## 🚀 시작하기 (Getting Started)
|
|
|
|
### 사전 요구사항 (Prerequisites)
|
|
- Docker & Docker Compose
|
|
- Flutter SDK (로컬 개발용, 3.38.0+)
|
|
- Go (로컬 백엔드 개발용)
|
|
|
|
### 환경 설정 (Environment Setup)
|
|
1. 예제 환경 설정 파일을 복사합니다.
|
|
```bash
|
|
cp .env.sample .env
|
|
```
|
|
2. `.env`를 작성합니다. (아래 작성 규칙 필수)
|
|
|
|
### `.env` 작성 규칙 (중요)
|
|
- `KEY=value` 한 줄만 사용하고, **값 뒤에 같은 줄 주석을 붙이지 않습니다.**
|
|
- 주석이 필요하면 반드시 **윗줄에 별도 주석 라인**으로 작성합니다.
|
|
- URL 값 끝에 공백이 들어가면 Hydra/Kratos 기동 실패로 이어질 수 있습니다.
|
|
|
|
잘못된 예:
|
|
```env
|
|
USERFRONT_URL=https://sso.example.com # 이렇게 같은 줄 주석 금지
|
|
```
|
|
|
|
올바른 예:
|
|
```env
|
|
# UserFront 공개 URL
|
|
USERFRONT_URL=https://sso.example.com
|
|
```
|
|
|
|
### `.env` 핵심 변수 가이드
|
|
- `IDP_PROVIDER`: 기본 `ory`
|
|
- `USERFRONT_URL`: 브라우저 기준 공개 도메인 (예: `https://sso.example.com`)
|
|
- `OATHKEEPER_PUBLIC_URL`: 보통 `${USERFRONT_URL}`
|
|
- `HYDRA_PUBLIC_URL`: 보통 `${OATHKEEPER_PUBLIC_URL}/oidc`
|
|
- `KRATOS_BROWSER_URL`: 보통 `${OATHKEEPER_PUBLIC_URL}/auth`
|
|
- `KRATOS_UI_URL`: UserFront UI URL (로컬 예: `http://localhost:5000`)
|
|
- `ADMINFRONT_CALLBACK_URLS`: 콤마 구분 콜백 목록 (예: `http://localhost:5173/auth/callback`)
|
|
- `DEVFRONT_CALLBACK_URLS`: 콤마 구분 콜백 목록 (예: `http://localhost:5174/callback`)
|
|
- 주의: callback URL 끝에 `/`가 붙으면 `make validate-auth-config`에서 실패 처리됩니다.
|
|
- `KRATOS_ALLOWED_RETURN_URLS_EXTRA`: 추가 허용 return URL (선택)
|
|
- 빈값: `[]`
|
|
- 다중값: `["https://a.example.com/callback","https://b.example.com/callback"]` 또는 `https://a.example.com/callback,https://b.example.com/callback`
|
|
- `CLIENT_LOG_DEBUG`: 클라이언트 로그 디버그 모드 강제 (기본: 비운영 `true`, 운영 `false`)
|
|
- 운영(`APP_ENV=production|prod`)에서 `true|1|on|yes` 설정 시 `INFO/DEBUG` 클라이언트 로그 수집 허용
|
|
- 미설정(기본) 시 운영에서는 `WARN/ERROR`만 수집
|
|
- `USERFRONT_DEBUG_LOG`: UserFront 측 디버그 로그 fallback 플래그
|
|
- `CLIENT_LOG_DEBUG`가 없을 때만 UserFront에서 대체로 참조
|
|
|
|
### 클라이언트 로그 정책 (중요)
|
|
- 기본 원칙: 운영 환경에서는 민감정보 보호를 우선하며, 과도한 로그 수집을 제한합니다.
|
|
- 환경별 동작:
|
|
- 비운영(`dev/local/stage` 등): 디버그 로그 허용 (`INFO/DEBUG/WARN/ERROR`)
|
|
- 운영(`production/prod`) + `CLIENT_LOG_DEBUG` 미설정: `WARN/ERROR`만 수집
|
|
- 운영(`production/prod`) + `CLIENT_LOG_DEBUG=true`: 디버그 로그 허용
|
|
- 민감정보는 환경과 무관하게 마스킹합니다.
|
|
- 예: `password`, `newPassword`, `token`, `authorization`, `cookie`, `sessionJwt`
|
|
- 문자열 패턴(`token=...`, `authorization:...`, JSON body 내 민감 key)도 마스킹
|
|
- 상세 정책 문서: `docs/client-log-policy.md`
|
|
|
|
### `.env` 작성 후 권장 점검
|
|
```bash
|
|
make validate-auth-config
|
|
```
|
|
위 검증은 callback/allowed_return_urls/게이트웨이 매핑 규칙을 점검하고 `.generated/auth-config.env`를 생성합니다.
|
|
|
|
### 전체 스택 실행 (Running the Stack)
|
|
|
|
#### 1. 네트워크 생성 (최초 1회)
|
|
Ory Stack과 애플리케이션 간 통신을 위한 도커 네트워크를 생성합니다.
|
|
```bash
|
|
# ory-net은 bridge 모드로 생성
|
|
docker network create -d bridge ory-net
|
|
docker network create hydranet
|
|
docker network create kratosnet
|
|
docker network create public_net #서비스용
|
|
```
|
|
|
|
#### 2. 인프라 및 Ory Stack 실행
|
|
데이터베이스와 Ory 서비스(Kratos, Hydra, Keto 등)를 실행합니다.
|
|
```bash
|
|
# 권장: Make 실행 (인증 설정 검증 포함)
|
|
make up-dev
|
|
```
|
|
|
|
#### 3. 애플리케이션 실행
|
|
userfront와 backend 서비스를 실행합니다.
|
|
```bash
|
|
make up-app
|
|
```
|
|
(또는 전체 스택 한번에 실행: `make up-all`)
|
|
|
|
### Make 기반 인증 설정 검증 (권장)
|
|
`up-*` 타깃은 실행 전 인증 리다이렉트 설정을 자동 검증합니다.
|
|
|
|
```bash
|
|
# 1) 인증 설정 생성
|
|
make build-auth-config
|
|
|
|
# 2) 정적 검증 (callback / allowed_return_urls / 게이트웨이 매핑)
|
|
make validate-auth-config
|
|
|
|
# 3) 배선 + (가능 시) 런타임 Hydra client 검증
|
|
make verify-auth-config
|
|
```
|
|
|
|
- 생성 파일: `.generated/auth-config.env` (compose 실행 시 자동 주입)
|
|
- 게이트웨이 경유 환경은 URL 문자열 완전일치 대신 매핑 유효성(`direct_match` / `mapped_match`) 기준으로 검증합니다.
|
|
- 관련 정책 문서: `docs/oidc_redirect_mapping_validation_policy.md`
|
|
|
|
### 권장 실행 순서
|
|
```bash
|
|
cp .env.sample .env
|
|
# .env 편집
|
|
make validate-auth-config
|
|
make up-dev
|
|
make up-app
|
|
```
|
|
|
|
직접 Compose를 사용하려면 다음처럼 env 파일을 함께 주입하세요.
|
|
```bash
|
|
docker compose --env-file .env --env-file .generated/auth-config.env -f compose.infra.yaml -f compose.ory.yaml up -d
|
|
docker compose --env-file .env --env-file .generated/auth-config.env -f docker-compose.yaml up -d
|
|
```
|
|
|
|
- **gateway (UserFront 프록시)**: http://localhost:5000 접속
|
|
- **backend**: http://localhost:3000 (API)
|
|
- **ClickHouse**: http://localhost:8123
|
|
- **Kratos Public**: http://localhost:4433
|
|
- **Hydra Public**: http://localhost:4444
|
|
- **Kratos UI (UserFront)**: http://localhost:5000
|
|
|
|
### MCP 서버 (Hydra/Kratos/Keto)
|
|
MCP 서버는 기존 Hydra/Kratos에 연결하며 별도 Ory 스택이나 포트를 추가로 띄우지 않습니다.
|
|
프로덕션에서는 실행하지 않도록 `mcp` 프로파일을 로컬에서만 켜세요.
|
|
|
|
```bash
|
|
docker compose -f compose.ory.yaml --profile mcp up -d hydra-mcp-server kratos-mcp-server keto-mcp-server
|
|
```
|
|
|
|
- MCP 서버는 stdio 기반이라 외부 포트를 열지 않습니다.
|
|
- 최초 실행시거나 빌드된 이미지가 없으면 `docker compose -f mcp/compose.mcp.ory.yaml build' 후에 사용 가능합니다
|
|
|
|
```toml
|
|
[mcp_servers.kratos-mcp]
|
|
command = "docker"
|
|
args = ["compose", "-f", "mcp/compose.mcp.ory.yaml", "run", "--rm", "--no-deps", "kratos-mcp-server"]
|
|
|
|
[mcp_servers.kratos-mcp.env]
|
|
KRATOS_ADMIN_URL = "http://kratos:4434"
|
|
|
|
[mcp_servers.hydra-mcp]
|
|
command = "docker"
|
|
args = ["compose", "-f", "mcp/compose.mcp.ory.yaml", "run", "--rm", "--no-deps", "hydra-mcp-server"]
|
|
|
|
[mcp_servers.hydra-mcp.env]
|
|
HYDRA_PUBLIC_URL = "http://hydra:4444"
|
|
HYDRA_ADMIN_URL = "http://hydra:4445"
|
|
|
|
[mcp_servers.keto-mcp]
|
|
command = "docker"
|
|
args = ["compose", "-f", "mcp/compose.mcp.ory.yaml", "run", "--rm", "--no-deps", "keto-mcp-server"]
|
|
|
|
[mcp_servers.keto-mcp.env]
|
|
KETO_READ_URL = "http://keto:4466"
|
|
KETO_WRITE_URL = "http://keto:4467"
|
|
```
|
|
|
|
## 🌐 i18n 구조 (간략)
|
|
- **Source of Truth**: `locales/template.toml`이 전체 키의 기준이며 `locales/ko.toml`, `locales/en.toml`과 항상 동기화합니다.
|
|
- **React(Admin/Dev)**: `adminfront/src/lib/i18n.ts`, `devfront/src/lib/i18n.ts`에서 `t(key, fallback, vars)`로 사용하고 TOML을 `?raw`로 로드합니다.
|
|
- **Flutter(User)**: `userfront/lib/i18n.dart`에서 `tr(key, fallback, params)` 사용. `locales/*.toml`을 `tools/i18n-scanner/gen-flutter-i18n.js`로 `userfront/lib/i18n_data.dart`에 사전 생성합니다.
|
|
- **UserFront 동기화 규칙**: `locales/*.toml`을 수정한 뒤에는 반드시 `./scripts/sync_userfront_locales.sh`를 실행해 `userfront/assets/translations/*.toml`과 런타임 번역 리소스를 동기화합니다.
|
|
- **검증**: `node tools/i18n-scanner/index.js`로 코드-키-로케일 동기화 상태를 점검합니다.
|
|
|
|
## 🧪 Code Check CI
|
|
워크플로우 파일: `.gitea/workflows/code_check.yml`
|
|
|
|
### 트리거
|
|
- `push` (`dev` 브랜치)
|
|
- `pull_request` (`dev` 대상)
|
|
- `workflow_dispatch` (수동 실행)
|
|
|
|
### workflow_dispatch 입력값
|
|
- `run_lint`: Go/Flutter lint 실행 여부
|
|
- `run_backend_tests`: backend 테스트 실행 여부
|
|
- `run_userfront_tests`: userfront 테스트 실행 여부
|
|
- `run_userfront_e2e_tests`: userfront WASM Playwright E2E 실행 여부
|
|
- `run_adminfront_tests`: adminfront 테스트 실행 여부
|
|
- `run_devfront_tests`: devfront 테스트 실행 여부
|
|
|
|
### 실행 잡
|
|
- `lint`
|
|
- `backend-tests`
|
|
- `userfront-tests`
|
|
- `userfront-e2e-tests`
|
|
- `adminfront-tests`
|
|
- `devfront-tests`
|
|
|
|
### 프런트 테스트 브라우저 프리비저닝 정책
|
|
- `userfront-tests`
|
|
- `flutter test`(VM)만 실행
|
|
- `locale_storage` 정책 테스트는 엔진 단위로 통합되어 별도 브라우저 실행이 필요하지 않음
|
|
- `adminfront-tests`, `devfront-tests`
|
|
- Playwright 기반 테스트
|
|
- `npx playwright install --with-deps`로 브라우저/OS 의존성을 사전 설치
|
|
|
|
### 실패 보고서 확인 방법
|
|
테스트가 실패하면 다음이 자동 생성됩니다.
|
|
- Job Summary: 실패 원인 요약(Markdown) 즉시 확인
|
|
- Artifact: 상세 로그/리포트 다운로드
|
|
- `backend-test-failure-report`
|
|
- `userfront-test-failure-report`
|
|
- `adminfront-test-failure-report`
|
|
- `devfront-test-failure-report`
|
|
|
|
### userfront `locale_storage` 테스트 정책
|
|
- `locale_storage_platform_test.dart`는 `LocaleStorageEngine` 기반 정책 테스트로 통합되었습니다.
|
|
- 일반 `flutter test`(VM) 실행에 포함되며, 브라우저 전용 `kIsWeb` 케이스를 사용하지 않습니다.
|
|
- 단일 파일만 확인하려면 다음 명령을 사용합니다.
|
|
- `flutter test test/locale_storage_platform_test.dart`
|
|
|
|
### userfront WASM Playwright E2E
|
|
- 워크스페이스: `userfront-e2e/`
|
|
- 빌드+실행:
|
|
- `cd userfront-e2e && npm run test:wasm`
|
|
- 빌드 결과가 이미 있을 때:
|
|
- `cd userfront-e2e && npm test`
|
|
- Makefile 타깃:
|
|
- `make code-check-userfront-e2e-tests`
|
|
- 전수 인벤토리:
|
|
- `docs/test-plan/userfront-wasm-e2e-route-inventory.md`
|
|
|
|
### 로컬 개발 (Manual)
|
|
Docker 없이는 개발할 수 없지만 Backend 및 [user/admin/dev]Front 코드는 개발모드로 수정하며 개발가능.
|
|
백그라운드로 infra 및 ory stack이 구동중이라는 가정
|
|
|
|
**Backend:**
|
|
```bash
|
|
cd backend
|
|
go mod tidy
|
|
go run cmd/server/main.go
|
|
```
|
|
|
|
**userfront:**
|
|
```bash
|
|
cd userfront
|
|
flutter pub get
|
|
flutter run -d chrome
|
|
# 정책: 웹 빌드는 기본적으로 WASM 사용
|
|
flutter build web --wasm
|
|
```
|
|
|
|
**adminfront:**
|
|
```bash
|
|
cd adminfront
|
|
npm install
|
|
npm run dev
|
|
```
|
|
|
|
**devfront:**
|
|
```bash
|
|
cd devfront
|
|
npm install
|
|
npm run dev
|
|
```
|
|
|
|
---
|
|
|
|
## 📂 프로젝트 구조 (Project Structure)
|
|
|
|
```
|
|
baron_sso/
|
|
├── backend/ # Go Fiber 애플리케이션
|
|
│ ├── cmd/server/ # 진입점 (Entry point)
|
|
│ ├── internal/ # 도메인, 핸들러, 저장소(Repository)
|
|
│ └── Dockerfile
|
|
├── userfront/ # Flutter 애플리케이션
|
|
│ ├── src/ # UI 및 로직
|
|
│ └── pubspec.yaml
|
|
├── adminfront/ # React 기반 관리
|
|
│ ├── src/ # UI 및 로직
|
|
│ └── pubspec.yaml
|
|
├── gateway/ # Nginx 기반 Gateway (UserFront 프록시)
|
|
├── compose.ory-stack.yaml # DB 서비스 (Postgres, ClickHouse)
|
|
├── compose.infra.yaml # DB 서비스 (Postgres, ClickHouse)
|
|
├── docker-compose.yaml # 앱 서비스 (Front, Back)
|
|
├── .env.sample # 환경 설정 템플릿
|
|
└── README.md # 본 파일
|
|
```
|
|
|
|
## 📝 상태 및 로드맵 (Status & Roadmap)
|
|
- [x] **Phase 1**: 초기 설정 및 아키텍처 설계 (완료)
|
|
- [x] **Phase 2**: Backend Audit API 구현 (일부 완료)
|
|
- [ ] **Phase 3**: userfront 로그인 UI 인증 로직 (예정)
|
|
- [ ] **Phase 4**: adminfront 기능 추가 (예정)
|
|
- [ ] **Phase 5**: 대시보드 및 통합 런처 구현 (예정)
|