プロンプトとスコープ
あなたの会社では、GitHub Actionsとセルフホストランナーから毎日数千のコンテナイメージをビルドしています。すべてのイメージに対して追跡可能なビルド来歴を生成・検証し、組織のポリシーに合格した場合にのみデプロイを許可するサービスを設計してください。データモデル、発行、検証、信頼のルート、キーローテーション、侵害されたランナー、オフラインデプロイ、ロールバック、オブザーバビリティを網羅してください。
サプライチェーンセキュリティに関する公の採用ガイダンスでは、現実的なシステムデザインのプロンプトが使用されます。それは、数千のサービスと混在するランナーにわたって、すべてのコンテナイメージに対して検証可能な来歴を生成することです。SLSAは来歴の生成、配布、検証を分離しており、Sigstoreはアイデンティティ、発行者、署名、およびアーティファクトダイジェストのチェックを文書化しています。この問題は、レジストリレコード上の単なる署名フィールドではなく、運用ポリシーを備えた信頼チェーンです。
面接官がテストしていること
- アーティファクトダイジェスト、来歴クレーム、署名、透明性ログ(transparency log)、アドミッションポリシーを区別できているか。
- 脅威モデルに、信頼できないソース、依存関係、ビルド構成、ランナーが含まれているか。
- クレームが、可変なタグや無関係なテキストではなく、不変のアーティファクトにバインドされているか。
- 検証失敗、キーローテーション、失効、オフラインモード、ロールバックに明示的なセマンティクスがあるか。
- 書き込み、クエリ、キャッシュ、保持、監査のコストを見積もり、ポリシーバージョンを公開しているか。
最初に確認すべき明確化のための質問
- 目標はデプロイの防止ですか、それとも監査証拠ですか?アドミッションは厳格なゲート(hard gate)であり、監査証拠は別途保存されると想定します。
- アーティファクトはコンテナのみですか?OCIイメージから開始し、バイナリやパッケージ用の拡張ポイントを残しておきます。
- すべてのビルダーはオンラインですか?制限された環境やオフライン環境では、事前にロードされたルートとバンドルが必要であると想定します。
- アイデンティティは個人、リポジトリ、ワークフロー、ビルダーのいずれに紐づけられていますか?メールアドレス単体ではなく、ワークフローアイデンティティとマネージドビルダーであると想定します。
- 証拠はどのくらいの期間保持する必要がありますか?ストレージとインデックスのサイズを見積もる前に、コンプライアンスと監査の期間を確認します。
30秒の回答
私は4つの境界を分離します。ビルダーはソースリビジョン、依存関係、パラメータ、ビルダーアイデンティティを含む来歴を発行します。発行者はクレームを不変のアーティファクトダイジェストにバインドし、透明性ログに記録します。検証者は署名チェーン、アイデンティティ、ダイジェスト、ポリシーバージョン、タイムウィンドウをチェックします。アドミッションコントローラーは、許可(allow)、隔離(quarantine)、または拒否(deny)を返します。ソース、依存関係、ランナーは信頼できない入力であるため、CI実行の成功それ自体は証拠になりません。ポリシーバージョンと失敗理由は追跡可能であり、オフライン環境では固定されたルートと有効期限が制限されたバンドルを使用します。
ステップごとの詳細解説
ステップ 1: 信頼境界と脅威のマッピング
ソース管理、依存関係の解決、ビルド構成、ランナー、レジストリ、発行者、デプロイコントローラーをリストアップします。攻撃者は依存関係を変更したり、ランナーの認証情報を盗んだり、タグを付け替えたり、クレームを偽造したり、古い証拠をリプレイしたりする可能性があります。証明すべき主張は、どの信頼できるビルダーがどの入力からどのダイジェストを生成したかということです。来歴は、コードに脆弱性がないことを証明するものではありません。
ステップ 2: 来歴とアーティファクトのバインディングの定義
ソースリビジョン、ビルダーアイデンティティ、エントリポイント、ロックされた依存関係、パラメータ、ステップのダイジェスト、ビルド時間、出力ダイジェストを含めます。ダイジェストは認可キーであり、タグは検出のためのエイリアスにすぎません。フィールドの意味が暗黙のうちに変更されないように、クレーム、署名、決定にスキーマバージョンを記録します。
artifact_digest -> provenance_digest -> signature -> log_entry
policy_version + identity + builder + time_window -> admission_decisionステップ 3: 発行と透明性の設計
ビルダーはクレームを送信します。発行者はワークフローアイデンティティとクレームの形状を検証し、署名するか、検証可能なバンドルを返します。署名されたペイロードは、アーティファクトダイジェストと重要なクレームをカバーしている必要があります。透明性ログは異常な発行を検出するのに役立ちますが、デプロイポリシーを置き換えるものではありません。大量の書き込みは最初に不変ストレージに格納され、ダイジェスト、リポジトリ、アイデンティティごとの非同期インデックスが作成されます。
ステップ 4: デプロイ検証の実装
検証者は不変のダイジェストを解決し、チェーン、信頼のルート、証明書のアイデンティティ、発行者、クレームの整合性、ログの証拠をチェックしてから、ポリシーを適用します。ルールの例としては、最新の依存関係チェックを受けたマネージドランナーからのmainブランチのビルドのみを許可するなどがあります。単なるブール値ではなく、ポリシーバージョンと理由コードを含むallow、quarantine、またはdenyを返します。
ステップ 5: 鍵、アイデンティティ、ランナー侵害の処理
有効期間の短いワークフローアイデンティティ、または対象者(audience)と発行権限が制限されたマネージドキーを優先します。ローテーションによってすべての過去のアーティファクトが無効になってはなりません。古いルートは有効期間と失効期間のために保持します。ランナーが侵害された場合は、そのアイデンティティを失効させ、影響を受けるワークフローを凍結し、関連するクレームにマークを付け、新しいアドミッションをブロックします。環境のリスクに応じて、デプロイ済みアーティファクトを再検証またはロールバックします。
ステップ 6: リプレイ、ロールバック、オフライン検証の対応
クレームにはビルド時間、バージョン、ポリシーウィンドウが含まれます。期限切れまたはダイジェストが一致しない証拠は拒絶します。ロールバックを行う場合でも、古いダイジェストが現在のポリシー、または明示的に互換性のあるポリシーを満たしていることをチェックします。オフライン環境では、ルート、失効スナップショット、バンドルを事前ロードし、スナップショットの経過時間を記録します。期限切れのスナップショットの場合は、現在の検証が行われたかのように見せかけるのではなく、デプロイを隔離します。
ステップ 7: キャパシティ、保持期間、障害モードの見積もり
アーティファクトの量、平均クレームサイズ、署名書き込み数、検証QPS、デプロイのバーストを見積もります。クレームは安価な不変ストレージに保持し、最近のダイジェストはホットインデックスに保持します。発行がダウンしている場合は、新しいアーティファクトを停止または隔離します。検証がダウンしている場合、本番環境はフェイルクローズ(fail-closed)になります。低リスク環境では、明示的な例外レコードを伴う、事前に承認された短いキャッシュウィンドウを使用する場合があります。
ステップ 8: オブザーバビリティとマイグレーションの追加
不要なソースやシークレットを保存することなく、ダイジェスト、ポリシーバージョン、信頼のルートバージョン、理由コード、レイテンシを記録します。来歴のカバレッジ、署名の失敗、アイデンティティの異常、ポリシーの拒否、キャッシュヒット、ログ遅延、失効したランナーを監視します。段階的なロールアウトの前に、ポリシーのアップグレードをシャドウテストします。すべての拒否はリプレイ可能で説明可能である必要があります。
質の高い模範解答
私はシステムを、ビルド証拠、発行と透明性、デプロイ検証、アドミッションポリシーに分割します。ビルダーは、ソースリビジョン、依存関係、パラメータ、ビルダーアイデンティティ、出力ダイジェストをバインドする来歴を生成します。発行者はワークフローアイデンティティを検証し、署名を不変のダイジェストにバインドしてイベントを記録します。デプロイの前に、検証者はチェーン、証明書アイデンティティ、発行者、クレームの整合性、信頼のルート、タイムウィンドウ、ポリシーバージョンをチェックし、説明可能なallow、quarantine、またはdenyを返します。タグが認可を与えることは決してありません。短期間のアイデンティティ、マネージドランナー、キーローテーション、および失効によって認証情報のリスクに対処します。オフライン環境では、有効期限が制限されたルート、失効スナップショット、およびバンドルを使用します。クレームはダイジェストインデックス付きの不変ストレージに保存されます。障害時は、完全なポリシーおよび決定の証拠とともに、環境に応じてフェイルクローズ、隔離、または制限付きキャッシュを使用します。
よくある間違い
- 可変なイメージタグにのみ署名すること。
- アイデンティティ、発行者、クレームのチェックを行わずに、数学的な署名の有効性のみを検証すること。
- SBOM、来歴、署名、脆弱性スキャンを1つのフィールドに統合してしまうこと。
- すべてのCIランナーを信頼し、失効の影響範囲(blast radius)を無視すること。
- すべての履歴を無効にする方法でキーをローテーションしたり、失効したアイデンティティを永久に受け入れたりすること。
- 検証機能が利用できないときに常にフェイルオープンにしてしまうこと。
- ポリシーバージョン、理由コード、またはリプレイ可能な証拠を持たずに、合否のみを保持すること。
フォローアップの質問と回答
ビルダーがクレームで嘘をついていないことをどのように証明できますか?
来歴は、信頼できるビルドプロセスが何を主張したかを証明するものであり、すべてのステップが正直であったことを証明するものではありません。分離されたビルダー、最小権限、再現可能または比較可能なビルド、独立したログ、ポリシーの制約によって前提条件を減らします。リスクの高いアーティファクトには、セカンドパーティによるレビューや追加の構成証明(アテステーション)を要求できます。
レジストリが侵害された場合はどうなりますか?
ダイジェストによってデプロイし、署名を検証します。タグやレジストリのメタデータを変更しても、署名されたダイジェストは変更されません。証拠とバンドルは独立した不変ストレージに保持します。新しいリリースを凍結し、ログエントリとダイジェストを比較し、影響を受けたアイデンティティを失効させ、インシデント後にデプロイ済み環境を再検証します。
複数のビルダーやベンダーをどのようにサポートしますか?
GitHub Actions、セルフホストランナー、ベンダービルダーに対して、単一のクレームスキーマとアイデンティティマッピング層を使用します。アダプターがクレームを正規化し、単一の検証者がダイジェスト、アイデンティティ、時間、ポリシーを引き続きチェックします。ベンダーに個別のバイパスルールを与えるべきではありません。
検証によってリリースが遅くなるとチームから苦情が出ています。どのようなトレードオフを行いますか?
まず、検証のレイテンシ、キャッシュヒット、失敗の理由を測定します。信頼境界を下げることなく、インデックスと並行読み取りを最適化します。低リスク環境には監査可能な短いキャッシュを提供し、本番環境では強力な検証を維持し、シャドウモードを使用してポリシーの誤りと実際の欠陥を区別します。すべての例外には、所有者、有効期限、自動クリーンアップが必要です。