Deploy security gate
このスキルは1つのチェックリストを強制します。キーが決して露出せず、単一障害で製品がダウンしないこと。3段階のパスで実行します:
scripts/scan.pyによる自動スキャン。高速で決定論的、読み取り専用。- 検出された各インテグレーションのコードレビュー。
references/integrations.mdをガイドに使用。 - リポジトリから確認できないすべての項目(プロバイダーダッシュボード、ローテーション、バックアップ、訓練など)に対する手動ゲート。これらの項目は
references/checklist.mdから得られます。
スキャンだけでは合格になりません。チェックリストのおおむね3分の1をカバーします。このスキルの価値は、3つのパスすべてを実行し、何が検証され、何にまだ人間の確認が必要かを正直に報告することにあります。
ワークフロー
1. スコープ
出荷するものを特定します:
- リポジトリルート
- フロントエンドまたはモバイルのビルド出力(あれば)
- デプロイ先(コンテナ、サーバーレス、Kubernetesなど)
- 初回ローンチ、新規インテグレーション、定期メンテナンスのいずれか
ユーザーが特定の変更(「Stripeを追加」など)を挙げた場合は、その変更にレビューを集中します。それでも完全スキャンは実行します。別の場所での漏洩がリリースを同様にブロックするためです。
2. スキャナーを実行する
python3 <skill-dir>/scripts/scan.py <repo> --history
- ビルドされたバンドル(
dist、.next/static、解凍したAPK/IPA)ごとに--build-dir <dir>を追加します。出荷されたバンドルは、「公開」キーが実際には秘密キーである場所です。一般的なビルドディレクトリは自動検出されます。該当するものがない場合は、先にアプリをビルドしてください。 --entropyは高エントロピーパスを追加し、名前付きパターンが知らないカスタムシークレットをキャッチします(低重要度。報告前に各結果を検証)。--format jsonまたは--format sarifは機械可読な出力を提供します。SARIFはGitHub Code Scanningにアップロードできます。--fail-on high|medium|low|neverは終了コードを制御し、CIで役立ちます。- 確認された誤検出は、インラインコメント
# security-gate: allowまたはリポジトリルートの.security-gate-ignoreファイルで抑制できます(README参照)。特定の検出結果を抑制することを、--fail-onを下げることより優先します。 - スキャナーはシークレット値をマスクします。あなたが書くすべてのものでその状態を維持してください。完全なキーをチャット、ファイル、コミット、PRテキストに絶対にエコーしないでください。それは二次的な漏洩を作り出します。
スキャナーがチェックするもの:
- ワークツリー、ビルド出力、Git履歴内のシークレットパターン(AWS、Anthropic、OpenAI、OpenRouter、Groq、xAI、Perplexity、Replicate、fal、Google APIキーとOAuthシークレット、StripeライブキーとWebhookシークレット、Razorpay、GitHub、GitLab、Slackトークンとアプリアップトークン、GCPサービスアカウント、npm、PyPI、SendGrid、Hugging Face、DigitalOcean、New Relic、Shopify、Square、Databricks、Doppler、PlanetScale、Linear、Azure Storageキー、Mailgun、Telegram、Discord Webhook、JWT、秘密鍵、パスワード付きDB URL、ハードコードされた
*_SECRET/*_TOKEN/*_SERVICE_ROLE代入 — 引用符付き(JSON/MCP設定を含む)または引用符なし) --entropy使用時: 既知の形式に一致しない高エントロピー文字列(カスタムまたは新しいシークレット)- コミットされた
.envファイルと欠落した.gitignoreエントリ - クライアント公開プレフィックス(
NEXT_PUBLIC_、VITE_、REACT_APP_、EXPO_PUBLIC_など)の背後にあるシークレットと思われる変数、およびクライアントコードからの直接のLLM呼び出し - ビルド出力内のソースマップ
- GitHub Actionsワークフロー: タグピン留めされたアクション、
pull_request_target、欠落したpermissions:ブロック、エコーされたシークレット、ファイルや$GITHUB_ENV/$GITHUB_OUTPUTに書き込まれたシークレット、OIDC の代わりに静的なクラウドキー、ライフサイクルスクリプトを実行するインストール - Dockerfile:
ARG/ENV内のシークレット、コピーされた.envファイル、rootでの実行 - 署名検証のないペイメントWebhookハンドラ
- コーディングエージェントによる
.envファイルへの読み取りアクセス - 使用中のインテグレーション、およびAIとペイメントの単一プロバイダー(単一障害点)のヒント
3. 検出結果をトリアージする
スキャナーはパターンマッチングで動作するため、報告する前にコードを読んで各検出結果を確認してください。
- ライブシークレットが見つかった場合(ツリー、履歴、またはバンドル内): リポジトリがプライベートであっても漏洩したものとして扱います。
references/leaked-key-runbook.mdに従い、まず失効させ、後でクリーンアップします。キーの失効またはローテーションはプロダクションを変更するため、どのキーがどこで見つかり、どのように失効させるかをユーザーに正確に伝えます。ユーザーに実行させるか、自分で何かをする前に確認を得てください。 - 誤検出(テストフィクスチャ、文書化された公開キー): なぜ安全かを説明し、次に進みます。
- 発見的検出結果(Webhook検証、クライアントサイドLLM呼び出し): ファイルを開き、実際の制御フローを確認します。検証は別の場所のミドルウェアにある可能性があります。
4. 検出された各インテグレーションをレビューする
スキャナーがリストしたすべてのインテグレーション、またはコード内で見つけたすべてのインテグレーションについて、references/integrations.md の該当セクションを読み、コードと照合します。このステップはパターンではキャッチできないものを捕捉します。例:
- オープンリレーになっているバックエンドプロキシ
- リクエストボディから取得されたモデル名
- クライアント上で計算された金額
- 管理者資格情報で実行されるツール呼び出し
- 分析サービスに送信されるPII
- テナントフィルターなしのRAGクエリ
- 間接的なプロンプトインジェクション: モデルが読み取るドキュメント、Webページ、文字起こし、ツール結果が指示として扱われる場合(チェックリスト3.17)
- タイプ/サイズ/アーカイブチェックやサンドボックスなしで解析されるファイルアップロード(3.18)
- SSRF: モデルやツールがプライベートアドレスやメタデータアドレスをブロックせずにフェッチする
*_url(3.19)
Webhook、クライアントLLM、シークレットのチェックは発見的です。スキャナーは候補をフラグしますが、手書きの制御や非標準的なレイアウトを見逃す可能性があります。常にコードを読んで確認してください。createHmac + timingSafeEqual で検証されたWebhookや、たまたま src/ の下にあるバックエンドは、ツールがフラグしても見逃しても問題ありません。
5. 単一障害点をチェックする
チェックリストのセクション10を使用し、コードとIaCで以下を探します:
- フォールバックのない1つのLLMプロバイダー
- タイムアウトやリトライのないベンダーへのHTTPクライアント
- 分析サービスダウン時にリクエストパスをブロックするベンダー呼び出し
- 単一リージョンまたは単一ゾーンのデータベース
- キャッシュのないシークレットフェッチ
- ユーザーが伝えるところによると、rootまたはownerアクセスを単独で保持する1人
6. 手動ゲート
多くのチェックリスト項目はリポジトリから確認できません。例:
- プロバイダーダッシュボードの支出上限
- ローテーションスケジュール
- ベンダーアカウントのSSOとMFA
- バックアップ復元テスト
- フェイルオーバー訓練
- DPA
- ペイメントページのPCIスクリプトインベントリ
これらは 確認が必要 としてリストし、それぞれに所有者への1行の質問を付けます。決して仮定で合格とマークしないでください。未確認の項目を黙って通過させるゲートは、ゲートがないより悪いです。
7. レポート
この構造を使用して、結果がリリース間で比較可能になるようにします:
# セキュリティゲート: <製品 / 変更> — <GO | NO-GO | GO WITH EXCEPTIONS>
## ブロッカー(デプロイ前に修正必須)
- [チェックID] ファイル:行 — 問題 — 修正方法
## 修正推奨(このスプリント内)
- ...
## レビュー済みインテグレーション
| インテグレーション | サーバーサイドのみ | スコープキー + 支出上限 | Webhook/出力検証済み | フォールバック | 備考 |
## 確認が必要(手動)
- [ ] <所有者への質問>(チェックリスト §n)
## 合格(検証済み)
- <項目> — 検証方法
判定ルール:
- NO-GO: 確認されたHIGHの検出結果がある場合。ライブシークレット、クライアントに露出したシークレットキー、未検証のペイメントWebhook、CIログ内のシークレットが該当。
- GO WITH EXCEPTIONS: mediumまたはlowの検出結果のみ残っており、ユーザーが所有者と期日を指定して受け入れた場合。
- GO: 未解決のものがなく、すべての手動項目が確認された場合。
問題の修正
ユーザーが検出結果の修正を依頼した場合、対症療法ではなく根本原因に対処する以下の是正手段を優先します:
- コード内のキー: シークレットマネージャーから注入された環境変数、またはプロバイダーSDKを介したランタイムルックアップに置き換えます。プレースホルダーを
.env.exampleに追加します。実際の値をどこにも書き込まないでください。キーをコードから削除しても漏洩は解消されないため、キーをまだ失効させる必要があることをユーザーに伝えます。 - クライアントに届くシークレット: ユーザーを認証し、ユーザーおよびテナントごとにレート制限し、モデルと操作を許可リスト化し、キーを保持するバックエンドルートまたはAIゲートウェイの背後に呼び出しを移動します。クライアントには公開可能なキーのみを残します。
- 未検証のWebhook: プロバイダーSDKを使用して生のボディの署名を検証します。古いタイムスタンプを拒否し、イベントIDで重複排除し、状態を変更する前にプロバイダーからオブジェクトを再フェッチします。
- CIの問題: アクションをコミットSHAにピン留めします(
git ls-remoteでSHAを解決し、タグをコメントに残します)。permissions: contents: readを追加します。静的なクラウドキーをOIDCに置き換えます。npm ci --ignore-scriptsを使用します。 - Dockerの問題: ビルド時のシークレットにはBuildKitの
RUN --mount=type=secretを、非rootのUSERを使用します。 - エージェントアクセス:
.claude/settings.jsonにpermissions.denyエントリRead(./.env)とRead(./.env.*)を追加します。平文ファイルが存在しないように、ランタイムインジェクション(doppler run、infisical run、op run)を推奨します。
継続的な使用
スキャナーをCIに組み込み、ローンチ時だけでなくすべてのPRでゲートが実行されるように提案します:
- run: python3 tools/deploy-security-gate/scripts/scan.py . --fail-on high
また、チェックリストのセクション12の頻度で定期的なレビューを提案します。
リファレンスファイル
references/checklist.md: 完全なチェックリスト(セクション1〜14)。各項目は[auto](スキャナー)、[code](コードレビュー)、[manual](所有者確認)でタグ付けされています。手順5〜6および正確な制御が必要なときに読んでください。references/integrations.md: AIゲートウェイとLLMプロバイダー、MCPサーバー、ペイメント、分析、認証にとって「良い状態」とは何かを、探すべきパターンとともに説明しています。スコープ内のインテグレーションのセクションを読んでください。references/leaked-key-runbook.md: ライブキーが見つかった場合のステップバイステップの対応手順。プロバイダーごとの失効手順へのポインタ付き。