시크릿 및 키 관리

이 페이지

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 키 교체프로바이더에서 교체, 플러그인의 관리자 설정에서 재입력