<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>DevSecOps on AI2CORE - AI技術ブログ</title>
    <link>https://www.ai2core.com/tags/devsecops/</link>
    <description>Recent content in DevSecOps on AI2CORE - AI技術ブログ</description>
    <generator>Hugo -- 0.146.4</generator>
    <language>ja</language>
    <lastBuildDate>Sat, 28 Feb 2026 13:30:00 +0900</lastBuildDate>
    <atom:link href="https://www.ai2core.com/tags/devsecops/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>GitHub Actionsセルフホストランナー防衛術：CI/CDの供給網リスクを減らす実装ガイド</title>
      <link>https://www.ai2core.com/posts/2026-02-28-github-actions-selfhosted-runner-security/</link>
      <pubDate>Sat, 28 Feb 2026 13:30:00 +0900</pubDate>
      <guid>https://www.ai2core.com/posts/2026-02-28-github-actions-selfhosted-runner-security/</guid>
      <description>セルフホストランナー運用で発生する主要リスクを洗い出し、実装可能な防御策を段階的に紹介。</description>
      <content:encoded><![CDATA[<h1 id="github-actionsセルフホストランナー防衛術cicdの供給網リスクを減らす実装ガイド">GitHub Actionsセルフホストランナー防衛術：CI/CDの供給網リスクを減らす実装ガイド</h1>
<p>セルフホストランナーは高速で柔軟です。特定ツールチェーンや社内ネットワーク接続が必要な環境では、ほぼ必須といえます。一方で、設定を誤ると CI/CD が攻撃経路になります。</p>
<p>近年のインシデントでは、依存パッケージ汚染だけでなく「Actions workflow の権限過多」「fork 由来PRでの秘密情報流出」「ランナー残存データ」が問題化しています。</p>
<p>本記事では、セルフホストランナーを安全に運用するための防衛策を、設計レイヤごとに整理します。</p>
<h2 id="脅威モデルを先に定義する">脅威モデルを先に定義する</h2>
<p>まず守る対象を明確にします。</p>
<ul>
<li>リポジトリのソースコード</li>
<li>Secrets（クラウド鍵、署名鍵、トークン）</li>
<li>配布物の完全性（改ざん防止）</li>
<li>社内ネットワーク接続経路</li>
</ul>
<p>攻撃経路は主に次です。</p>
<ol>
<li>悪意ある PR が workflow を悪用</li>
<li>Marketplace Action の supply chain 汚染</li>
<li>ランナー上に残る credential / build artifact</li>
<li>過剰な <code>GITHUB_TOKEN</code> 権限</li>
</ol>
<p>この4点を潰す設計が防御の中心になります。</p>
<h2 id="1-ランナーは使い捨てを前提にする">1. ランナーは「使い捨て」を前提にする</h2>
<p>長寿命ランナーは便利ですが、攻撃後の残留リスクが高いです。可能ならジョブ単位で破棄できる ephemeral 構成を採用します。</p>
<ul>
<li>Kubernetes + Actions Runner Controller</li>
<li>VMテンプレートから都度起動</li>
<li>ジョブ終了後に完全破棄</li>
</ul>
<p>少なくとも <code>/tmp</code> と workspace を確実に消去し、Docker layer cache の共有範囲を制御してください。</p>
<h2 id="2-workflow-権限を最小化する">2. workflow 権限を最小化する</h2>
<p><code>permissions: write-all</code> は禁止レベルです。workflowごとに最小権限を明記します。</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
<table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3
</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">permissions</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">contents</span>: <span style="color:#ae81ff">read</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">pull-requests</span>: <span style="color:#ae81ff">write</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">id-token</span>: <span style="color:#ae81ff">write</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>特に <code>id-token: write</code> は OIDC 連携に必要ですが、不要ジョブで許可しないこと。権限漏れがクラウド侵害に直結します。</p>
<h2 id="3-fork-pr-の実行ポリシーを分離する">3. fork PR の実行ポリシーを分離する</h2>
<p>外部 fork からの PR で secrets を使うジョブを実行しない設計が必須です。</p>
<p>推奨:</p>
<ul>
<li><code>pull_request</code> イベント: テストのみ、secrets 無し</li>
<li><code>pull_request_target</code>: 原則禁止、必要なら厳格レビュー</li>
<li>デプロイ系は <code>push</code>（保護ブランチ）だけ</li>
</ul>
<p>また、<code>workflow_run</code> を使って「検証済み成果物だけを次段へ渡す」2段構成にすると安全性が上がります。</p>
<h2 id="4-action-の固定と検証">4. Action の固定と検証</h2>
<p><code>uses: actions/checkout@v4</code> のようなタグ指定だけでは、将来更新の影響を受けます。高リスク工程では commit SHA 固定を検討します。</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">
<table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>- <span style="color:#f92672">uses</span>: <span style="color:#ae81ff">actions/checkout@8ade135a...</span> <span style="color:#75715e"># SHA pin</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>加えて、許可済み Action の allowlist を組織ポリシー化します。無制限に Marketplace Action を使わせると監査不能になります。</p>
<h2 id="5-secrets-管理は-oidc-中心へ">5. Secrets 管理は OIDC 中心へ</h2>
<p>長期固定鍵を GitHub Secrets に置く運用は、漏洩時の被害が大きいです。クラウド連携は OIDC フェデレーションに移行し、短命トークンを発行します。</p>
<p>利点:</p>
<ul>
<li>鍵配布不要</li>
<li>期限短い</li>
<li>リポジトリ/ブランチ条件で絞れる</li>
</ul>
<p>AWS なら role trust policy に <code>sub</code> 条件を入れ、「main ブランチの release workflow だけ許可」といった制御が可能です。</p>
<h2 id="6-ネットワーク分離と出口制御">6. ネットワーク分離と出口制御</h2>
<p>セルフホストランナーが社内フラットネットワークに直結している構成は危険です。ランナー専用サブネットを作り、次を実施します。</p>
<ul>
<li>egress allowlist（必要ドメインのみ）</li>
<li>社内DBへの直接接続禁止</li>
<li>管理プレーンと実行プレーン分離</li>
</ul>
<p>「CIだから社内に近いほど便利」は短期的発想です。侵害前提で最小到達範囲に設計します。</p>
<h2 id="7-監査ログと改ざん検知">7. 監査ログと改ざん検知</h2>
<p>必要なログ:</p>
<ul>
<li>workflow 実行者</li>
<li>使用ランナーID</li>
<li>取得したクラウド権限</li>
<li>成果物ハッシュ</li>
</ul>
<p>さらに、リリース成果物に SBOM と署名（cosign / sigstore）を付与し、配布前検証を自動化します。これで supply chain の追跡性が大きく向上します。</p>
<h2 id="8-実装チェックリストそのまま使える">8. 実装チェックリスト（そのまま使える）</h2>
<ul>
<li><input disabled="" type="checkbox"> セルフホストランナーは ephemeral 運用</li>
<li><input disabled="" type="checkbox"> workflow permissions を最小権限化</li>
<li><input disabled="" type="checkbox"> fork PR と deploy workflow を分離</li>
<li><input disabled="" type="checkbox"> 高リスク Action は SHA pin</li>
<li><input disabled="" type="checkbox"> OIDC による短命認証へ移行</li>
<li><input disabled="" type="checkbox"> ネットワーク egress 制限</li>
<li><input disabled="" type="checkbox"> artifact 署名と SBOM 生成</li>
<li><input disabled="" type="checkbox"> 監査ログを90日以上保持</li>
</ul>
<h2 id="9-段階導入プラン4週間">9. 段階導入プラン（4週間）</h2>
<ul>
<li>Week1: 権限棚卸し、<code>write-all</code> 排除</li>
<li>Week2: fork PR ポリシー分離、allowlist導入</li>
<li>Week3: OIDC移行、固定鍵削減</li>
<li>Week4: ephemeral runner 化、署名/SBOM実装</li>
</ul>
<p>一気に変えると運用停止リスクがあるため、週単位で区切るのが現実的です。</p>
<h2 id="まとめ">まとめ</h2>
<p>セルフホストランナーは強力ですが、セキュリティ設計を誤ると CI/CD が最も危険な入口になります。ポイントは「最小権限」「使い捨て」「短命認証」「監査可能性」の4つです。</p>
<p>まずは <code>permissions</code> の最小化と fork PR 分離から始めてください。ここを押さえるだけでも、供給網リスクは大幅に下げられます。</p>
<h2 id="実運用での検知ルール例siem連携">実運用での検知ルール例（SIEM連携）</h2>
<p>防御策を実装しても、検知が弱いと侵害を見逃します。次のイベントを SIEM 側で高優先度アラート化してください。</p>
<ul>
<li>深夜帯の workflow 権限変更</li>
<li>普段使わないランナーラベルでのジョブ実行</li>
<li>release workflow で未知の Action 呼び出し</li>
<li>OIDC 経由で想定外クラウドロールを取得</li>
</ul>
<p>検知時には自動で <code>repository dispatch</code> を使い、該当リポジトリのデプロイを一時停止する仕組みを入れると被害拡大を防げます。</p>
<h2 id="インシデント対応runbookの最小構成">インシデント対応Runbookの最小構成</h2>
<p>供給網インシデントは初動が遅れると致命傷になります。Runbook には最低限次を含めます。</p>
<ol>
<li>影響範囲特定（対象リポジトリ、workflow、artifact）</li>
<li>該当 Secrets/Role の無効化</li>
<li>ランナー群の全廃棄と再構築</li>
<li>直近リリース成果物のハッシュ再検証</li>
<li>監査ログ保全と関係者通知</li>
</ol>
<p>この手順を平時に演習しておくことで、実際の障害時に迷いを減らせます。</p>
<h2 id="組織導入で効くポリシー">組織導入で効くポリシー</h2>
<ul>
<li>新規 workflow はセキュリティレビュー必須</li>
<li>Action 追加時はリスク評価テンプレート提出</li>
<li>重要リポジトリは branch protection + required review を強制</li>
<li>セルフホストランナーの管理責任者を明確化</li>
</ul>
<p>技術対策だけでは継続しません。責任分界とレビュー手順を運用ルール化することが、防御の持続性を高めます。</p>
<h2 id="まとめ運用視点">まとめ（運用視点）</h2>
<p>最終的に重要なのは「侵害されないこと」ではなく「侵害されても被害を限定し、速く復旧できること」です。セルフホストランナーを使うなら、最初からゼロトラスト前提で設計し、検知・対応まで含めた体制を整えてください。</p>
<h3 id="最後に">最後に</h3>
<p>現場では「便利だから後で固める」が最も危険です。セルフホストランナーは導入初日から最小権限と隔離を前提に設計し、定期監査で逸脱を戻す運用を続けてください。</p>
<h3 id="追加の運用tip">追加の運用Tip</h3>
<p>新しいリポジトリを作るたびに同じ議論をしないため、テンプレートリポジトリへ安全な workflow 雛形を同梱しておくと効果的です。初期状態を安全側に固定するだけで、運用負荷と事故率の両方を下げられます。</p>
<p>継続的な棚卸しを習慣化してください。</p>
]]></content:encoded>
      <category>Tech</category>
      <category>GitHub Actions</category>
      <category>Security</category>
      <category>CI/CD</category>
      <category>DevSecOps</category>
    </item>
  </channel>
</rss>
