シークレットとキーの管理

このページ

この一覧を使い、どの値がランタイム環境に属し、どれがデータベースに生成され、どれがプラグインによって保存されるかを判断します。各セクションは、ローテーションが稼働中のサイトにどう影響するかを示します。

Node.js では、プロセス起動時に process.env に入るよう、ランタイムシークレットをホスティングプラットフォームのシークレットマネージャーに置きます。Worker では wrangler secret put を使います。シークレット値を astro.config.mjs、wrangler.jsonc、import.meta.env に置かないでください。Vite はビルド時の値をサーバーバンドルに埋め込むことがあります。

概要

シークレットソース保存先キー紛失時の影響
EMDASH_ENCRYPTION_KEY運用者(emdash secrets generate)環境 / Worker シークレットのみ一致するキーを復元するまで、暗号化したプラグイン設定は読めません
プレビューシークレット自動生成(環境オーバーライド)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)再ログインします。アイデンティティは PDS にあります

暗号化キー

EMDASH_ENCRYPTION_KEY は type: "secret" で宣言されたプラグイン設定を暗号化します。EmDash はプラグイン ID と設定キーを認証付きデータとする AES-GCM を使います。不正な形式の値は運用者向けの起動メッセージを出し、暗号化されたプラグイン設定が必要な操作は fail closed します。無関係なサイトリクエストは引き続き動作します。

次のコマンドは正しい形式の値を生成します。ランタイム環境に保存するか、 デプロイがこの変数を使う場合は Worker シークレットとして保存します。

npx emdash secrets generate
# emdash_enc_v1_<43 base64url chars>

# Cloudflare:
wrangler secret put EMDASH_ENCRYPTION_KEY

形式は emdash_enc_v1_ のあとに、パディングなし base64url の 32 ランダムバイトです。値は運用者が提供し、データベースには保存されません。シークレットマネージャーと、別の復旧バックアップに保管してください。

キーをローテーションするには、新しい値を先頭に置き、カンマのあとに古い値を残します。

EMDASH_ENCRYPTION_KEY=emdash_enc_v1_<new-key>,emdash_enc_v1_<old-key>

EmDash は新規および再保存した値を最初のキーで暗号化します。読み取りでは、保存された kid フィンガープリントで古いキーを選びます。古いキーを外す前にすべてのプラグインシークレットを再保存し、新しいキーだけを含むデプロイからそれらの連携を検証してください。EmDash は現在、どのキー ID がまだ使われているかを報告しないため、再保存した資格情報の一覧を保ち、各連携がその検証を通るまで古いキーを外さないでください。

生成されるサイトシークレット

2 つのシークレットは初回利用時に自動生成され、options テーブルに永続化されるため、リクエスト、デプロイ、isolate をまたいで安定します。生成はアトミックです。同時のコールドスタートは 1 つの値に収束します。

プレビューシークレット

プレビュー 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 ではファイルシステム)。Cookie は不透明なセッション 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 に置きます。Wrangler は .dev.vars または .env のどちらかを読み、両方ではありません。存在する場合は .dev.vars が優先されます。バインディング経由の R2 は、バインディングがランタイムアクセスを付与するため、アクセスキー変数は不要です。メディアストレージ を参照してください。

プラグインシークレット

プラグインが type: "secret" で宣言する設定(メールプロバイダーの API キー、フォーム CAPTCHA など)は管理 UI で入力され、options テーブルの plugin:<id>:settings:<key> 下に暗号化されます。一致する暗号化キーがない場合でも、管理画面はシークレットが設定されているかどうかだけを受け取るため、管理者は読めない資格情報を置き換えできます。プラグインコードは隔離されたランタイム内の ctx.settings 経由で平文を読みます。宣言された設定スキーマ外に保存された値(任意のプラグイン KV および状態エントリを含む)はこの暗号化パスを使いません。

  • 資格情報のローテーション: プロバイダーで資格情報をローテーションし、新しい値をプラグインの設定ページに貼り付けます。保存は新しい暗号化エンベロープを書き込みます。
  • 平文の移行: 以前の EmDash リリースで保存されたシークレットは引き続き読めます。各値を再保存して暗号化します。
  • 暗号化キーを紛失した場合: 別のキーバックアップから一致する EMDASH_ENCRYPTION_KEY を復元します。コピーがない場合は、影響を受ける各資格情報をプロバイダーで置き換え、新しい暗号化キーを設定したあとに置換値を入力します。

CLI 資格情報

emdash CLI は 2 種類の資格情報を保持し、どちらも ~/.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 セッションファイルが依然として必要です。環境変数だけでは OAuth セッションを運びません。
  • 公開アクセスのローテーションや取り消しは AT Protocol アカウント(例: アプリパスワード)で行い、EmDash 内ではありません。Atmosphere 認証 を参照してください。

ローテーション早見表

やりたいこと手順
プラグイン設定の暗号化をローテーション新しいキーを先頭に置き、プラグインシークレットを再保存し、古いキーを外す
すべてのプレビューリンクを無効化emdash:preview_secret オプション行を削除(または環境オーバーライドを変更)
コメントのレート制限ハッシュをリセットEMDASH_IP_SALT を変更(または emdash:ip_salt オプション行を削除)
漏洩した API トークンを取り消しAdmin → Users → API tokens → 取り消し、その後置換を作成
すべてのセッションを終了セッションストアをクリア(Workers KV 名前空間 / セッションディレクトリ)
プロバイダー資格情報を置き換えプロバイダーでローテーションし、環境変数を更新して再デプロイ
プラグイン API キーを置き換えプロバイダーでローテーションし、プラグインの管理設定に再入力