alt/docs/kis-live-secret-guide.md
toki cb8bdd3470 docs: add KIS Live secret guide and SOPS configuration
- Add .sops.yaml for SOPS encryption configuration
- Add kis-live-secret-guide.md with setup instructions
- Add kis-live-secret-handoff.md for secret handoff procedure
- Add secrets/kis.live.sops.yaml with encrypted credentials
- Update kis-live-data-collection-pipeline milestone document
2026-06-02 15:01:11 +09:00

6 KiB

KIS Live Secret Guide

이 문서는 KIS live smoke를 준비할 때 사용자가 어떤 값을 어디에 넣고, 에이전트에게 무엇만 알려주면 되는지 정리한다. secret 원문, 계좌번호, 비밀번호, Vaultwarden item 이름, vault 이름은 이 문서와 task/roadmap/log에 기록하지 않는다.

원칙

  • Vaultwarden은 원격 host의 code-server와 동레벨 container로 둔다.
  • sopsage는 원격 host에만 설치한다.
  • code-server container 안에는 age private key, 평문 secret 파일, KIS credential 원문을 두지 않는다.
  • KIS smoke는 원격 host wrapper가 sops exec-env로 필요한 환경변수만 주입해서 code-server container 안의 명령을 실행한다.
  • 원격 dev/test credential은 조회/smoke 최소 권한을 원칙으로 한다.
  • 주문, 잔고, 계좌 비밀번호는 KIS live data collection smoke 범위에 넣지 않는다.

사용자가 준비할 것

Vaultwarden에 KIS 관련 원본 secret을 직접 저장한다. 채팅이나 tracked 파일에 원문을 붙여넣지 않는다.

SOPS 암호화 파일에는 KIS live smoke에 필요한 값만 환경변수 이름으로 저장한다. 국내주식 일봉 조회 smoke의 기본 후보는 아래와 같다.

KIS_APP_KEY
KIS_APP_SECRET
KIS_BASE_URL
KIS_IS_PAPER

계좌번호나 계좌 상품코드는 일봉 시세 조회에 필요할 때만 별도 범위로 추가한다.

KIS_ACCOUNT_NO
KIS_ACCOUNT_PRODUCT

Vaultwarden에 원본 저장

원격 Vaultwarden은 공개 포트가 아니라 원격 host loopback에만 열린다. 먼저 SSH tunnel을 연다.

ssh -L 18088:127.0.0.1:18088 toki@192.168.0.97

브라우저에서 아래 주소로 접속한다.

http://127.0.0.1:18088

처음 사용하는 경우:

  1. Vaultwarden 계정을 만든다.
  2. KIS 원본 credential을 저장할 항목을 만든다.
  3. 항목 이름, vault 이름, 계좌번호, 비밀번호, app secret 원문은 이 repo 문서나 채팅에 쓰지 않는다.
  4. 첫 계정을 만든 뒤에는 원격 host의 Vaultwarden compose .env에서 SIGNUPS_ALLOWED=false로 바꾸고 Vaultwarden을 재시작한다.

KIS 항목에는 실제 원본 값을 사람이 알아볼 수 있게 저장한다. 예시는 항목 구성 방식만 보여주며 값은 쓰지 않는다.

KIS app key
KIS app secret
KIS base URL
KIS paper/live 구분

일봉 조회 smoke에 계좌 정보가 필요하지 않으면 계좌번호, 계좌 상품코드, 계좌 비밀번호, 주문 비밀번호는 넣지 않거나 별도 항목으로 분리한다.

SOPS 파일에 smoke용 env 저장

SOPS 파일은 에이전트와 테스트 명령이 읽을 수 있는 암호화된 env 파일이다. Vaultwarden은 원본 금고이고, SOPS 파일은 smoke 실행에 필요한 최소 값만 담는다.

원격 host에서 ALT repo로 이동한다.

cd /Users/toki/docker/services/code-server/data/volume/workspace/alt

아래 명령으로 암호화된 파일을 연다.

SOPS_AGE_KEY_FILE="$HOME/.config/sops/age/keys.txt" \
sops secrets/kis.live.sops.yaml

편집기가 열리면 아래 키들의 오른쪽 값을 채운다.

KIS_APP_KEY: "..."
KIS_APP_SECRET: "..."
KIS_BASE_URL: "..."
KIS_IS_PAPER: "true"

입력 기준:

  • KIS_APP_KEY: KIS에서 발급받은 app key
  • KIS_APP_SECRET: KIS에서 발급받은 app secret
  • KIS_BASE_URL: KIS 실전 또는 모의투자 API base URL
  • KIS_IS_PAPER: 모의투자면 "true", 실전이면 "false"

저장 후 종료하면 SOPS가 파일을 다시 암호화한다. 저장된 파일에서 실제 값이 ENC[...] 형태로 보이면 정상이다. 아직 값을 넣지 않은 빈 placeholder는 ""로 보일 수 있다. 실제 credential을 넣은 뒤에도 값이 평문으로 보이면 저장이 잘못된 것이다.

sed -n '1,80p' secrets/kis.live.sops.yaml

복호화 확인이 필요하면 원격 host에서만 아래 명령을 실행한다. 출력에는 secret 원문이 나오므로 화면 공유, 로그 저장, 채팅 복사를 하지 않는다.

SOPS_AGE_KEY_FILE="$HOME/.config/sops/age/keys.txt" \
sops --decrypt secrets/kis.live.sops.yaml

에이전트에게 알려줄 것

에이전트에게 secret 원문을 알려주지 않는다. 아래 메타 정보만 알려준다.

1. Vaultwarden에 KIS 항목을 만들었다.
2. SOPS 파일에 다음 env 이름으로 저장했다:
   - KIS_APP_KEY
   - KIS_APP_SECRET
   - KIS_BASE_URL
   - KIS_IS_PAPER
3. 첫 smoke 대상:
   - market: KR
   - symbol: 005930
   - date range: 20240501~20240531

실행 흐름

에이전트가 준비할 수 있는 항목:

  • .sops.yaml
  • secrets/kis.live.sops.yaml 템플릿
  • KIS smoke wrapper script
  • code-server container에 env만 주입하는 실행 명령

현재 repo에는 .sops.yaml과 암호화된 secrets/kis.live.sops.yaml 템플릿이 준비되어 있다. 현재 설정 요약과 다음 에이전트 handoff는 docs/kis-live-secret-handoff.md를 본다.

사용자는 원격 host에서 sops 편집기로 secret 값을 직접 입력한다.

SOPS_AGE_KEY_FILE="$HOME/.config/sops/age/keys.txt" \
sops secrets/kis.live.sops.yaml

KIS live smoke는 host-only age key를 사용해 실행한다.

SOPS_AGE_KEY_FILE="$HOME/.config/sops/age/keys.txt" \
sops exec-env secrets/kis.live.sops.yaml -- \
docker exec \
  -e KIS_APP_KEY \
  -e KIS_APP_SECRET \
  -e KIS_BASE_URL \
  -e KIS_IS_PAPER \
  code-server bash -lc 'cd /config/workspace/alt && bin/kis-live-smoke'

완료 조건

KIS live smoke가 완료되었다고 보려면 다음 evidence가 필요하다.

  • 실제 KIS 일봉 조회가 credential 준비 환경에서 실행되었다.
  • raw secret 없이 sanitized response 또는 요약 evidence가 남았다.
  • 실패 시 auth, quota, unavailable, malformed response 중 어떤 상태인지 grep 가능한 출력으로 남았다.
  • 수집된 normalized daily bars가 worker import/storage 경계를 통과했다.
  • 저장된 bars가 backtest 입력 조회 경계에서 사용 가능함을 확인했다.