iop/agent-ops/skills/project/openai-usage-token-issue/SKILL.md

15 KiB

name version description
openai-usage-token-issue 1.0.6 OpenAI-compatible 사용자 추가와 usage metering용 IOP token을 발급하고 private Edge mapping, local secret store, 사용자가 승인한 Confluence metadata table을 동기화하는 운영 절차

openai-usage-token-issue

목적

OpenAI-compatible 사용량 metering에 쓸 IOP bearer token을 발급하고, raw token 없이 token_ref, token hash, principal_ref, 내부 alias 매핑만 운영 기록에 남긴다. IOP는 사용자/테넌트 source of truth를 소유하지 않고, 외부 principal id 또는 내부 운영 id를 참조값으로만 다룬다. 이 스킬은 dev-corp에서 사용자 추가와 token 발급을 함께 요청받았을 때의 단일 진입점이다.

언제 호출할지

  • OpenAI-compatible 호출 사용량을 특정 principal_ref 또는 내부 alias로 귀속할 IOP token을 새로 발급할 때
  • dev/dev-corp 운영자가 Grafana 사용량 label에 노출될 token_ref, principal_alias를 준비할 때
  • raw bearer token을 tracked 파일이나 최종 보고에 남기지 않고 1회 전달해야 할 때
  • dev-corp 사용자 추가와 함께 해당 사용자의 IOP token 발급·private Edge mapping 반영을 요청받았을 때

입력

  • operation: 사용자 추가와 함께 발급할 때는 create를 사용한다. token만 추가하거나 회전할 때는 작업 의도를 명시한다. (기본: create)
  • env: 대상 환경. 사용자 추가 발급 기본값은 dev-corp이다. (기본: dev-corp)
  • principal_ref: 외부 사용자/테넌트 프로젝트 또는 운영 시스템의 principal 참조값 (필수)
  • principal_alias: Grafana에 노출할 내부 alias. 없으면 principal_ref에서 secret이 아닌 짧은 별칭을 정한다. (선택)
  • token_ref: metric label과 설정에 쓸 안정 token 참조값. 한 principal_ref가 여러 앱/통합을 운영하면 앱/통합/용도별로 서로 다른 token_ref를 발급한다. 없으면 token hash prefix로 만든다. (선택)
  • output_path: raw token을 보관해야 한다면 이 프로젝트 repo root의 gitignored token/.dev-corp-iop-token을 사용한다. 이 파일 외의 운영 기록은 raw token 없이 남긴다. (선택)

이 프로젝트의 local secret store

  • token/.dev-corp-iop-token은 repo root의 operator-local 파일이며, 한 줄에 <private-user-key>: <raw-token>을 기록한다. 기본 private-user-key는 요청자가 지정한 식별자다.
  • 발급 전에 .gitignore에 정확한 /token/ 항목이 있는지 확인하고, 없으면 token directory 경로만 추가한다. raw token이나 사용자 값 자체를 .gitignore에 쓰지 않는다.
  • 파일은 umask 077으로 만들거나 유지해 mode 0600이어야 한다. 기존 기록을 보존하기 위해 token/ 안의 후보 파일을 만든 뒤 검증하고 원자적으로 교체한다.
  • 요청자가 이메일을 private-user-key 또는 dev-corp principal_ref로 명시하면, 그 이메일은 이 ignored local store와 private Edge 설정에만 둔다. tracked 파일, 스킬 예시, 최종 보고에는 실제 이메일을 쓰지 않는다.

승인된 Confluence metadata table 동기화

  • 사용자가 사용자별 발급 현황을 특정 Confluence path에 표로 동기화하라고 명시했을 때만 target URL을 ignored operator-local 파일 token/.dev-corp-iop-confluence-target에 한 줄로 보관한다. 이 파일도 mode 0600, ignored, untracked여야 하며, tracked 스킬·문서·최종 보고에는 draft share URL 또는 식별자를 쓰지 않는다.
  • Confluence 갱신 전에는 local secret store의 private-user-key 집합과 active openai.principal_tokens[]principal_ref 집합을 1:1로 대조한다. local store에 없는 service/smoke principal은 표에서 제외하며, 불일치 또는 중복이면 표를 쓰지 않고 불일치를 보고한다.
  • 표의 source of truth는 local secret store의 private-user-key와 active Edge의 principal_ref, principal_alias, token_ref, 활성 상태다. 표는 사용자, principal alias, token ref, 상태, 동기화 시각 열만 사용하고 행은 principal_ref로 upsert한다. raw token, token hash, Authorization 값, provider credential은 storage body와 API payload에 넣지 않는다.
  • 실제 갱신은 lgucorp-confluence-docs 스킬의 sync-token-metadata-table 절차를 따른다. HTTP Basic 인증과 table JSON payload는 stdin 또는 동등한 비노출 stream으로 전달하며 raw token을 shell 인자 또는 payload에 넣지 않는다.
  • target draft/page는 id, title, status, version, parent, storage body를 먼저 읽는다. body가 비어 있으면 관리 섹션과 표를 쓰고, 비어 있지 않은 body는 IOP 사용자 토큰 발급 현황 관리 섹션만 교체한다.
  • Confluence write 뒤에는 같은 content id를 다시 읽어 title·status·version·parent와 metadata 행 수·사용자/alias/ref/status 값을 active mapping과 내부 비교한다. 인증·권한·version conflict·재조회 실패 시 raw token store나 Edge mapping을 변경하거나 write를 자동 재시도하지 않는다.

사용자 추가(create) 기준

  • 요청자가 이메일을 명시하면 그 값은 private-user-key와 dev-corp principal_ref로만 사용한다. tracked 문서·스킬 예시·최종 보고에는 실제 값을 쓰지 않는다.
  • principal_alias는 요청자 식별에 쓸 짧은 ASCII alias로 정하고, token_refiop-dev-corp-<alias>처럼 환경과 용도를 포함한 안정값으로 정한다.
  • active private Edge config에서 같은 principal_ref 또는 token_ref를 먼저 찾는다. 하나라도 있으면 새 raw token을 발급하지 않고 기존 매핑의 활성 상태를 확인한다.
  • operation=createiop-user-crud-ops의 create 책임과 함께 적용하되, raw token 생성·local secret store·principal token 매핑 절차는 이 스킬이 소유한다.

먼저 확인할 것

  • principal_ref가 secret, provider token, provider identity가 아니라 외부 시스템 참조값인지 확인한다. 운영자가 private dev-corp 매핑의 이메일을 명시한 경우에는 ignored local store와 private Edge 설정으로 범위를 제한한다.
  • raw token을 tracked docs/, agent-roadmap/, agent-spec/, configs/, git diff, shell history, 최종 보고에 남기지 않을 전달 경로를 정한다.
  • raw token 보관이 필요한 경우 token/.dev-corp-iop-token의 ignore 상태와 mode 0600을 확인한다.
  • Confluence 동기화를 요청받은 경우 token/.dev-corp-iop-confluence-target의 mode 0600, ignored, untracked 상태와 대상 page 접근을 확인한다.
  • token_refprincipal_alias가 낮은 cardinality label로 안전한 값인지 확인한다.
  • 같은 principal_ref에 여러 앱/통합용 token이 필요한 경우 각 token의 앱/통합/용도 구분이 token_ref에 반영되는지 확인한다.
  • 기존 token을 회전하는 경우 기존 token_ref를 재사용할지 새 token_ref를 만들지 운영 정책을 확인한다.

실행 절차

  1. 입력 정규화

    • principal_ref 앞뒤 공백을 제거한다.
    • principal_alias는 공백을 -로 바꾸고, 운영자가 식별할 수 있는 짧은 ASCII alias로 둔다.
    • token_ref를 직접 받지 않았으면 생성할 token hash의 앞 16자를 사용해 ioptok_<hash-prefix> 형식으로 만든다.
    • operation=create이면 raw token 생성 전에 active private Edge config의 principal_reftoken_ref 중복을 확인한다. 기존 매핑이 있으면 발급을 중단하고 활성 상태를 검증한다.
  2. raw token 생성

    • 현재 shell에서 set +x를 확인한다.
    • 아래 형태의 고엔트로피 token을 생성한다. 실제 출력은 operator에게 1회만 전달한다.
set +x
umask 077
raw_token="iop_$(openssl rand -base64 36 | tr '+/' '-_' | tr -d '=')"
token_hash="$(printf '%s' "$raw_token" | sha256sum | awk '{print $1}')"
token_ref="${token_ref:-ioptok_${token_hash:0:16}}"
  1. local secret store 갱신

    • raw token을 보관해야 할 때만 repo root의 token/.dev-corp-iop-token<private-user-key>: <raw-token> 한 줄을 추가한다.
    • 새 파일 또는 후보 파일은 umask 077으로 만들고, 기존 매핑을 보존한 뒤 mode 0600 및 ignore 상태를 검증한다.
    • raw token을 shell 인자, trace, 화면 출력, tracked diff에 노출하지 않는다.
  2. 사용자 추가와 private Edge 후보 반영

    • operation=create이면 active private Edge config의 openai.principal_tokens[]에서 principal_reftoken_ref 중복을 다시 확인한다.
    • local secret store는 token/ 안의 후보 파일에 기존 레코드와 새 <private-user-key>: <raw-token>을 함께 기록하고, mode 0600·ignore 상태를 확인한 뒤 원자적으로 교체한다.
    • raw token은 SSH 표준 입력처럼 비노출 stream으로만 private Edge config 후보 생성기에 전달한다. 후보 config에는 token_ref, SHA-256 hash, principal_ref, principal_alias만 기록한다.
    • openai.principal_tokens[] 변경은 restart-required다. 환경 배포 스킬의 config check·refresh dry-run·backup/mv cutover·Edge restart 절차를 따른다. live apply 완료로 처리하지 않는다.
  3. raw-token-free 운영 기록 작성

    • tracked 문서나 공유 운영 기록에는 아래 필드만 남긴다.
token_ref: "<token_ref>"
principal_ref: "<principal_ref>"
principal_alias: "<principal_alias>"
token_hash_sha256: "<token_hash>"
status: active
  1. 승인된 Confluence metadata table 동기화

    • 동기화 요청이 있을 때만 local secret store의 private-user-key와 active Edge principal_tokens[]principal_ref 기준으로 1:1 대조한다. 불일치 또는 중복이면 표를 쓰지 않고 blocked로 보고한다.
    • target URL은 token/.dev-corp-iop-confluence-target에서만 읽고, lgucorp-confluence-docssync-token-metadata-table 인증·대상 재조회·version 기반 update 절차를 사용한다.
    • 표에는 사용자, principal alias, token ref, 상태: active, 동기화 시각만 넣는다. raw token, token hash, Authorization 값, provider credential, draft share URL은 넣지 않는다.
    • target body가 비어 있으면 관리 섹션과 표를 쓰고, 비어 있지 않으면 IOP 사용자 토큰 발급 현황 관리 섹션만 대체한다. 다른 섹션, title, parent, 권한은 변경하지 않는다.
    • 갱신 후 page 재조회로 table의 행 수·사용자/alias/ref/status metadata를 active mapping과 내부 검증한다. 실패하면 결과를 blocked로 보고하고, 앞선 token/Edge 상태를 되돌리거나 새 token을 발급하지 않는다.
  2. raw token 1회 전달

    • raw token은 operator-only 채널로 한 번만 전달한다.
    • 채팅 최종 보고, git diff, tracked 문서, 검증 출력에는 raw token을 쓰지 않는다.
  3. 누출 확인

    • 저장소 안에 raw token이 남지 않았는지 조용한 검색으로 확인한다. 실패 시 출력에 raw token이 찍히지 않게 한다.
    • 검사 대상에서 의도된 ignored token/ directory는 제외하되, 그 안의 secret store가 추적되지 않았음을 별도로 확인한다.
if rg -q -F "$raw_token" agent-ops agent-roadmap agent-spec agent-contract docs configs apps packages proto; then
  echo "raw token leak detected in tracked workspace paths"
  exit 1
fi
echo "raw token not found in tracked workspace paths"
  1. 결과 보고
    • token_ref, principal_ref, principal_alias, 매핑 기록 위치, Confluence metadata table 동기화 상태, raw token 전달 여부만 보고한다.
    • raw token과 전체 token hash는 보고하지 않는다.

실행 결과 검증

  • operation=create의 active private Edge config에 대상 principal_reftoken_ref가 각각 한 번만 존재하는가
  • raw token이 operator에게 1회만 전달되었는가
  • tracked 파일에는 raw token이 없고, token_ref, principal_ref, principal_alias, hash만 남았는가
  • token/.dev-corp-iop-token이 mode 0600이고 git check-ignore -q token/.dev-corp-iop-token을 통과하며 git ls-files --error-unmatch token/.dev-corp-iop-token이 실패하는가
  • Confluence 동기화를 요청한 경우 token/.dev-corp-iop-confluence-target이 mode 0600, ignored, untracked이고, local private-user-key 집합과 active Edge principal_ref 집합이 일치하는가
  • Confluence table은 local secret store의 각 사용자당 정확히 한 행이고 사용자, alias, ref, status metadata가 active mapping과 일치하며 raw token·token hash를 포함하지 않는가
  • Confluence 갱신 뒤 같은 draft/page의 title, status, parent가 유지되고 version·table 행 수가 기대값으로 재조회되는가
  • Edge restart 후 새 token으로 /v1/models/v1/chat/completions 인증이 성공하고, 가능한 경우 usage metric의 principal/token label이 관측되는가
  • rg -q -F "$raw_token" ... 누출 확인이 실패하지 않았는가
  • 최종 보고에 raw token, provider token, provider identity, raw prompt/response가 포함되지 않았는가
  • 검증 실패 시: raw token을 폐기하고 새 token을 발급한다. 누출된 tracked 파일은 수정한 뒤 다시 누출 확인을 실행하고, local secret store는 새 후보 파일 검증 뒤에만 교체한다.

출력 형식

OpenAI usage token issue
- operation: <create|rotate-token|other>
- token_ref: <token_ref>
- principal_ref: <principal_ref>
- principal_alias: <principal_alias>
- secret_store: token/.dev-corp-iop-token
- edge_mapping: <candidate-validated-and-restarted|existing-verified|not-applied>
- confluence_metadata_sync: <updated|not-requested|blocked>
- mapping_record: <path or operator-private store>
- raw_token_delivered_once: <yes|no>
- leak_check: <pass|fail>
- notes: raw token omitted from report

금지 사항

  • raw token을 tracked 파일, 최종 보고, 로그, metric label, Grafana dashboard, shell trace에 남기지 않는다.
  • raw token 또는 실제 요청자 식별자를 .gitignore, 스킬 예시, tracked 문서, shell 인자에 쓰지 않는다. .gitignore에는 /token/ directory 경로만 둔다.
  • raw token, token hash, Authorization 값, provider credential, draft share URL을 Confluence metadata table 또는 Confluence API payload에 넣지 않는다.
  • local secret store와 active Edge mapping이 1:1로 대조되지 않은 상태에서 Confluence 표를 갱신하거나, 관리 섹션 밖의 본문·title·parent를 변경하지 않는다.
  • active config에 같은 principal_ref 또는 token_ref가 있는데 새 raw token을 발급하거나 중복 entry를 추가하지 않는다.
  • metadata.user, provider token, provider identity를 사용자 식별 source로 쓰지 않는다.
  • request_id, session_id, raw token, raw prompt, raw response 같은 high-cardinality 또는 secret 값을 metric label 후보로 만들지 않는다.
  • 사용자 CRUD, tenant/org source of truth, token 제한 enforcement를 이 스킬 책임으로 확장하지 않는다.