이 인벤토리를 사용하여 런타임 환경에 속하는 값, 데이터베이스에서 생성되는 값, 플러그인이 저장하는 값을 결정하세요. 각 섹션은 로테이션이 실행 중인 사이트에 어떤 영향을 미치는지 설명합니다.
Node.js에서는 호스팅 플랫폼의 시크릿 매니저에 런타임 시크릿을 넣어 프로세스 시작 시 process.env에 들어가도록 합니다. Worker의 경우 wrangler secret put을 사용하세요. astro.config.mjs, wrangler.jsonc 또는 import.meta.env에 시크릿 값을 넣지 마세요. Vite가 빌드 시 값을 서버 번들에 포함시킬 수 있습니다.
개요
| 시크릿 | 소스 | 저장 위치 | 키 분실 시 영향 |
|---|---|---|---|
EMDASH_ENCRYPTION_KEY | 운영자 (emdash secrets generate) | 환경 / Worker 시크릿만 | 현재 데이터에 영향 없음; EmDash는 형식만 확인 |
| 프리뷰 시크릿 | 자동 생성 (환경 변수 오버라이드) | options 테이블 (emdash:preview_secret) | 발급된 프리뷰 링크가 작동 중지; 새로운 것은 정상 |
| IP 솔트 | 자동 생성 (환경 변수 오버라이드) | options 테이블 (emdash:ip_salt) | 댓글 레이트 리밋 연속성 리셋 |
| 세션 및 API 토큰 | 세션/토큰별 생성 | 세션 스토어 / 데이터베이스 (해시만) | 없음 — 평문은 저장되지 않음 |
| 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는 현재 플러그인 시크릿이나 다른 저장된 데이터를 암호화하지 않습니다. 변수가 설정되면 EmDash는 시작 시 형식을 확인합니다. 잘못된 형식의 값은 운영자용 로그 메시지를 생성하지만, 사이트는 계속 요청을 처리합니다.
다음 명령은 올바른 형식의 값을 생성합니다. 배포가 이 변수를 사용하는 경우 런타임 환경이나 Worker 시크릿으로 저장하세요.
npx emdash secrets generate
# emdash_enc_v1_<43자의 base64url>
# Cloudflare:
wrangler secret put EMDASH_ENCRYPTION_KEY
형식은 emdash_enc_v1_ 다음에 패딩 없는 base64url로 된 32바이트 랜덤 데이터입니다. 값은 운영자가 제공하며 데이터베이스에 저장되지 않습니다. 분실해도 데이터 복구에 영향이 없습니다 (저장된 데이터가 이에 의존하지 않으므로).
생성된 사이트 시크릿
두 시크릿은 첫 사용 시 자동으로 생성되어 options 테이블에 영구 저장되므로, 요청, 배포, isolate 간에 안정적입니다. 생성은 원자적입니다 — 동시 콜드 스타트가 하나의 값으로 수렴합니다.
프리뷰 시크릿
프리뷰 URL에 서명합니다 (HMAC). emdash:preview_secret로 저장; 32바이트 랜덤 데이터, base64url.
- 오버라이드: 여러 프로세스 간에 동일한 시크릿이 필요하거나 감사 목적으로 고정하려면
EMDASH_PREVIEW_SECRET(레거시 별칭:PREVIEW_SECRET)를 설정하세요. 환경 변수는 항상 저장된 값보다 우선합니다. - 로테이션:
emdash:preview_secret행을 삭제 (또는 환경 변수 변경)하고 재배포합니다. 영향: 이전에 발급된 프리뷰 링크가 더 이상 검증되지 않습니다. 다른 것은 깨지지 않습니다 — 다음 프리뷰 요청 시 새 시크릿이 생성 (또는 환경에서 읽기)됩니다. - 분실 시: 복구 불가능한 것은 없습니다. 프리뷰 링크는 설계상 수명이 짧습니다.
프리뷰 URL의 구성 및 검증에 대해서는 프리뷰 가이드를 참조하세요.
IP 솔트
댓글 레이트 리밋에 사용되는 댓글 작성자 IP 주소의 SHA-256 해시 (댓글의 ip_hash)에 솔트를 추가합니다. emdash:ip_salt로 저장. 사이트별이므로 해시는 EmDash 설치 간에 상관될 수 없습니다.
- 오버라이드:
EMDASH_IP_SALT를 설정하세요. 하위 호환성을 위해EMDASH_AUTH_SECRET/AUTH_SECRET도 참조됩니다 — 역사적으로 이들로부터 솔트를 파생한 설치는 안정적인 해시를 유지합니다. - 로테이션: 환경 변수를 변경하거나
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 (또는 접두사 없는 별칭) |
| 마켓플레이스 게시 (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에 넣습니다. Wrangler는 .dev.vars 또는 .env 중 하나를 읽으며 둘 다 읽지 않습니다. .dev.vars가 있으면 우선합니다. 바인딩을 통한 R2는 바인딩이 런타임 접근을 부여하므로 액세스 키 변수가 필요하지 않습니다. 미디어 스토리지를 참조하세요.
플러그인 시크릿
플러그인이 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이 저장된 토큰을 오버라이드합니다. - 마켓플레이스 토큰 —
emdash plugin publish는 GitHub 디바이스 플로우를 통해 EmDash 마켓플레이스에 인증하고marketplace:<origin>을 키로 결과 JWT를 저장합니다. 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 세션/상태 blob은
~/.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 세션 파일이 필요합니다 — 환경 변수만으로는 OAuth 세션을 전달할 수 없습니다. - 게시 접근의 로테이션 또는 취소는 EmDash가 아닌 AT Protocol 계정 (예: 앱 비밀번호)에서 수행됩니다. Atmosphere 인증을 참조하세요.
로테이션 빠른 참조
| 하고 싶은 것 | 방법 |
|---|---|
| 모든 프리뷰 링크 무효화 | emdash:preview_secret 옵션 행 삭제 (또는 환경 변수 오버라이드 변경) |
| 댓글 레이트 리밋 해싱 리셋 | EMDASH_IP_SALT 변경 (또는 emdash:ip_salt 옵션 행 삭제) |
| 유출된 API 토큰 취소 | 관리자 → 사용자 → API 토큰 → 취소, 대체 생성 |
| 모든 세션 종료 | 세션 스토어 비우기 (Workers KV 네임스페이스 / 세션 디렉토리) |
| 제공자 자격 증명 교체 | 제공자에서 로테이션, 환경 변수 업데이트, 재배포 |
| 플러그인 API 키 교체 | 제공자에서 로테이션, 플러그인 관리자 설정에서 재입력 |