ドキュメントメニュー
はじめに
ダッシュボードと分析
マネージドランナー
- ランナーの概要
- 最初のジョブを実行する
- GitHub ホステッドからの移行
- Runners ページ
- カスタムランナー (AI Scan)
- 自己修復
- ランナーイメージとソフトウェア
- プロビジョニングとウォームプール
- 上限と同時実行数
キャッシュ
チームと通知
請求とプラン
ヘルプ
セキュリティアーキテクチャ
LatchkeyがすべてのCIジョブをどのように隔離するか: 専用の使い捨て仮想マシン、インバウンドネットワークなし、エフェメラルな認証情報、保存時および転送中の暗号化、そしてセルフヒーリングエージェントが動作する際の制約。
このページはセキュリティレビュー向けに書かれています。ランナープラットフォームが実際にどのように構築されているか、つまり隔離境界、マシンから外部に出るもの、認証情報の取り扱い方、そしてセルフヒーリングエージェントに許可されていること・いないことを説明します。GitHub Appがあなたのリポジトリで読み取り・書き込みできる内容については、セキュリティとGitHubの権限を参照してください。
隔離: 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がタグ付けされ、単一の組織ランナーグループに登録されます |
ランナーグループは 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のSecureString | TLS |
| 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_PRELOAD、LD_LIBRARY_PATH、PATH、BASH_ENV、ENV の設定は拒否されます。シェルのメタ文字とコマンド置換も同様です。 |
| 機密パスの拒否 | /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つの方法でゲートされています:
- ファイルパスは、リポジトリごとのマニフェストに照らして編集可能と解決される必要があります。一致しないパスはデフォルトで編集不可となります: このチェックはフェイルクローズです。
- フォークを起点とするプルリクエストは拒否されます。また、フォークかどうかのシグナルが欠落している場合も、安全であると仮定せずに拒否されます。
- 提案された修正は、取得済みのログ内の失敗シグネチャと一致する必要があり、一致しない場合は抑制されます。
運用上のセキュリティ#
- ランナーイメージは毎週再ビルドされるため、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は、ログ出力が当社に届く前に、登録済みのシークレットをマスクします。