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
This commit is contained in:
parent
e5aae4c20f
commit
cb8bdd3470
5 changed files with 259 additions and 0 deletions
3
.sops.yaml
Normal file
3
.sops.yaml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
creation_rules:
|
||||||
|
- path_regex: ^secrets/kis\.live\.sops\.yaml$
|
||||||
|
age: age1fwqdkmqh3ykq7cnchcrr5nfwr77qsdt4p79lpa49g6q5k88cluvqkfw8d3
|
||||||
|
|
@ -72,6 +72,8 @@ fixture/mock 기반 adapter를 실제 KIS provider 호출과 worker import pipel
|
||||||
- 표준선(선택): 기존 provider-neutral importer/storage/backtest 입력 경계를 유지하고, KIS 특수성은 provider adapter와 runtime config에 격리한다.
|
- 표준선(선택): 기존 provider-neutral importer/storage/backtest 입력 경계를 유지하고, KIS 특수성은 provider adapter와 runtime config에 격리한다.
|
||||||
- 표준선(선택): KIS 공식 샘플은 tracked source dependency가 아니라 local cache 참조로 사용한다. private rule의 `.agent-cache/koreainvestment/open-trading-api` 경계를 따른다.
|
- 표준선(선택): KIS 공식 샘플은 tracked source dependency가 아니라 local cache 참조로 사용한다. private rule의 `.agent-cache/koreainvestment/open-trading-api` 경계를 따른다.
|
||||||
- 표준선(선택): live smoke는 credential이 준비된 환경에서만 실행하며, credential 미설정 상태는 실패가 아니라 `unavailable` evidence로 남긴다.
|
- 표준선(선택): live smoke는 credential이 준비된 환경에서만 실행하며, credential 미설정 상태는 실패가 아니라 `unavailable` evidence로 남긴다.
|
||||||
|
- 표준선(선택): 원격 field secret boundary는 Vaultwarden container와 host-only `sops`/`age`로 둔다. code-server 컨테이너에는 age private key나 평문 secret 파일을 두지 않고, host wrapper가 `sops exec-env`로 필요한 환경변수만 주입해 smoke를 실행한다.
|
||||||
|
- 표준선(선택): Vaultwarden 접속 경로, host 경로, age key 위치 같은 환경 세부는 private testing rule에만 두고 tracked roadmap에는 raw secret, 계좌번호, item/vault 이름을 기록하지 않는다.
|
||||||
- 선행 작업: Korea Daily Data Foundation, Backtest Engine Baseline, Operator Client API/Core Integration Validation
|
- 선행 작업: Korea Daily Data Foundation, Backtest Engine Baseline, Operator Client API/Core Integration Validation
|
||||||
- 후속 작업: Flutter Operator Console MVP
|
- 후속 작업: Flutter Operator Console MVP
|
||||||
- 확인 필요:
|
- 확인 필요:
|
||||||
|
|
|
||||||
169
docs/kis-live-secret-guide.md
Normal file
169
docs/kis-live-secret-guide.md
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
# KIS Live Secret Guide
|
||||||
|
|
||||||
|
이 문서는 KIS live smoke를 준비할 때 사용자가 어떤 값을 어디에 넣고, 에이전트에게 무엇만 알려주면 되는지 정리한다. secret 원문, 계좌번호, 비밀번호, Vaultwarden item 이름, vault 이름은 이 문서와 task/roadmap/log에 기록하지 않는다.
|
||||||
|
|
||||||
|
## 원칙
|
||||||
|
|
||||||
|
- Vaultwarden은 원격 host의 code-server와 동레벨 container로 둔다.
|
||||||
|
- `sops`와 `age`는 원격 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의 기본 후보는 아래와 같다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
KIS_APP_KEY
|
||||||
|
KIS_APP_SECRET
|
||||||
|
KIS_BASE_URL
|
||||||
|
KIS_IS_PAPER
|
||||||
|
```
|
||||||
|
|
||||||
|
계좌번호나 계좌 상품코드는 일봉 시세 조회에 필요할 때만 별도 범위로 추가한다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
KIS_ACCOUNT_NO
|
||||||
|
KIS_ACCOUNT_PRODUCT
|
||||||
|
```
|
||||||
|
|
||||||
|
## Vaultwarden에 원본 저장
|
||||||
|
|
||||||
|
원격 Vaultwarden은 공개 포트가 아니라 원격 host loopback에만 열린다. 먼저 SSH tunnel을 연다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh -L 18088:127.0.0.1:18088 toki@192.168.0.97
|
||||||
|
```
|
||||||
|
|
||||||
|
브라우저에서 아래 주소로 접속한다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
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 항목에는 실제 원본 값을 사람이 알아볼 수 있게 저장한다. 예시는 항목 구성 방식만 보여주며 값은 쓰지 않는다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
KIS app key
|
||||||
|
KIS app secret
|
||||||
|
KIS base URL
|
||||||
|
KIS paper/live 구분
|
||||||
|
```
|
||||||
|
|
||||||
|
일봉 조회 smoke에 계좌 정보가 필요하지 않으면 계좌번호, 계좌 상품코드, 계좌 비밀번호, 주문 비밀번호는 넣지 않거나 별도 항목으로 분리한다.
|
||||||
|
|
||||||
|
## SOPS 파일에 smoke용 env 저장
|
||||||
|
|
||||||
|
SOPS 파일은 에이전트와 테스트 명령이 읽을 수 있는 암호화된 env 파일이다. Vaultwarden은 원본 금고이고, SOPS 파일은 smoke 실행에 필요한 최소 값만 담는다.
|
||||||
|
|
||||||
|
원격 host에서 ALT repo로 이동한다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /Users/toki/docker/services/code-server/data/volume/workspace/alt
|
||||||
|
```
|
||||||
|
|
||||||
|
아래 명령으로 암호화된 파일을 연다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
SOPS_AGE_KEY_FILE="$HOME/.config/sops/age/keys.txt" \
|
||||||
|
sops secrets/kis.live.sops.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
편집기가 열리면 아래 키들의 오른쪽 값을 채운다.
|
||||||
|
|
||||||
|
```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을 넣은 뒤에도 값이 평문으로 보이면 저장이 잘못된 것이다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sed -n '1,80p' secrets/kis.live.sops.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
복호화 확인이 필요하면 원격 host에서만 아래 명령을 실행한다. 출력에는 secret 원문이 나오므로 화면 공유, 로그 저장, 채팅 복사를 하지 않는다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
SOPS_AGE_KEY_FILE="$HOME/.config/sops/age/keys.txt" \
|
||||||
|
sops --decrypt secrets/kis.live.sops.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## 에이전트에게 알려줄 것
|
||||||
|
|
||||||
|
에이전트에게 secret 원문을 알려주지 않는다. 아래 메타 정보만 알려준다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
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 값을 직접 입력한다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
SOPS_AGE_KEY_FILE="$HOME/.config/sops/age/keys.txt" \
|
||||||
|
sops secrets/kis.live.sops.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
KIS live smoke는 host-only age key를 사용해 실행한다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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 입력 조회 경계에서 사용 가능함을 확인했다.
|
||||||
66
docs/kis-live-secret-handoff.md
Normal file
66
docs/kis-live-secret-handoff.md
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
# KIS Live Secret Handoff
|
||||||
|
|
||||||
|
## Current Setup
|
||||||
|
|
||||||
|
- Remote field host owns the secret boundary.
|
||||||
|
- Vaultwarden runs outside the code-server container as a sibling container.
|
||||||
|
- `sops` and `age` are installed on the remote host only.
|
||||||
|
- The remote host age recipient for KIS live smoke is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
age1fwqdkmqh3ykq7cnchcrr5nfwr77qsdt4p79lpa49g6q5k88cluvqkfw8d3
|
||||||
|
```
|
||||||
|
|
||||||
|
## Repo Files
|
||||||
|
|
||||||
|
- `.sops.yaml`: SOPS rule for `secrets/kis.live.sops.yaml`.
|
||||||
|
- `secrets/kis.live.sops.yaml`: encrypted KIS live smoke env template.
|
||||||
|
- `docs/kis-live-secret-guide.md`: user-facing guide for how to fill and use the secret.
|
||||||
|
|
||||||
|
## User Fill-In
|
||||||
|
|
||||||
|
Do not paste secret values into chat, roadmap, docs, task logs, or command output.
|
||||||
|
|
||||||
|
Open the Vaultwarden SSH tunnel from the local machine:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh -L 18088:127.0.0.1:18088 toki@192.168.0.97
|
||||||
|
```
|
||||||
|
|
||||||
|
Then open Vaultwarden in the browser:
|
||||||
|
|
||||||
|
```text
|
||||||
|
http://127.0.0.1:18088
|
||||||
|
```
|
||||||
|
|
||||||
|
On the remote host, edit the encrypted file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
Fill only the env names required for first KIS daily-bar smoke:
|
||||||
|
|
||||||
|
```text
|
||||||
|
KIS_APP_KEY
|
||||||
|
KIS_APP_SECRET
|
||||||
|
KIS_BASE_URL
|
||||||
|
KIS_IS_PAPER
|
||||||
|
```
|
||||||
|
|
||||||
|
Account number, account product, account password, order password, balance, and order scopes are not part of the first daily-bar smoke unless a later task explicitly expands the scope.
|
||||||
|
|
||||||
|
## Agent Handoff
|
||||||
|
|
||||||
|
After the user fills the encrypted file, tell the agent only:
|
||||||
|
|
||||||
|
```text
|
||||||
|
SOPS file is filled.
|
||||||
|
First smoke target:
|
||||||
|
- market: KR
|
||||||
|
- symbol: 005930
|
||||||
|
- date range: <YYYYMMDD>~<YYYYMMDD>
|
||||||
|
```
|
||||||
|
|
||||||
|
The agent should then implement or run a host-wrapper flow that decrypts on the remote host and passes env vars into the code-server container only for the command lifetime.
|
||||||
19
secrets/kis.live.sops.yaml
Normal file
19
secrets/kis.live.sops.yaml
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
KIS_APP_KEY: ""
|
||||||
|
KIS_APP_SECRET: ""
|
||||||
|
KIS_BASE_URL: ""
|
||||||
|
KIS_IS_PAPER: ENC[AES256_GCM,data:BqMakQ==,iv:AJEP2eaQeYSQfWP8BhfcDR946tSQHUT6EPWV8EE4Txc=,tag:nsjz0h9Eh2H2/lru3qwmyQ==,type:str]
|
||||||
|
sops:
|
||||||
|
age:
|
||||||
|
- enc: |
|
||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA5cVJCUlNwcHcrN2lOM1g3
|
||||||
|
U2NHL3VMdkhnQ1V6Y3NlNFdGOW5HdTlnZFdvCmtyREUySFp0VXFHUk5tQmE0L1Yz
|
||||||
|
VTBXQUFoWWRmSDQyYlE2QTVtRzk1R3cKLS0tIDNTS3ljYjI0OFZVeWJhb1ZuTUNQ
|
||||||
|
U2c4Z0tRNHFSVkVja2dMZnBtM3pQeEEKJbdpCZ3XAWQaRqe3GbqsdIXDEjjEuLkT
|
||||||
|
HQUSiPEpFJcj8nunztDM6YQZS/QDJLNv2nWOxuts5AHoWaQEVAKkCw==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
recipient: age1fwqdkmqh3ykq7cnchcrr5nfwr77qsdt4p79lpa49g6q5k88cluvqkfw8d3
|
||||||
|
lastmodified: "2026-06-02T05:31:11Z"
|
||||||
|
mac: ENC[AES256_GCM,data:QSdh4ZoAE97c9TzQoe1baZefZ5Rk2vaRw97lKnR2h/iMRjTYbHgkP75Werd8T5oDH20q1o4IkjmOjyEk1XpHDZ9HThKsYmMI3xDFh/64Gz6rW8oCs8dEKW+j7AZ11DleGDkWHu4bIXk5HEeP2GNb7WJufpeIad0Ci3SyBGfJ+aA=,iv:5/BretO0xOrJ4o3jSSRlH0tIccM2wxaYg2TgiXj+gFk=,tag:8hxUFjbL/Q1UN74k1upYgQ==,type:str]
|
||||||
|
unencrypted_suffix: _unencrypted
|
||||||
|
version: 3.13.1
|
||||||
Loading…
Reference in a new issue