📋 기획 및 설계: - PharmQ SaaS 서비스 기획서 작성 - 구독 서비스 라인업 정의 (클라우드PC, AI CCTV, CRM) - DB 스키마 설계 및 API 아키텍처 설계 🗄️ 데이터베이스 구조: - service_products: 서비스 상품 마스터 테이블 - pharmacy_subscriptions: 약국별 구독 현황 테이블 - subscription_usage_logs: 서비스 이용 로그 테이블 - billing_history: 결제 이력 테이블 - 샘플 데이터 자동 생성 (21개 구독, 월 118만원 매출) 🔧 백엔드 API 구현: - 구독 현황 통계 API (/api/subscriptions/stats) - 약국별 구독 조회 API (/api/pharmacies/subscriptions) - 구독 상세 정보 API (/api/pharmacy/{id}/subscriptions) - 구독 생성/해지 API (/api/subscriptions) 🖥️ 프론트엔드 UI 구현: - 대시보드 구독 현황 카드 (월 매출, 구독 수, 구독률 등) - 약국 목록에 구독 상태 아이콘 및 월 구독료 표시 - 약국 상세 페이지 구독 서비스 섹션 추가 - 실시간 구독 생성/해지 기능 구현 ✨ 주요 특징: - 서비스별 색상 코딩 및 이모지 아이콘 시스템 - 실시간 업데이트 (구독 생성/해지 즉시 반영) - 반응형 디자인 (모바일/태블릿 최적화) - 툴팁 기반 상세 정보 표시 📊 현재 구독 현황: - 총 월 매출: ₩1,180,000 - 구독 약국: 10/14개 (71.4%) - AI CCTV: 6개 약국, CRM: 10개 약국, 클라우드PC: 5개 약국 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
480 lines
14 KiB
Markdown
480 lines
14 KiB
Markdown
# 🔑 FARMQ Headscale Pre-auth Key 관리 가이드
|
|
|
|
## 📚 목차
|
|
1. [Pre-auth Key 개념](#pre-auth-key-개념)
|
|
2. [키 유형별 비교](#키-유형별-비교)
|
|
3. [약국 환경별 사용 전략](#약국-환경별-사용-전략)
|
|
4. [실제 명령어 예시](#실제-명령어-예시)
|
|
5. [보안 관리](#보안-관리)
|
|
6. [문제 해결](#문제-해결)
|
|
7. [체크리스트](#체크리스트)
|
|
|
|
---
|
|
|
|
## 🧠 Pre-auth Key 개념
|
|
|
|
### Pre-auth Key란?
|
|
- **사전 인증 키**: 클라이언트가 Headscale 서버에 자동 등록할 수 있는 "입장권"
|
|
- **일회용 패스워드** 개념으로, 관리자가 미리 생성해서 배포
|
|
- **보안 계층**: 무작위 접속을 방지하는 첫 번째 보안 장벽
|
|
|
|
### 작동 원리
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant Admin as 관리자
|
|
participant Server as Headscale 서버
|
|
participant Client as 클라이언트
|
|
|
|
Admin->>Server: 1. PreAuth 키 생성
|
|
Server-->>Admin: 2. 키 반환 (abc123def456...)
|
|
Admin->>Client: 3. 키 전달
|
|
Client->>Server: 4. 키와 함께 등록 요청
|
|
Server->>Server: 5. 키 검증
|
|
Server-->>Client: 6. 승인 및 VPN 설정 전송
|
|
Server->>Server: 7. 키 사용됨 표시 (일회용인 경우)
|
|
```
|
|
|
|
---
|
|
|
|
## 🔄 키 유형별 비교
|
|
|
|
### 1. 일회용 키 (Single-use Key)
|
|
```bash
|
|
# 생성 명령어
|
|
docker exec headscale headscale preauthkeys create --user [USER_ID] --expiration 1h
|
|
|
|
# 특징
|
|
✅ 최고 수준 보안
|
|
✅ 정확한 기기 추적 가능
|
|
❌ 매번 새 키 생성 필요
|
|
❌ 관리 복잡도 높음
|
|
```
|
|
|
|
### 2. 재사용 키 (Reusable Key)
|
|
```bash
|
|
# 생성 명령어
|
|
docker exec headscale headscale preauthkeys create --user [USER_ID] --expiration 7d --reusable
|
|
|
|
# 특징
|
|
✅ 편리한 관리
|
|
✅ 여러 기기에서 동일 키 사용
|
|
⚠️ 키 노출 시 보안 위험
|
|
⚠️ 기기별 구분 어려움
|
|
```
|
|
|
|
### 3. 임시 키 (Ephemeral Key)
|
|
```bash
|
|
# 생성 명령어
|
|
docker exec headscale headscale preauthkeys create --user [USER_ID] --expiration 30m --ephemeral
|
|
|
|
# 특징
|
|
✅ 일시적 접속용 최적
|
|
✅ 네트워크에서 자동 제거
|
|
❌ 영구 연결 불가
|
|
❌ 재시작 시 재등록 필요
|
|
```
|
|
|
|
---
|
|
|
|
## 🏥 약국 환경별 사용 전략
|
|
|
|
### 전략 1: 약국별 개별 키 (🌟 권장)
|
|
|
|
#### 적용 대상
|
|
- 정기적으로 운영되는 약국
|
|
- 여러 POS 단말기가 있는 매장
|
|
- 보안이 중요한 환경
|
|
|
|
#### 설정 예시
|
|
```bash
|
|
# 1단계: 약국별 사용자 생성
|
|
docker exec headscale headscale users create pharmacy-gangnam
|
|
docker exec headscale headscale users create pharmacy-hongdae
|
|
docker exec headscale headscale users create pharmacy-itaewon
|
|
|
|
# 2단계: 사용자 ID 확인
|
|
docker exec headscale headscale users list
|
|
# 출력:
|
|
# ID | Name
|
|
# 1 | myuser
|
|
# 2 | pharmacy-gangnam
|
|
# 3 | pharmacy-hongdae
|
|
# 4 | pharmacy-itaewon
|
|
|
|
# 3단계: 약국별 재사용 키 생성
|
|
docker exec headscale headscale preauthkeys create --user 2 --expiration 30d --reusable
|
|
# 강남약국용: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0
|
|
|
|
docker exec headscale headscale preauthkeys create --user 3 --expiration 30d --reusable
|
|
# 홍대약국용: z9y8x7w6v5u4t3s2r1q0p9o8n7m6l5k4j3i2h1g0f9e8d7c6b5a4z3y2x1w0
|
|
|
|
docker exec headscale headscale preauthkeys create --user 4 --expiration 30d --reusable
|
|
# 이태원약국용: m5n6o7p8q9r0s1t2u3v4w5x6y7z8a9b0c1d2e3f4g5h6i7j8k9l0m1n2o3p4
|
|
```
|
|
|
|
#### 장점
|
|
- ✅ **약국별 구분**: 네트워크에서 약국별로 명확히 구분
|
|
- ✅ **부분적 보안**: 한 약국의 키 노출이 다른 약국에 영향 없음
|
|
- ✅ **관리 용이**: 약국별로 키 갱신 및 관리 가능
|
|
- ✅ **확장성**: 새 약국 추가 시 독립적으로 관리
|
|
|
|
### 전략 2: 지역별 그룹 키
|
|
|
|
#### 적용 대상
|
|
- 같은 지역 내 여러 지점
|
|
- 관리 구역별 분할 필요 시
|
|
- 중간 규모 보안 요구사항
|
|
|
|
```bash
|
|
# 지역별 사용자 생성
|
|
docker exec headscale headscale users create region-seoul
|
|
docker exec headscale headscale users create region-busan
|
|
docker exec headscale headscale users create region-daegu
|
|
|
|
# 지역별 키 생성 (서울 지역 모든 약국이 공유)
|
|
docker exec headscale headscale preauthkeys create --user 2 --expiration 14d --reusable
|
|
```
|
|
|
|
### 전략 3: 단일 공통 키 (⚠️ 비권장)
|
|
|
|
#### 적용 대상
|
|
- 테스트 환경
|
|
- 매우 소규모 운영 (5개 미만 약국)
|
|
- 관리 리소스 극도로 제한적인 경우
|
|
|
|
```bash
|
|
# 모든 약국이 하나의 키 공유
|
|
docker exec headscale headscale preauthkeys create --user 1 --expiration 90d --reusable
|
|
```
|
|
|
|
#### 단점
|
|
- ❌ **보안 위험**: 키 하나만 노출되면 전체 네트워크 위험
|
|
- ❌ **관리 복잡**: 문제 발생 시 원인 추적 어려움
|
|
- ❌ **확장성 부족**: 규모 증가 시 관리 한계
|
|
|
|
---
|
|
|
|
## 💻 실제 명령어 예시
|
|
|
|
### FARMQ 표준 설정 (권장)
|
|
|
|
#### 1단계: 약국 등록 준비
|
|
```bash
|
|
# 새 약국 등록 시 실행할 명령어들
|
|
|
|
# 약국명 변수 설정 (편의를 위해)
|
|
PHARMACY_NAME="pharmacy-myeongdong"
|
|
EXPIRATION="30d" # 30일 만료
|
|
|
|
echo "🏥 새 약국 등록: $PHARMACY_NAME"
|
|
```
|
|
|
|
#### 2단계: 사용자 생성
|
|
```bash
|
|
# 사용자 생성
|
|
docker exec headscale headscale users create "$PHARMACY_NAME"
|
|
|
|
# 생성 결과 확인
|
|
docker exec headscale headscale users list
|
|
```
|
|
|
|
#### 3단계: 사용자 ID 확인
|
|
```bash
|
|
# 방법 1: 수동 확인
|
|
docker exec headscale headscale users list | grep "$PHARMACY_NAME"
|
|
|
|
# 방법 2: 자동 추출 (스크립트용)
|
|
USER_ID=$(docker exec headscale headscale users list | grep "$PHARMACY_NAME" | awk '{print $1}')
|
|
echo "사용자 ID: $USER_ID"
|
|
```
|
|
|
|
#### 4단계: Pre-auth 키 생성
|
|
```bash
|
|
# 재사용 가능한 키 생성
|
|
PREAUTH_KEY=$(docker exec headscale headscale preauthkeys create --user "$USER_ID" --expiration "$EXPIRATION" --reusable | tail -1)
|
|
|
|
echo "🔑 생성된 Pre-auth Key:"
|
|
echo "$PREAUTH_KEY"
|
|
```
|
|
|
|
#### 5단계: 클라이언트에서 사용
|
|
```bash
|
|
# 약국의 각 기기에서 실행
|
|
sudo tailscale up \
|
|
--login-server=http://192.168.0.151:8070 \
|
|
--authkey="$PREAUTH_KEY" \
|
|
--hostname=myeongdong-pos1 \
|
|
--accept-dns=false
|
|
|
|
sudo tailscale up \
|
|
--login-server=http://192.168.0.151:8070 \
|
|
--authkey="$PREAUTH_KEY" \
|
|
--hostname=myeongdong-pos2 \
|
|
--accept-dns=false
|
|
|
|
sudo tailscale up \
|
|
--login-server=http://192.168.0.151:8070 \
|
|
--authkey="$PREAUTH_KEY" \
|
|
--hostname=myeongdong-office \
|
|
--accept-dns=false
|
|
```
|
|
|
|
### 특수 상황별 명령어
|
|
|
|
#### 임시 접속 (매니저 노트북)
|
|
```bash
|
|
# 2시간 짜리 일회용 키
|
|
docker exec headscale headscale preauthkeys create --user "$USER_ID" --expiration 2h
|
|
|
|
# 일시적 접속 (재부팅 시 자동 해제)
|
|
docker exec headscale headscale preauthkeys create --user "$USER_ID" --expiration 1h --ephemeral
|
|
```
|
|
|
|
#### 기술 지원용 (원격 지원)
|
|
```bash
|
|
# 30분 짜리 ephemeral 키 (지원 완료 후 자동 삭제)
|
|
docker exec headscale headscale preauthkeys create --user "$USER_ID" --expiration 30m --ephemeral
|
|
```
|
|
|
|
#### 테스트용 (개발/검증)
|
|
```bash
|
|
# 테스트 사용자 및 짧은 만료시간
|
|
docker exec headscale headscale users create test-environment
|
|
docker exec headscale headscale preauthkeys create --user [TEST_USER_ID] --expiration 15m --reusable
|
|
```
|
|
|
|
---
|
|
|
|
## 🔐 보안 관리
|
|
|
|
### 키 생명주기 관리
|
|
|
|
#### 1. 키 생성 정책
|
|
```bash
|
|
# 권장 만료시간 설정
|
|
# - 일반 약국: 30일
|
|
# - 임시 접속: 2-8시간
|
|
# - 기술 지원: 30분-1시간
|
|
# - 테스트: 15분-1시간
|
|
|
|
# 예시: 단계별 만료시간
|
|
docker exec headscale headscale preauthkeys create --user 2 --expiration 30d --reusable # 운영
|
|
docker exec headscale headscale preauthkeys create --user 2 --expiration 4h # 임시
|
|
docker exec headscale headscale preauthkeys create --user 2 --expiration 30m --ephemeral # 지원
|
|
```
|
|
|
|
#### 2. 키 갱신 스케줄
|
|
```bash
|
|
# 월별 키 갱신 스크립트 (cron 등록 권장)
|
|
#!/bin/bash
|
|
# monthly-key-renewal.sh
|
|
|
|
PHARMACIES=("pharmacy-gangnam" "pharmacy-hongdae" "pharmacy-itaewon")
|
|
|
|
for pharmacy in "${PHARMACIES[@]}"; do
|
|
echo "🔄 갱신 중: $pharmacy"
|
|
|
|
# 기존 키 만료 처리 (수동)
|
|
echo "⚠️ 기존 키를 수동으로 비활성화하세요"
|
|
|
|
# 새 키 생성
|
|
USER_ID=$(docker exec headscale headscale users list | grep "$pharmacy" | awk '{print $1}')
|
|
NEW_KEY=$(docker exec headscale headscale preauthkeys create --user "$USER_ID" --expiration 30d --reusable | tail -1)
|
|
|
|
echo "🔑 $pharmacy 새 키: $NEW_KEY"
|
|
echo "📧 약국에 새 키 전달 필요"
|
|
done
|
|
```
|
|
|
|
#### 3. 키 모니터링
|
|
```bash
|
|
# 활성 키 확인
|
|
docker exec headscale headscale preauthkeys list --user [USER_ID]
|
|
|
|
# 만료 예정 키 확인 (스크립트화 권장)
|
|
docker exec headscale headscale preauthkeys list --user [USER_ID] | grep -E "(expires|expired)"
|
|
```
|
|
|
|
### 보안 사고 대응
|
|
|
|
#### 키 노출 시 대응 절차
|
|
```bash
|
|
# 1단계: 즉시 새 키 생성
|
|
EMERGENCY_KEY=$(docker exec headscale headscale preauthkeys create --user [USER_ID] --expiration 7d --reusable | tail -1)
|
|
|
|
# 2단계: 해당 약국에 긴급 연락
|
|
echo "🚨 긴급 키 교체 필요"
|
|
echo "새 키: $EMERGENCY_KEY"
|
|
|
|
# 3단계: 기존 키로 등록된 노드 확인
|
|
docker exec headscale headscale nodes list --user [USER_ID]
|
|
|
|
# 4단계: 의심스러운 노드 제거 (필요시)
|
|
# docker exec headscale headscale nodes delete [NODE_ID]
|
|
```
|
|
|
|
### 접근 제한 설정
|
|
|
|
#### 태그 기반 접근 제어 (고급)
|
|
```bash
|
|
# 약국별 태그 설정
|
|
docker exec headscale headscale preauthkeys create \
|
|
--user [USER_ID] \
|
|
--expiration 30d \
|
|
--reusable \
|
|
--tags "pharmacy:gangnam,role:pos"
|
|
|
|
# 지역별 접근 제한
|
|
docker exec headscale headscale preauthkeys create \
|
|
--user [USER_ID] \
|
|
--expiration 30d \
|
|
--reusable \
|
|
--tags "region:seoul,type:retail"
|
|
```
|
|
|
|
---
|
|
|
|
## 🔧 문제 해결
|
|
|
|
### 일반적인 문제들
|
|
|
|
#### 1. "invalid auth key" 오류
|
|
```bash
|
|
# 원인: 키 만료, 잘못된 키, 이미 사용된 일회용 키
|
|
# 진단:
|
|
docker exec headscale headscale preauthkeys list --user [USER_ID]
|
|
|
|
# 해결: 새 키 생성
|
|
docker exec headscale headscale preauthkeys create --user [USER_ID] --expiration 1h --reusable
|
|
```
|
|
|
|
#### 2. "user not found" 오류
|
|
```bash
|
|
# 원인: 존재하지 않는 사용자 ID
|
|
# 진단:
|
|
docker exec headscale headscale users list
|
|
|
|
# 해결: 사용자 생성
|
|
docker exec headscale headscale users create [USERNAME]
|
|
```
|
|
|
|
#### 3. "foreign key constraint" 오류
|
|
```bash
|
|
# 원인: 데이터베이스 무결성 문제 (FARMQ 확장 테이블과 충돌)
|
|
# 해결: 기존 사용자 사용 또는 데이터베이스 정리
|
|
docker exec headscale headscale users list # 기존 사용자 확인
|
|
# 기존 사용자 ID로 키 생성
|
|
```
|
|
|
|
### 디버깅 명령어
|
|
```bash
|
|
# 전체 키 목록 확인
|
|
docker exec headscale headscale preauthkeys list
|
|
|
|
# 특정 사용자의 키 목록
|
|
docker exec headscale headscale preauthkeys list --user [USER_ID]
|
|
|
|
# 노드 등록 상태 확인
|
|
docker exec headscale headscale nodes list
|
|
|
|
# 로그 확인
|
|
docker logs headscale | grep -i "preauth\|auth\|key"
|
|
```
|
|
|
|
---
|
|
|
|
## 📋 체크리스트
|
|
|
|
### 새 약국 등록 체크리스트
|
|
- [ ] 약국명 결정 (naming convention 준수)
|
|
- [ ] Headscale 사용자 생성
|
|
- [ ] 사용자 ID 확인
|
|
- [ ] 적절한 만료시간으로 Pre-auth 키 생성
|
|
- [ ] 키를 안전한 방법으로 약국에 전달
|
|
- [ ] 약국에서 클라이언트 등록 테스트
|
|
- [ ] 네트워크 연결 확인
|
|
- [ ] FARMQ 관리자 페이지에서 확인
|
|
|
|
### 정기 보안 점검 체크리스트
|
|
- [ ] 만료 예정 키 확인 (30일 전 알림)
|
|
- [ ] 사용되지 않는 키 정리
|
|
- [ ] 의심스러운 노드 연결 확인
|
|
- [ ] 키 사용 로그 검토
|
|
- [ ] 백업된 키 정보 업데이트
|
|
|
|
### 긴급 상황 대응 체크리스트
|
|
- [ ] 키 노출 확인 시 즉시 새 키 생성
|
|
- [ ] 해당 약국에 긴급 연락
|
|
- [ ] 의심스러운 노드 차단
|
|
- [ ] 사고 경위 문서화
|
|
- [ ] 재발 방지 대책 수립
|
|
|
|
---
|
|
|
|
## 📚 명령어 참조 카드
|
|
|
|
### 자주 사용하는 명령어
|
|
```bash
|
|
# === 사용자 관리 ===
|
|
docker exec headscale headscale users create [USERNAME]
|
|
docker exec headscale headscale users list
|
|
|
|
# === 키 생성 ===
|
|
# 일회용
|
|
docker exec headscale headscale preauthkeys create --user [USER_ID] --expiration 1h
|
|
|
|
# 재사용 (일반적)
|
|
docker exec headscale headscale preauthkeys create --user [USER_ID] --expiration 30d --reusable
|
|
|
|
# 임시 (ephemeral)
|
|
docker exec headscale headscale preauthkeys create --user [USER_ID] --expiration 30m --ephemeral
|
|
|
|
# === 키 관리 ===
|
|
docker exec headscale headscale preauthkeys list --user [USER_ID]
|
|
docker exec headscale headscale preauthkeys expire [KEY_ID]
|
|
|
|
# === 노드 관리 ===
|
|
docker exec headscale headscale nodes list
|
|
docker exec headscale headscale nodes list --user [USER_ID]
|
|
docker exec headscale headscale nodes delete [NODE_ID]
|
|
```
|
|
|
|
### 클라이언트 명령어
|
|
```bash
|
|
# 표준 등록
|
|
sudo tailscale up \
|
|
--login-server=http://192.168.0.151:8070 \
|
|
--authkey=[PREAUTH_KEY] \
|
|
--hostname=[HOSTNAME] \
|
|
--accept-dns=false
|
|
|
|
# 상태 확인
|
|
tailscale status
|
|
tailscale ip -4
|
|
|
|
# 연결 해제
|
|
sudo tailscale down
|
|
sudo tailscale logout
|
|
```
|
|
|
|
---
|
|
|
|
## 🎯 모범 사례 요약
|
|
|
|
### DO ✅
|
|
- **약국별 개별 키 사용**
|
|
- **적절한 만료시간 설정** (30일 권장)
|
|
- **정기적인 키 갱신**
|
|
- **키 전달 시 보안 채널 사용**
|
|
- **키 사용 로그 모니터링**
|
|
|
|
### DON'T ❌
|
|
- **모든 약국이 하나의 키 공유하지 않기**
|
|
- **만료시간 너무 길게 설정하지 않기** (90일 이상)
|
|
- **키를 평문으로 이메일 전송하지 않기**
|
|
- **만료된 키 방치하지 않기**
|
|
- **키 백업 없이 운영하지 않기**
|
|
|
|
---
|
|
|
|
**🎊 체계적인 키 관리로 안전한 FARMQ 네트워크를 운영하세요!** |