본문으로 건너뛰기

시크릿 회전

운영 중 시크릿을 회전(rotate)할 때 따라야 할 절차와, 각 시크릿이 회전되었을 때 시스템 컴포넌트에 미치는 영향 범위를 정리합니다. 본 페이지는 회전 영향의 단일 출처입니다 — 다른 모든 페이지는 본 페이지로 링크만 합니다.

이 문서는 코드 레포의 docs/operations/secrets.mddocs/operations/secret_rotation.md 두 파일을 흡수했습니다. 원본은 개발자용 백업으로 그대로 유지됩니다.

TL;DR — 회전 영향 매트릭스

시크릿영향 범위사용자 영향회전 후 필수 조치
ENCRYPTION_SALTserver/auth/crypto.py Fernet 키 파생. 모든 거래소(CCXT/Alpaca/KIS) API 키 + KIS 계좌번호가 동일 SALT로 암복호화전체 사용자 거래 중단. 기존 암호 컬럼 일괄 복호화 불가1) 사용자 일괄 알림 → 2) 거래소 키 재등록 강제(UI gate) → 3) 자동 거래 일시 중단
AUTH_SECRET_KEYJWT 서명 키 (server/auth/jwt.py)발급된 모든 JWT 무효 → 전 사용자 재로그인1) 클라이언트 캐시 무효화 안내 → 2) 401 응답 시 자동 로그아웃 동작 확인
LIVE_CONFIRM_SECRETpaper→live 승급 confirm token HMAC. 빈값이면 AUTH_SECRET_KEY로 폴백진행 중인 confirm 이메일 모두 무효1) 사용자에게 재발급 안내 → 2) 회전 24h 윈도
DB_PASSWORD (TimescaleDB)DATABASE_URL 패스워드 부분회전 자체는 데이터 무영향. 컨테이너 재시작 필요1) Postgres ALTER USER → 2) .env 갱신 → 3) compose up -d
OPENAI_API_KEY (LiteLLM master)analysis-worker가 LLM 호출 시 사용분석 보고서 신규 생성 즉시 401. 거래는 무영향LiteLLM proxy 키 갱신 → analysis-worker만 재시작 (compose restart analysis-worker)
ALPACA_API_KEY / _SECRET_KEY사용자 단위 페이퍼/실거래 라우팅. 개별 사용자 키는 DB의 암호화 컬럼. 환경변수는 폴백/시스템 키만환경변수 회전 → 시스템 키 사용 작업만 영향. 개별 사용자 키 회전은 DB 갱신UI에서 사용자가 신규 등록 → 자동 재연결
KIS_APP_KEY / _APP_SECRET / _ACCOUNT_NO위와 동일. 추가로 KIS는 토큰 캐시 사용 → 회전 시 토큰 재발급 필요진행 중 주문 reconcile에서 일시 실패 가능UI에서 재등록 → reconciler 다음 패스에서 자동 복구
TELEGRAM_TOKEN / TELEGRAM_CHAT_ID알림 발송알림만 영향. 거래/리스크 무영향.env 갱신 → compose restart api analysis-worker position-reconciler
DART_API_KEY / FRED_API_KEY매크로/공시 데이터 폴백LLM 분석 품질 저하. 거래 무영향.env 갱신 → analysis-worker 재시작
GRAFANA_WEBHOOK_SECRETGrafana → API 알림 브리지 인증알림만 영향Grafana / API 양쪽 동시 갱신
RECAPTCHA_SECRET_KEY라이브 승급 사용자 검증비어 있으면 검증 스킵 (개발용). 운영에서 필수UI 환경변수 동시 갱신

회전 절차 (공통)

  1. 새 값 발급 — 비밀 저장소(Azure Key Vault / GitHub Encrypted Secrets)에 신규 값 추가.
  2. 그레이스 윈도우 — 가능하면 구 값 회수 전 24h 유예.
  3. VM .env 갱신~/quantai/.env 수정. chmod 600 .env 유지.
  4. 영향 서비스 재시작 — 위 매트릭스의 "회전 후 필수 조치" 컬럼 참조.
  5. 검증infra/healthcheck.sh 실행 + 사용자 표본(1~3명) 거래 흐름 확인.
  6. 사후 알림 — 사용자 영향이 있는 항목(SALT/AUTH_SECRET)은 Telegram + 이메일.

ENCRYPTION_SALT 회전 (위험도: 최상)

거래소 키 일괄 무효화

ENCRYPTION_SALT를 회전하면 DB에 저장된 모든 거래소 API 키, KIS 계좌번호 등 암호화 컬럼이 즉시 복호화 불가 상태가 됩니다. 정상 절차는 다음과 같습니다.

  1. 사전 공지 — 최소 48h 전 사용자 공지 (UI 배너 + Telegram).

  2. 유지보수 모드 진입:

    # API에 503을 반환하는 nginx maintenance 페이지로 라우팅
    ssh azureuser@<vm-ip> 'sudo nginx -s reload -c /etc/nginx/maintenance.conf'
  3. 데이터 백업:

    ssh azureuser@<vm-ip> \
    'cd ~/quantai && sudo -E docker compose -f docker-compose.prod.yml exec -T \
    timescaledb pg_dump -U quant quantai | gzip' \
    > ~/backup-pre-salt-rotation-$(date -u +%Y%m%dT%H%M%SZ).sql.gz
  4. .env 갱신ENCRYPTION_SALT 새 값으로 변경.

  5. 암호 컬럼 정리 마이그레이션exchange_keys, equity_account_credentials, 기타 암호 컬럼을 NULL로 초기화하고 is_active=false로 표기. (마이그레이션 스크립트는 alembic/versions/<rev>_clear_encrypted_after_salt_rotation.py 형태로 회전 시 1회용으로 작성.)

  6. 재시작:

    bash scripts/rolling_restart.sh
  7. 재등록 안내 — 사용자 로그인 시 "거래소 API 키를 재등록해주세요" UI 강제.

  8. 자동 거래 비활성FEATURE_EQUITY_LIVE를 임시로 false 처리. 사용자가 신규 키 등록을 마치면 자동 재활성화.

AUTH_SECRET_KEY 회전 (위험도: 중)

JWT 서명 키 회전은 DB 영향이 없습니다. 회전 즉시 모든 활성 세션이 무효화됩니다.

# 1. .env에서 AUTH_SECRET_KEY 새 값
# 2. api 컨테이너만 재시작
docker compose restart api
  1. 프론트엔드는 401 응답 시 자동 로그아웃이므로, 사용자는 다음 요청 시 로그인 화면으로 이동.
  2. WebSocket 연결은 끊긴 후 클라이언트가 재연결 시 새 토큰 사용.
LIVE_CONFIRM_SECRET 폴백

LIVE_CONFIRM_SECRET이 빈값이면 AUTH_SECRET_KEY로 폴백하므로, AUTH_SECRET_KEY 회전 시 발급된 모든 paper→live confirm token도 무효 됩니다. 사용자가 confirm 이메일 미사용 상태라면 재발급 안내.

DB_PASSWORD 회전 (위험도: 하)

# 1. Postgres에서 패스워드 변경
docker compose exec timescaledb psql -U quant -d quantai \
-c "ALTER USER quant WITH PASSWORD 'new-strong-password';"

# 2. .env 갱신
sed -i 's/^DB_PASSWORD=.*/DB_PASSWORD=new-strong-password/' .env

# 3. 재시작 (api / 워커 / Grafana 모두 재기동 필요 — Grafana도 같은 패스워드 사용)
docker compose -f docker-compose.prod.yml up -d

검증: docker compose exec api alembic current이 정상 응답.

OPENAI_API_KEY 회전 (위험도: 하)

# 1. LiteLLM proxy 측에서 새 master_key 발급
# 2. .env의 OPENAI_API_KEY 갱신
# 3. analysis-worker만 재시작
docker compose restart analysis-worker

거래 / 페이퍼 모드는 영향 없음. 분석 큐 적재된 작업이 잠시 401로 실패할 수 있으나 retry로 자동 회복.

자동화 — scripts/deploy_azure.sh와의 관계

배포 스크립트는 시크릿을 직접 회전하지 않습니다. 다만:

  • 배포 시 VM의 .env는 그대로 둠 (이미 회전된 값 보존).
  • deploy_azure.sh --rollback은 이미지만 되돌리고 시크릿은 건드리지 않음.
  • 회전 도중 배포가 발생하면 새 컨테이너가 새 시크릿을 즉시 picks up — 중간 상태 최소화를 위해 회전과 배포를 동시에 수행하지 않음 (Change Window 분리).

사후 검증 체크리스트

  • infra/healthcheck.sh 모든 항목 OK
  • analysis-worker 로그에서 401/403 없음
  • position-reconciler 한 사이클 정상 (broker_order_events에 신규 audit 행)
  • 표본 사용자 1~3명: 로그인 → 대시보드 로딩 → 페이퍼 주문 1건
  • Telegram 알림 채널에 회전 완료 메시지 수신

관련 페이지