コンテンツへスキップ
Latchkey
無料で始める
ドキュメントメニュー

セキュリティアーキテクチャ

LatchkeyがすべてのCIジョブをどのように隔離するか: 専用の使い捨て仮想マシン、インバウンドネットワークなし、エフェメラルな認証情報、保存時および転送中の暗号化、そしてセルフヒーリングエージェントが動作する際の制約。

このページはセキュリティレビュー向けに書かれています。ランナープラットフォームが実際にどのように構築されているか、つまり隔離境界、マシンから外部に出るもの、認証情報の取り扱い方、そしてセルフヒーリングエージェントに許可されていること・いないことを説明します。GitHub Appがあなたのリポジトリで読み取り・書き込みできる内容については、セキュリティとGitHubの権限を参照してください。

1
仮想マシンあたりのジョブ数
終了後に破棄されます
0
インバウンドネットワークルール
ランナーは接続を一切受け付けません
1
許可されたsudoパターン
セルフヒーリングエージェント向け
14d
ビルドキャッシュの保持期間
失敗ログは90日間

隔離: 1ジョブ、1マシン#

Latchkeyはジョブ間でマシンを共有しません。各ジョブは、そのジョブのために起動された専用のEC2仮想マシン(m6aクラス、Ubuntu 24.04 LTS)上で実行されます。あなたのジョブは、他のテナントとカーネルを共有するコンテナではなく、長期稼働する共有ホスト上のプロセスでもありません。

単一使用は慣習によってではなく、GitHubの登録レイヤーで強制されます。コールドスタートのランナーはジャストインタイム構成で登録され、GitHubはこれを正確に1つのジョブに対してのみ受け入れます。ウォームプールのランナーは --ephemeral フラグで登録され、同じ動作になります。いずれの場合も、インスタンスはシャットダウン時に終了するよう構成されているため、何らかの問題が発生しても再利用されることはありません。

境界どのように強制されるか
マシンあたり1ジョブGitHubのジャストインタイム構成(コールドスタート)または --ephemeral 登録(ウォームプール)
マシンは再利用できないインスタンス起因のシャットダウン動作が終了(terminate)に設定されています。起動テンプレートと直接起動パスの両方で設定されています
ディスクは残らないルートEBSボリュームは暗号化され、終了時に削除(delete-on-termination)としてマークされています
暴走したジョブは回収されるクリーンアッププロセスが、4時間のジョブ上限(ハードキャップは8時間)を超えたインスタンスを終了させます
ランナーは1つのworkspaceに紐付くインスタンスには組織IDがタグ付けされ、単一の組織ランナーグループに登録されます
01起動専用のEC2インスタンスが特定の1ジョブのために起動します
02登録ジャストインタイム構成。正確に1つのジョブに対してのみ有効です
03一度だけ読み取りランナーは認証情報を取得し、直ちにそれを削除します
04実行あなたのジョブがマシン上で単独で実行されます
05終了インスタンスがシャットダウンします。シャットダウン動作は終了(terminate)です
06破棄暗号化されたルートボリュームがインスタンスとともに削除されます

ランナーグループは visibility: selected と明示的なリポジトリリストで作成されるため、あなたのworkspace向けに登録されたランナーには、有効化したリポジトリのジョブのみが割り当てられます。

何がrootとして動作し、なぜそれが封じ込められているのか#

自身のVM内では、あなたのジョブは完全な制御権を持ちます: runner ユーザーはパスワードなしのsudoとDockerアクセスを持ちます。これはCIとしては通常のことであり(ビルドはパッケージをインストールし、コンテナを実行します)、そして安全である理由はまさに、影響範囲がインバウンドネットワークを持たず、ジョブの終了時に破棄される短命なマシン1台に限られているからです。存在しないサンドボックスをほのめかすよりも、これを率直に述べることを選びます。

ネットワーク#

ロックダウンされているもの

  • ランナーはパブリックIPアドレスを持たないプライベートサブネットに起動されます
  • ランナーのセキュリティグループにはイングレスルールがゼロです: インターネット上のいかなるものもランナーへの接続を開くことはできません
  • IMDSv2が必須であり、ホップ制限が1に設定されているため、ブリッジネットワークのコンテナがホスト経由でインスタンスの認証情報に到達することはできません
  • 内部のAWSトラフィックは、パブリックインターネットではなくVPCのゲートウェイエンドポイントおよびインターフェースエンドポイントを使用します
  • WAF(レート制限、AWS Common Rule Set、Known Bad Inputs)がWebアプリケーションの前段に配置されています

ビルドが依然として到達できるもの

  • アウトバウンドトラフィックは開放されています。CIはnpm、PyPI、Docker Hub、あなたのクラウド、そしてあなた自身のサービスに到達する必要があるためです
  • ジョブに公開したシークレットは、そのジョブから到達可能であると考えてください: GitHubホストランナーと同じモデルです

認証情報とシークレット#

ランナーの認証情報はジョブごとに発行されます

ジャストインタイムのランナー構成が単一のジョブ用に生成され、暗号化されたSecureStringとしてAWS Systems Manager Parameter Storeに書き込まれます。スコープはそのインストールとジョブに限定されます。

ランナーは一度読み取り、その後削除します

起動時にインスタンスはそのパラメーターを取得し、鍵素材を含むため直ちに削除します。同じパターンがウォームプールの登録トークンにも適用され、これらは利用可能な55分間のみキャッシュされます。

GitHubへのアクセスは短命です

GitHub Appは秘密鍵でJWTに署名し、操作ごとに短命なインストールアクセストークンと交換します。ランナー上に長期間有効なGitHubトークンが置かれることはありません。

プラットフォームのシークレットはランナーから隔離されています

GitHub Appの秘密鍵はParameter StoreにSecureStringとして保存されます。ランナーが読み取れるシークレットは意図的に最小限であり、プラットフォーム構成のシークレットとは分離されているため、侵害されたインスタンスロールがプラットフォームの認証情報を読み取ることはできません。

デプロイはGitHub OIDCによるロール引き受けでAWSに認証します。CIに長期間有効なAWSアクセスキーは存在しません。MCP連携用のAPIキーはSHA-256ハッシュとしてのみ保存され、平文のキーは作成時に一度だけ表示され、永続化されることはありません。

暗号化#

データ保存時転送中
ランナーのルートディスク暗号化されたEBS(gp3)、終了時に削除該当なし
ビルドキャッシュ(S3)SSE-S3(AES-256)、14日で失効TLS
アプリケーションデータベース暗号化されたストレージ、パブリックにアクセス不可TLS
キャッシュ / キューレイヤー保存時および転送中の暗号化を有効化TLS
ランナー構成とアプリの鍵Parameter StoreのSecureStringTLS
APIトラフィック該当なしAPIドメインでTLS 1.2以上

ビルドキャッシュの隔離#

キャッシュオブジェクトは、あなたの組織IDから導出されたキープレフィックスの下にS3へ保存され、テナントIDはジョブリクエストからコントロールプレーンによって注入されます: ジョブが環境変数を設定して別のテナントを名乗ることはできません。オブジェクトは14日後に失効します。

ランナーから外部に出るもの#

2種類のデータがマシンから外部に出ます。2つ目については正確に述べる価値があります。

  • 実行およびジョブのメタデータ: 名前、タイミング、ステータス、ラベル、そしてワークフローYAML。これらが分析機能と最適化機能を支えます。
  • 失敗したステップの出力。 ステップが失敗すると、セルフヒーリングのパイプラインがそのステップの標準出力と標準エラー(それぞれ最大1 MiB)を取得して保存し、失敗の診断と、必要に応じた修正案の作成に使用できるようにします。保持期間は90日です。

セルフヒーリングエージェントに課された制約#

セルフヒーリングは、実行中のジョブを変更する唯一のコンポーネントであるため、レビュアーが最も強く精査すべき部分です。ここでは、それが何をできるのかを正確に説明します。

  • systemdサービスとして、rootではなく runner ユーザーで動作します。
  • グループに制限されたパーミッションを持つUnixドメインソケットでリッスンします。TCPリスナーもネットワーク面の攻撃対象もありません。
  • ランナーエージェント自身のステップスクリプトのみを横取りするシムを介して呼び出されます。それ以外のコマンドはすべて、手を加えられずにそのまま通過します。
  • フェイルオープンします: エージェントがタイムアウト、拒否、またはエラーになった場合、コマンドはLatchkeyがない場合とまったく同じように実行されます。壊れたヒーラーがあなたのビルドを壊すことはできません。

実行できる特権操作はフィルタリングではなく、許可リスト方式です:

制御その意味
sudo許可リスト許可されるのはアンカーされたパターン1つだけです: 単一パッケージの非対話的な apt-get install です。sudo で始まるそれ以外のものは、プロセスが生成される前に拒否されます。
パッケージ許可リストインストール可能なパッケージはコンパイル時のリストから取られ、2つの段階で独立して強制されます。一方の段階は信頼できないビルド出力からコマンドを組み立てるためです。
環境の安全下限LD_PRELOADLD_LIBRARY_PATHPATHBASH_ENVENV の設定は拒否されます。シェルのメタ文字とコマンド置換も同様です。
機密パスの拒否/etc/root/proc/sys/var/log~/.ssh~/.aws~/.config/gh 配下の読み取りは拒否されます。
AIツールのサンドボックスステージ3のツールは、bubblewrapベースのサンドボックス内で実行されます。このサンドボックスはデフォルト拒否(ネットワークなし、書き込みパスなし)から始まり、ツールごとに必要最小限の範囲まで緩和されます。
常駐AIキーなし推論ステップはインスタンスロールを介してAWS Bedrockに認証するため、あなたのコードを実行するマシン上に長期間有効なモデルAPIキーが置かれることはありません。
キルスイッチセルフヒーリングはworkspaceごとに無効化できます。

GitHub Appがアクセスできるもの#

以下のすべての権限は、特定の機能を支えるために存在します。付与の理由がすぐ隣で分かるよう、フラットなリストではなく用途ごとにグループ化しています。

目的アクセス権限
Latchkeyランナーでジョブを実行する読み取りと書き込み組織のセルフホストランナー、管理、組織管理
パイプラインが何をしたかを確認する読み取りActions、アーティファクトのメタデータ、メタデータ
ジョブの発生に応じて反応する読み取りと書き込み組織のフック、リポジトリのフック
ワークフローを読み取り、修正をPRとして提案する読み取りと書き込みワークフロー、コード、プルリクエスト
GitHubのコストを正確にモデル化する読み取り組織のプラン
組織のメンバーを確認する読み取りメンバー
セキュリティの検出結果をダッシュボードに表示する読み取りDependabotアラート、シークレットスキャンのアラート、セキュリティイベント、Dependabotのシークレット
あなたのスタックに合わせたランナーイメージをビルドする読み取り組織のランナーカスタムイメージ

リポジトリへの変更#

Latchkeyがデフォルトブランチにプッシュすることは決してありません。すべての変更はあなたがレビューするプルリクエストであり、書き込み経路は3つの方法でゲートされています:

  1. ファイルパスは、リポジトリごとのマニフェストに照らして編集可能と解決される必要があります。一致しないパスはデフォルトで編集不可となります: このチェックはフェイルクローズです。
  2. フォークを起点とするプルリクエストは拒否されます。また、フォークかどうかのシグナルが欠落している場合も、安全であると仮定せずに拒否されます。
  3. 提案された修正は、取得済みのログ内の失敗シグネチャと一致する必要があり、一致しない場合は抑制されます。

運用上のセキュリティ#

  • ランナーイメージは毎週再ビルドされるため、OSのセキュリティパッチが計画的にフリートへ適用されます。
  • ランナーのインスタンスロールは最小権限であり、AWSマネージドポリシーのアカウント全体にわたるParameter Storeへのアクセスを、Latchkey自身のランナーパスに絞り込む明示的な拒否を含みます。
  • 変更を伴うすべての管理操作は、操作者、アクション、対象、パラメーター、結果とともに監査ログに記録されます。
  • ダッシュボードとAPIへのアクセスは、APIゲートウェイのJWTオーソライザーによって認証されます。workspaceのロールはOwner、Admin、Memberであり、オーナーは削除や降格から保護されています。

データの保持#

Latchkeyが保存するものと、その保持期間です。

データ保持期間
ランナー上のあなたのソースコードジョブ終了時にインスタンスとともに破棄されます
ビルドキャッシュのオブジェクト最終書き込みから14日
診断のために取得された失敗ステップの出力90日
セルフヒール試行の記録90日
修正案の記録365日
ダッシュボードを支える実行およびジョブのメタデータリポジトリが有効なままである間、保持されます

リポジトリを無効化すると、そのリポジトリの収集が停止します。workspaceを削除すると、そのデータが削除されます。組織として特定の保持期間が必要な場合は、お問い合わせいただければご相談に応じます。

脆弱性の報告#

security@latchkey.dev までメールでご連絡ください。セキュリティ報告のためにパブリックなGitHub issueを作成しないでください。

ジョブの後、ソースコードはランナー上に残りますか?

いいえ。ジョブが終了すると、インスタンスとその暗号化されたルートボリュームは破棄されます。明示的に利用を選択したビルドキャッシュのエントリ(14日後に失効します)を除き、チェックアウトしたものは何も残りません。

他の顧客のジョブが自分のジョブを見ることはできますか?

いいえ。各ジョブは独自の仮想マシン上で実行され、単一のworkspaceに登録され、その1つのジョブの後に破棄されます。ランナーにはインバウンドのネットワークアクセスがありません。

セルフヒーリングエージェントは、自分のビルド上で任意のコマンドを実行できますか?

いいえ。特権的なアクションはフィルタリングではなく許可リスト方式です: 許可されたsudoパターンは1つのみ、パッケージリストは固定、コード注入を可能にする環境変数は拒否、AIツールのステージはデフォルト拒否のサンドボックスです。エージェントが何らかの理由で失敗した場合、あなたのコマンドはエージェントがない場合とまったく同じように実行されます。

自分のビルドのシークレットはLatchkeyから見えますか?

いいえ。あなたのGitHub Actionsのシークレットは、GitHubホストランナーの場合とまったく同じように、実行時にGitHubによってジョブへ直接注入されます。Latchkeyがその値を要求したり保存したりすることは決してありません。GitHubは、ログ出力が当社に届く前に、登録済みのシークレットをマスクします。

References