DKDevKey Docs

Architectural security interface

시크릿을 저장하고,
필요한 만큼만 전달하세요.

DevKey는 프로젝트별 시크릿을 암호화해 보관하고, 만료·권한·감사 로그가 있는 Access Key로 애플리케이션에 전달합니다. 이 문서는 관리자 콘솔과 API를 처음부터 운영까지 한 흐름으로 설명합니다.

01 · Start here

처음 5분: 프로젝트에서 API 호출까지

계정과 프로젝트를 만든 뒤, 시크릿 하나에 읽기 권한이 있는 Access Key를 발급하고 첫 호출을 확인합니다.

  1. 관리자 콘솔에 로그인dev-key.com에서 이메일 인증을 마치고 로그인합니다.
  2. Project 만들기Projects에서 이름과 URL-safe slug(예: erp)를 정합니다. API 요청에는 이 slug를 사용합니다.
  3. Secret 저장Secrets → Create에서 DB_PASSWORD 같은 키와 값을 입력합니다. 값은 저장 후 암호화되어 관리자 목록에도 평문으로 노출되지 않습니다.
  4. Access Key 발급Access Keys → Create에서 같은 Project를 선택하고, 필요한 Secret에 Read/List 권한만 부여합니다. 만료일은 달력 또는 빠른 기간 버튼으로 지정할 수 있습니다.
  5. 첫 번째 읽기 요청생성 직후 한 번만 표시되는 원문 키를 안전한 런타임 시크릿에 넣고 아래 API 예제로 확인합니다.
원문 키는 다시 볼 수 없습니다. Access Key 생성 성공 화면에서만 sk_dev_... 또는 sk_live_... 원문이 표시됩니다. 복사하지 못했다면 기존 키를 비활성화하고 새 키를 발급하세요.

02 · Mental model

DevKey의 구성 모델

권한 범위가 섞이지 않도록 리소스를 계층으로 나눕니다. 하나의 Access Key는 정확히 하나의 Project에 속하고, 그 Project 안의 Secret Item들에만 권한을 받을 수 있습니다.

Account

사용자 소유의 최상위 경계입니다. Project·Secret·Access Key·감사 로그는 계정 소유권 검사를 통과해야 합니다.

Project

서비스 또는 환경 단위의 격리 경계입니다. API URL에는 Project의 slug가 들어갑니다.

Secret Item

키와 암호화된 값의 쌍입니다. 값 자체는 API 권한을 통과한 요청에서만 복호화됩니다.

Access Key

애플리케이션이 API를 호출하는 자격 증명입니다. 활성 상태·만료일·Project 범위를 함께 검사합니다.

Permission

Access Key와 Secret Item 사이의 연결입니다. canRead, canList 등을 Secret 단위로 지정합니다.

Audit Log

읽기·목록 조회와 성공/실패를 추적합니다. IP, User-Agent, 오류 코드가 함께 기록됩니다.

03 · Admin console

관리자 콘솔 사용법

웹 콘솔은 Better Auth 세션과 계정 소유권으로 보호됩니다. 브라우저에서 값을 직접 다루는 시간을 줄이고, 작업 단위를 Project로 분리하세요.

Secret 만들기·수정·삭제

Secrets → Create에서 Project, key, value를 입력합니다. key는 애플리케이션 환경 변수 이름처럼 대문자와 밑줄 조합을 권장합니다. 설명은 운영자가 목적과 소유 팀을 확인하는 데 사용합니다.

목록에서는 값 대신 메타데이터만 확인할 수 있습니다. 수정 화면에서 값을 비워 둔 채 저장하면 기존 값이 유지되고, 새 값을 넣으면 암호화된 값이 교체됩니다. 삭제 전에는 해당 Secret을 사용하는 Access Key 권한도 함께 점검하세요.

Project 경계

예를 들어 erp-dev, erp-staging, erp-prod를 별도 Project로 만들면 같은 키 이름을 사용해도 API 자격 증명이 서로 섞이지 않습니다. Access Key 생성 후에는 Project를 변경할 수 없습니다.

04 · Access keys

Access Key 발급과 수명 관리

Access Key는 sk_dev_... 또는 sk_live_... 형식입니다. 서버는 원문 대신 HMAC-SHA-256 해시만 저장하고, 요청 때 prefix로 후보를 찾은 뒤 전체 키를 검증합니다.

기간 선택

키는 기한없음, 1개월, 3개월, 6개월, 9개월, 1년 빠른 버튼 또는 정확한 날짜·시간 달력으로 만료를 지정할 수 있습니다. 만료 시각은 저장된 UTC ISO 시각으로 비교되며, 만료된 키는 401을 반환합니다.

생성 후 운영 체크리스트

  • 원문 키를 CI/CD 또는 Worker의 시크릿 저장소에 즉시 저장합니다.
  • 개발·스테이징·운영 환경마다 Project와 키를 분리합니다.
  • 필요한 Secret만 선택하고, 목록 조회가 필요 없으면 canList를 끕니다.
  • 교체할 때는 새 키를 먼저 배포하고, 트래픽 확인 후 이전 키를 비활성화합니다.

05 · Permissions

권한은 Access Key가 아니라 Secret에 부여합니다

Access Key 설정에서 “Access Key 자체”나 별도 메뉴를 권한 대상으로 고르는 방식이 아닙니다. 선택한 Project의 Secret Item을 행으로 보고, 각 행에 동작을 부여하는 구조입니다.

플래그현재 의미권장 사용
canRead해당 Secret의 값을 단건으로 읽을 수 있음필요한 단건 조회에만 켭니다.
canList프로젝트의 .env 목록 응답에 포함할 수 있음. 현재 구현은 Read도 함께 필요부팅 시 여러 값을 한 번에 주입할 때만 켭니다.
canWrite권한 모델에 예약된 쓰기 플래그현재 공개 API에는 Secret 쓰기 엔드포인트가 없으므로 읽기 전용 키에는 끕니다.
canDelete권한 모델에 예약된 삭제 플래그현재 공개 API에는 Secret 삭제 엔드포인트가 없으므로 읽기 전용 키에는 끕니다.
Project 범위는 서버에서 재검증됩니다. 화면에서 보이는 Secret 목록뿐 아니라 API가 제출된 모든 Secret ID가 Access Key의 Project에 속하는지 확인합니다. 다른 Project의 ID를 임의로 넣어도 403으로 거절됩니다.

06 · API

API로 Secret 읽기

운영 API의 기본 주소는 https://dev.dev-key.com입니다. 모든 Secret API 요청은 Authorization: Bearer 헤더에 Access Key를 담아야 합니다. 원문 키를 URL, 로그, 소스 코드에 넣지 마세요.

단건 조회 · curl
curl --fail-with-body --silent --show-error   https://dev.dev-key.com/api/v1/projects/erp/secrets/DB_PASSWORD   -H "Authorization: Bearer $DEVKEY_ACCESS_KEY"

성공 응답은 다음처럼 project, key, 복호화된 value를 반환합니다.

200 · application/json
{
  "project": "erp",
  "key": "DB_PASSWORD",
  "value": "example-value"
}

프로젝트의 여러 값 읽기

목록 조회 · curl
curl --fail-with-body --silent --show-error   https://dev.dev-key.com/api/v1/projects/erp/secrets   -H "Authorization: Bearer $DEVKEY_ACCESS_KEY"

목록 응답에는 Access Key에서 canReadcanList가 모두 켜진 Secret만 포함됩니다.

공개 API 엔드포인트

메서드경로인증응답
GET/health없음{ "ok": true }
GET/api/v1/projects/:slug/secrets/:keyBearer Access Key단건 Secret JSON
GET/api/v1/projects/:slug/secretsBearer Access Key{ "secrets": { ... } }
GET/api/v1/projects/:slug/secrets.envBearer Access Key환경 변수 형식의 text/plain
GET/openapi.json없음OpenAPI 3 문서

대화형 API Reference는 dev.dev-key.com/docs에서 열 수 있습니다. 문서 호스트에서 /docs로도 같은 Swagger 화면을 사용할 수 있습니다.

07 · Environment injection

.env 형식으로 주입하기

애플리케이션 시작 시 여러 값을 읽어야 한다면 secrets.env를 사용합니다. 응답은 KEY=value 줄 목록이며, 값에 줄바꿈·따옴표가 있을 때는 서버의 dotenv 포맷터 규칙을 따릅니다.

.env 다운로드 · curl
curl --fail-with-body --silent --show-error   https://dev.dev-key.com/api/v1/projects/erp/secrets.env   -H "Authorization: Bearer $DEVKEY_ACCESS_KEY"   -o .env.runtime
파일을 로그에 남기지 마세요. .env.runtime는 프로세스 시작 직후 메모리로 읽고, 저장이 필요하면 배포 플랫폼의 시크릿 저장소를 사용합니다. Git에 커밋하지 않도록 .gitignore에 추가하세요.

08 · Security model

보안 경계와 감사

세션 게이트

관리자 API는 Better Auth 세션과 사용자 소유권을 확인합니다. 세션 쿠키를 API 키처럼 공유하지 마세요.

암호화 저장

Secret 값은 Worker의 암호화 키로 AES-GCM 처리되어 D1에 저장됩니다. 목록 DTO에는 평문·암호문을 포함하지 않습니다.

최소 권한

단건 Read와 일괄 List를 분리해 필요한 범위만 허용합니다. 키마다 짧은 만료 기간을 우선하세요.

감사 추적

읽기와 목록 조회의 성공·실패, Project·Access Key, IP, User-Agent, 오류 코드가 감사 로그에 남습니다.

호스트 분리

dev-key.com은 관리자 UI, dev.dev-key.com은 API, docs.dev-key.com은 문서 전용입니다.

키 회전

새 키를 먼저 배포하고 이전 키를 비활성화하는 두 단계 회전으로 다운타임을 피합니다.

운영 전 확인

  • 브라우저 개발자 도구·서버 로그·CI 출력에 Access Key가 찍히지 않는지 확인합니다.
  • 만료·비활성화 후 같은 요청이 401이 되는지 스테이징에서 테스트합니다.
  • 접근하지 않아야 할 Secret은 권한을 끄고, 필요한 경우 Project 자체를 분리합니다.
  • 감사 로그에서 비정상 IP·User-Agent·실패 코드가 반복되는지 확인합니다.

09 · Local & deploy

로컬 개발과 배포

DevKey는 Vite로 React 정적 자산을 빌드하고 Hono Worker가 API와 자산을 함께 제공합니다. D1 마이그레이션과 비밀값은 배포 환경별로 분리됩니다.

로컬 시작

PowerShell / macOS / Linux
npm install
Copy-Item .dev.vars.example .dev.vars  # PowerShell
# cp .dev.vars.example .dev.vars       # macOS/Linux
npm run db:migrate:local
npm run dev

.dev.vars에는 로컬 암호화 키·Access Key pepper·Better Auth 설정이 필요합니다. 예제 파일을 복사한 뒤 값은 직접 생성하고, 파일 내용은 커밋하거나 공유하지 마세요.

검증과 운영 배포

검증
npm test
npm run build

운영 배포 스크립트는 빌드 → 원격 D1 마이그레이션 → 운영 비밀값 동기화 → wrangler deploy --env production 순서로 실행됩니다.

운영 명령은 승인 후 실행합니다. npm run deploy, npm run db:migrate:prod, npm run secrets:prod는 원격 상태를 변경합니다. 먼저 변경 범위·마이그레이션 SQL·환경 변수를 리뷰하고, 승인된 운영 세션에서만 실행하세요.

호스트별 책임

호스트역할허용 표면
dev-key.com
www.dev-key.com
관리자 웹React UI, Better Auth 경로
dev.dev-key.comAPI/api/*, /health, OpenAPI, Swagger
docs.dev-key.com문서문서 홈, Swagger, OpenAPI JSON
localhost개발 편의웹·API 표면을 함께 제공

10 · Troubleshooting

문제 해결

증상가능한 원인확인할 것
401 Missing or invalid bearer tokenAuthorization 헤더가 없거나 형식이 다름Authorization: Bearer $DEVKEY_ACCESS_KEY와 키의 공백·개행을 확인합니다.
401 Access key has expired만료일이 현재 시각보다 과거콘솔에서 만료일을 확인하고 새 키를 발급합니다.
401 Access key is inactive or missing키가 비활성화됐거나 prefix를 찾지 못함키 전체를 다시 복사하지 말고, 새 키를 발급해 배포합니다.
403 Access key cannot read this secret해당 Secret에 Read 권한이 없음Access Key 상세 → 권한에서 Secret 행의 Read를 켭니다.
목록에 Secret이 안 보임Read 또는 List 중 하나가 꺼져 있음목록 조회는 두 플래그가 모두 필요합니다.
404 Project/Secret not foundslug·key 오탈자 또는 다른 ProjectAPI 호스트와 Project slug, Secret key의 대소문자를 확인합니다.
관리자 API 401Better Auth 세션이 없거나 다른 호스트에서 호출관리자 UI 호스트에서 로그인하고 쿠키 전송 여부를 확인합니다.

11 · Glossary

용어

Account 사용자 소유 경계. Project 서비스/환경별 격리 단위. Secret Item 암호화되는 key-value 리소스. Access Key API 호출용 Bearer 자격 증명. Permission 키와 Secret 사이의 동작 범위. Audit Log 접근 성공·실패 추적 기록.

문서와 구현의 기준이 다르게 보이면 OpenAPI JSON과 현재 배포된 콘솔의 동작을 우선 확인하세요.