EmDash는 미리보기, 댓글, 인증, 스토리지, 플러그인에 걸쳐 소수의 시크릿을 사용합니다. 이 페이지는 완전한 인벤토리입니다: 각 시크릿의 출처, 저장 위치, 교체 방법, 잃어버리면 무엇이 깨지는지.
개요
| 시크릿 | 출처 | 저장 위치 | 분실 시 영향 |
|---|---|---|---|
EMDASH_ENCRYPTION_KEY | 운영자 (emdash secrets generate) | 환경변수 / Worker 시크릿만 | 암호화된 플러그인 시크릿이 복구 불가능 (저장 시 암호화 출시 후) |
| 미리보기 시크릿 | 자동 생성 (env 오버라이드) | options 테이블 (emdash:preview_secret) | 기존 미리보기 링크 무효화; 새 링크는 정상 |
| IP 솔트 | 자동 생성 (env 오버라이드) | options 테이블 (emdash:ip_salt) | 댓글 레이트 리밋 연속성 리셋 |
| 세션 & API 토큰 | 세션/토큰별 생성 | 세션 스토어 / DB (해시만) | 없음 — 평문은 저장되지 않음 |
| OAuth 프로바이더 자격증명 | 사용자 (Google/GitHub 콘솔) | 환경변수 | 해당 프로바이더 로그인이 교체까지 중단 |
| Turnstile 시크릿 | 사용자 (Cloudflare 대시보드) | 환경변수 | 댓글 CAPTCHA 검증 실패 |
| S3 자격증명 | 사용자 (스토리지 프로바이더) | 환경변수 또는 설정 | 미디어 업로드/다운로드가 교체까지 실패 |
| 플러그인 시크릿 | 사용자 (관리자 설정 UI) | 데이터베이스 (플러그인 설정 / 스토리지) | 관리자에서 재입력 |
| CLI 자격증명 | emdash login / emdash plugin publish 디바이스 플로우 | ~/.config/emdash/auth.json (모드 0600) | 디바이스 플로우 재실행 |
| 레지스트리 CLI 자격증명 | emdash-plugin atproto OAuth | ~/.emdash/oauth/, ~/.emdash/credentials.json (모드 0600) | 재로그인; ID는 PDS에 존재 |
암호화 키
EMDASH_ENCRYPTION_KEY는 플러그인 시크릿의 저장 시 암호화를 위한 사이트 키입니다. 운영자가 제공하며 데이터베이스에 저장되지 않습니다 — 데이터베이스에는 암호문만 포함되므로 유출된 백업이 키를 노출하지 않습니다.
키를 생성하고 환경변수(또는 Worker 시크릿)로 설정합니다:
npx emdash secrets generate
# emdash_enc_v1_<43 base64url 문자>
# Cloudflare:
wrangler secret put EMDASH_ENCRYPTION_KEY
형식은 emdash_enc_v1_ 뒤에 32바이트 랜덤 데이터를 패딩 없는 base64url로 인코딩한 것입니다. 키는 런타임 시작 시 검증됩니다. 잘못된 값은 운영자 대상 오류를 로깅하되 요청 경로를 중단하지 않습니다.
교체
변수는 쉼표로 구분된 키 목록을 받습니다. 첫 번째 항목이 기본이며 새 쓰기에 사용됩니다. 모든 항목이 복호화에 시도됩니다. 각 암호화된 값에는 8자리 키 핑거프린트(kid, emdash secrets fingerprint <key>로 출력 가능)가 태그되어 있어 런타임이 자동으로 올바른 키를 선택합니다.
교체 방법: 새 키를 생성하고 목록 앞에 추가(EMDASH_ENCRYPTION_KEY="새키,이전키"), 재배포, 기존 값이 재암호화되면 이전 키를 제거.
생성된 사이트 시크릿
두 개의 시크릿이 최초 사용 시 자동 생성되어 options 테이블에 영구 저장되므로 요청, 배포, 아이솔레이트 간에 안정적입니다. 생성은 원자적입니다 — 동시 콜드 스타트가 하나의 값으로 수렴합니다.
미리보기 시크릿
미리보기 URL에 서명합니다 (HMAC). emdash:preview_secret로 저장; 32바이트 랜덤, base64url.
- 오버라이드: 여러 프로세스에서 동일한 시크릿이 필요하거나 감사 목적으로 고정하려면
EMDASH_PREVIEW_SECRET(레거시 별칭:PREVIEW_SECRET)를 설정합니다. 환경변수가 항상 저장된 값보다 우선합니다. - 교체:
emdash:preview_secret행을 삭제(또는 env 변수 변경)하고 재배포. 영향: 이전에 발급된 미리보기 링크가 검증 실패. 다른 것은 깨지지 않음 — 다음 미리보기 요청 시 새 시크릿이 생성됩니다(또는 env에서 읽힘). - 분실 시: 복구 불가능한 것이 없습니다. 미리보기 링크는 설계상 단기적입니다.
미리보기 URL의 구축과 검증에 대해서는 미리보기 가이드를 참조하세요.
IP 솔트
댓글 레이트 제한에 사용되는 댓글 작성자 IP 주소의 SHA-256 해시(ip_hash)에 솔트를 적용합니다. emdash:ip_salt로 저장. 사이트별이므로 해시는 EmDash 설치 간에 상관 불가능합니다.
- 오버라이드:
EMDASH_IP_SALT를 설정. 하위 호환성을 위해EMDASH_AUTH_SECRET/AUTH_SECRET도 참조됩니다 — 역사적으로 이들에서 솔트를 유도한 설치는 안정적인 해시를 유지합니다. - 교체: env 변수를 변경하거나
emdash:ip_salt행을 삭제. 영향: 새 댓글 제출이 다른 해시값을 생성하므로 모든 사람의 레이트 제한 카운팅이 재시작. 기존 댓글과 저장된 해시는 영향 없음. - 분실 시: 데이터 손실 없음. 레이트 제한 연속성만 리셋.
세션 및 API 토큰
- 세션은 Astro의 세션 스토어를 사용합니다 (Cloudflare의 Workers KV, Node의 파일시스템). 쿠키는 불투명한 세션 ID를 전달하며 관리할 서명 시크릿이 없습니다. 로그아웃으로 세션을 종료하거나 세션 스토어(예: KV 네임스페이스)를 비워 모든 사용자에게 재로그인을 강제합니다.
- API 토큰 (
ec_pat_,ec_oat_,ec_ort_접두사)은 불투명한 256비트 랜덤 값입니다. SHA-256 해시만 저장됩니다. 평문은 생성 시 한 번만 표시됩니다. 관리자에서 취소하고 재생성하여 교체합니다. - 초대, 매직 링크, 복구 토큰은 단일 목적이며,
auth_tokens에 SHA-256 해시로 저장되고, 시간 제한이 있습니다 (초대 7일, 매직 링크 15분).
사전에 백업하거나 교체할 것이 없습니다: 데이터베이스 유출은 해시만 노출하며, 모든 토큰은 관리자에서 취소하거나 재발급할 수 있습니다.
사용자 제공 서비스 자격증명
외부 서비스 자격증명은 환경변수에서 읽으며 데이터베이스에 기록되지 않습니다. 프로바이더에서 교체하고, 변수를 업데이트하고, 재배포하세요.
| 서비스 | 변수 |
|---|---|
| Google 로그인 | EMDASH_OAUTH_GOOGLE_CLIENT_ID, EMDASH_OAUTH_GOOGLE_CLIENT_SECRET (또는 접두사 없는 별칭) |
| GitHub 로그인 | EMDASH_OAUTH_GITHUB_CLIENT_ID, EMDASH_OAUTH_GITHUB_CLIENT_SECRET (또는 접두사 없는 별칭) |
| Marketplace 게시 (CI) | EMDASH_MARKETPLACE_TOKEN |
| Turnstile (댓글) | EMDASH_TURNSTILE_SECRET_KEY (또는 TURNSTILE_SECRET_KEY) |
| S3 호환 스토리지 | S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_ENDPOINT, S3_BUCKET, S3_REGION |
Cloudflare에서는 wrangler secret put으로 설정; 로컬에서는 .env에 넣습니다. 바인딩을 통한 R2는 자격증명이 필요 없습니다 — 접근은 wrangler.jsonc의 바인딩으로 부여되며, Workers에서 권장되는 설정입니다. 스토리지 옵션을 참조하세요.
플러그인 시크릿
플러그인이 type: "secret"으로 선언하는 설정(이메일 프로바이더 API 키, 폼 CAPTCHA 등)은 관리자 UI에서 입력되어 데이터베이스에 저장됩니다 — options 테이블의 plugin:<id>:settings:<key> 아래, 또는 플러그인의 키-값 스토리지. 저장된 시크릿이 관리자 UI에 반환되는지는 플러그인에 따릅니다. 잘 작성된 플러그인은 시크릿 자체 대신 “값이 설정됨” 플래그만 반환합니다 (번들된 폼 플러그인이 이렇게 합니다).
- 교체: 프로바이더에서 키를 교체하고 새 값을 플러그인 설정 페이지에 붙여넣습니다. 즉시 적용됩니다.
- 분실 시: 관리자에서 값을 재입력합니다. 다른 것이 의존하지 않습니다.
CLI 자격증명
emdash CLI는 두 종류의 자격증명을 보유하며, 둘 다 ~/.config/emdash/auth.json (XDG_CONFIG_HOME 준수)에 소유자 전용 권한(0600)으로 생성됩니다:
- 사이트 토큰 —
emdash login은 OAuth 디바이스 플로우를 통해 EmDash 인스턴스에 인증하고 결과 토큰을 인스턴스 URL을 키로 저장합니다.emdash logout으로 제거합니다. 호출별로--token또는EMDASH_TOKEN이 저장된 토큰을 오버라이드합니다. - Marketplace 토큰 —
emdash plugin publish는 GitHub 디바이스 플로우를 통해 EmDash Marketplace에 인증하고 결과 JWT를marketplace:<origin>으로 인덱싱하여 저장합니다. CI 게시에는EMDASH_MARKETPLACE_TOKEN을 설정하세요 — 저장된 자격증명보다 우선합니다.
파일 분실은 무해합니다: emdash login (또는 디바이스 플로우를 재실행하는 emdash plugin publish)을 다시 실행하세요.
플러그인 레지스트리 CLI 자격증명
별도의 emdash-plugin CLI (패키지 @emdash-cms/plugin-cli)는 실험적인 AT Protocol 레지스트리를 대상으로 합니다. 거기서의 게시는 당신의 AT Protocol 아이덴티티(게시자 DID)에 연결됩니다 — 사이트 자체는 게시 자격증명을 보유하지 않으며, 설치는 해당 DID에 귀속된 릴리스 레코드의 체크섬에 대해 아티팩트를 검증합니다.
- atproto OAuth로 인증합니다. OAuth 세션/상태 블롭은
~/.emdash/oauth/에, 게시자 아이덴티티(DID, 핸들, PDS)는~/.emdash/credentials.json에 캐시됩니다. 둘 다 소유자 전용 권한으로 작성됩니다. - CI에서는
EMDASH_PUBLISHER_DID,EMDASH_PUBLISHER_HANDLE,EMDASH_PUBLISHER_PDS로 아이덴티티를 제공합니다.EMDASH_REGISTRY_URL은 레지스트리 호스트를 오버라이드합니다. CI에서의 자동publish는 여전히 러너의~/.emdash/oauth/에 OAuth 세션 파일이 필요합니다 — env 변수만으로는 OAuth 세션을 전달할 수 없습니다. - 게시 접근 권한의 교체 또는 취소는 EmDash가 아닌 AT Protocol 계정(예: 앱 패스워드)에서 수행합니다. Atmosphere auth를 참조하세요.
교체 빠른 참조
| 하고 싶은 것 | 방법 |
|---|---|
| 암호화 키 교체 | 새 키를 앞에 추가: EMDASH_ENCRYPTION_KEY="새키,이전키", 재배포, 나중에 이전 키 제거 |
| 모든 미리보기 링크 무효화 | emdash:preview_secret 옵션 행 삭제 (또는 env 오버라이드 변경) |
| 댓글 레이트 제한 해싱 리셋 | EMDASH_IP_SALT 변경 (또는 emdash:ip_salt 옵션 행 삭제) |
| 유출된 API 토큰 취소 | 관리자 → 사용자 → API 토큰 → 취소, 대체 생성 |
| 모든 세션 종료 | 세션 스토어 비우기 (Workers KV 네임스페이스 / 세션 디렉토리) |
| 프로바이더 자격증명 교체 | 프로바이더에서 교체, env 변수 업데이트, 재배포 |
| 플러그인 API 키 교체 | 프로바이더에서 교체, 플러그인의 관리자 설정에서 재입력 |