使い捨て公開 runner¶
公開用 runner は、ジョブごとに新しい QEMU/KVM 仮想マシンを使います。
PR 用 Docker runner とは別であり、それ自体はタグや Release を公開しません。
Issue #988 の実装の一部です。
イメージ作成、ゲスト内の開始前チェック、単一ジョブの起動処理を提供します。
常駐サービスの設置や日次公開の有効化は行いません。
手動実行だけの rc.yml は読み取り権限でゲストの判定記録を確認します。
checkout、第三者 Action、公開ステップはありません。実行指示と runner 登録は
別途承認する運用操作です。
作成と確認¶
KVM を利用できる Linux、Python 3.11 以降、QEMU、qemu-img、
cloud-localds、-N 対応の OpenBSD nc、setpriv、memory と process の
cgroup 制御を利用できる systemd user manager が必要です。実行ファイルは root 所有で、一般ユーザーが
書き換えられない経路から解決します。Python は継承した loader 環境変数なしで起動できる
必要があります。LD_LIBRARY_PATH に依存する toolcache の Python は VM 起動前に拒否します。
ネイティブ Linux ストレージにイメージの
専用コピーと 20 GiB のゲストディスクを置ける空き領域を用意します。
VM は 2 vCPU、4 GiB RAM を使います。実ジョブの実行時は PC の起動と通信が必要です。
QEMU 起動前に、一時的な user scope 内で非 root の全 UID、capability がゼロ、
no-new-privileges、最大 128 タスク、合計 6 GiB メモリ、swap 無効を確認します。
この上限には proxy 子プロセスも含みます。ゲスト RAM は QEMU の core dump から除外します。転送に必要な setsid を許すため、
proxy 利用時の QEMU の権限 syscall 制限は、検証済みの OS 制約で補います。
ゲストの 2 vCPU はホスト全体の CPU 使用量上限ではありません。ホストの実行ユーザーと
QEMU は信頼境界の内側であり、侵害された QEMU から同じユーザーのファイルを隔離する
仕組みではありません。
python3 scripts/build_release_vm.py --output /absolute/new/release.qcow2
python3 scripts/release_vm.py --image /absolute/new/release.qcow2 \
--image-sha256 IMAGE_DIGEST --workflow-sha ACCEPTED_WORKFLOW_COMMIT
scripts/smoke_release_vm_network.py --image IMAGE --image-sha256 DIGEST は
一時的なループバック HTTP サーバーを使い、認証情報なしのゲストで通信を試します。
指定した proxy 経路だけが通り、ホストやインターネットへの直接接続が拒否されることを
確認します。
作成結果の JSON にあるイメージ、Ubuntu ベース、runner、チェック処理、 起動処理のダイジェストを保存し、その成果物を登録前にレビューします。 日付指定の Ubuntu ベースと runner アーカイブをハッシュで検証し、依存パッケージは 日付指定の Ubuntu snapshot から入れます。毎回同一バイト列のイメージになるという 保証ではなく、作成したイメージそのもののハッシュを起動時の識別子とします。
通常の起動は認証情報なしの動作確認です。GitHub への登録は行いません。 許可・拒否の入力をゲスト内で試し、権限を落とした runner ユーザーでチェックを 実行し、証拠ファイルを書き換えられないことを確認して、停止・破棄します。 実 Actions ジョブ、proxy の可用性、自動公開の成功を証明するものではありません。
別途承認する単一ジョブの起動¶
イメージ、承認済み rc.yml の正確なコミット、proxy を確認した後に使います。
次の操作は GitHub runner の登録を変更するため、その操作の承認が必要です。
python3 scripts/release_vm.py --image /absolute/new/release.qcow2 \
--image-sha256 IMAGE_DIGEST --workflow-sha ACCEPTED_WORKFLOW_COMMIT \
--proxy TRUSTED_PROXY_IPV4:PORT --register-one-job
ホストの既存 gh 認証は JIT 登録とその正確な削除だけに使い、ゲストには
コピーしません。一意の ai-teams-release-INSTANCE 名と公開専用ラベルを使います。
JIT 値は専用の一時ディスクで渡し、コマンド引数やコンソールへ出力しません。
ジョブの GITHUB_TOKEN とその権限は引き続き GitHub と workflow が管理します。
ゲストの通信は QEMU の転送で明示したホスト側 proxy だけに制限します。 通常の外向き通信、ホストの待受ポート、共有ディレクトリ、Docker socket は 与えません。proxy の接続先ポリシーは別途確認します。認証情報のないイメージ作成時 だけは通常の通信を使い、登録済みゲストにはその通信設定を使いません。
ホストが VM・登録・イメージ・workflow・期限を結び付けた証拠を作り、ゲスト内で
root 所有の読み取り専用ファイルとして渡します。runner に sudo 権限はありません。
開始前チェックは、このリポジトリの main 上の rc.yml、承認済み workflow SHA、
schedule または workflow_dispatch、正確な runner 名、初回実行だけを受け入れます。
チェックは一度だけ通過でき、公開権限は与えません。ラベルや外から渡した JSON
だけを隔離の証拠にはしません。
runner v2.336.0 は開始前チェックより先に Action アーカイブを準備します。 拒否するのは workflow のステップ実行であり、未信頼のデータを一切ダウンロード しない保証ではありません。拒否された場合も含め、一つのジョブが終わるたびに ゲスト全体を破棄します。GitHub 側の runner group による制限ではありません。
失敗と復旧¶
一回の起動は VM と登録が各一つ、最長 30 分、出力 4 MiB、ゲストディスク 20 GiB までです。既存の Linux プロセス管理が QEMU と proxy の子プロセスを停止させてから 一時領域を削除します。期限切れ、中断、イメージ不一致、未対応の外部ディスク参照、 古い証拠、ゲストの失敗は成功扱いにしません。登録の削除は既存の runner 管理が担当します。 登録の結果が不明な場合や停止・削除が未確認の場合は、再試行前に正確な状態を 照合してください。不在を推測して新しい登録を作ってはいけません。
常駐化、pilot、live activation は別の段階です。#988 の workflow/provider 検証と 認証情報を分離した 10 窓の試験が終わるまでは、手動公開を維持します。