Contents
GitHub Actions におけるセキュリティスキャンの重要性
CI/CD パイプラインに脆弱性検出を組み込むことで、コードが本番環境へ流入する前に問題点を把握できます。GitHub が提供する Security → Code scanning、Dependabot alerts、Secret scanning といった標準機能は、プルリクエスト単位で自動的に結果を可視化し、開発フローへの介入コストを最小限に抑える設計となっています。ここでは、スキャン導入のメリットと、実務で直面する典型的な課題について概観します。
標準機能が提供する保護レイヤー
GitHub の組み込み機能は以下の3点でプロジェクトを守ります。
- コード解析 – CodeQL がプルリクエスト作成時に自動実行し、潜在的なバグや脆弱性を SARIF 形式で Checks に表示。
- 依存関係の監視 – Dependabot が
pom.xml・package.jsonなどを定期走査し、新たな CVE を検出したら PR を自動生成。 - シークレット漏洩防止 – Secret scanning がリポジトリ内にハードコーディングされた認証情報をリアルタイムで警告。
これらの機能だけでも基本的な保護は実現できますが、コンテナイメージや IaC(Infrastructure as Code)まで網羅したい場合は外部ツールとの併用が推奨されます。
スキャナツール選定基準と主要ツール比較
プロジェクトに最適なスキャナを選ぶ際は、言語対応・CI 連携の容易さ・レポート形式・コスト の4軸で評価します。
選定基準(表)
| 基準 | 評価ポイント |
|---|---|
| 言語・プラットフォーム対応 | 対象コード、コンテナイメージ、K8s マニフェストの有無 |
| CI 連携の容易さ | GitHub Actions の公式アクションが提供されているか、設定例が充実しているか |
| レポート形式 | SARIF が出力できれば Checks に自動表示可能。JSON/HTML は別途加工が必要 |
| コスト・ライセンス | 無料枠の上限と有償プランの価格感、商用利用時の制約 |
Trivy の概要
- 対象:Docker イメージ、ファイルシステム、Kubernetes マニフェスト全般。
- メリット:軽量・高速で脆弱性 DB が数分ごとに更新される点が実務向き。公式アクション
aquasecurity/trivy-action@v0が提供されており、format: sarifで直接 GitHub Checks に連携可能。 - 留意点:コードレベルの静的解析は行わないため、CodeQL などと併用する必要がある。
CodeQL の概要
- 対象言語:C/C++、Java、Python、JavaScript、Go など主要言語。
- メリット:GitHub が公式に保守しているので
github/codeql-action/*@v2系列で安定動作。SARIF 出力が標準化されており、PR ごとに詳細な注釈を付与できる。 - 留意点:カスタムクエリの作成や高度なチューニングには学習コストがかかる。
Dependabot・Snyk・OWASP Dependency‑Check の比較
| ツール | 主な機能 | ライセンス | 対応依存関係 |
|---|---|---|---|
| Dependabot (GitHub) | 脆弱性 PR 自動生成、バージョン更新提案 | 無料(GitHub の一部) | npm, Maven, RubyGems, Docker, GitHub Actions など |
| Snyk | 脆弱性データベースと自動パッチ適用、IaC スキャン | 有償プランあり(無料枠あり) | コンテナ、IaC、依存関係全般 |
| OWASP Dependency‑Check | ローカル実行型スキャナー、HTML/JSON レポート生成 | オープンソース | Maven, Gradle, npm, Python 等 |
実践的なワークフロー構築例(Trivy・CodeQL・Dependabot の組み合わせ)
以下は GitHub Actions で イメージスキャン → コード解析 → 依存関係監査 を順次実行し、すべての結果を SARIF 形式で GitHub Checks にアップロードするサンプルです。各ジョブは needs キーワードで明示的に依存関係を定義しています。
ワークフローファイル全体像
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
name: Security Scan on: push: branches: [ main ] pull_request: types: [ opened, synchronize ] # ワークフロー全体の最小権限設定 permissions: contents: read # ソースコードの読み取りのみ許可 security-events: write # SARIF アップロードに必須 packages: read # プライベートレジストリへアクセスする場合 jobs: trivy-scan: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: Build Docker image run: | docker build -t myapp:${{ github.sha }} . # Trivy の公式アクション(バージョン固定)を使用 - name: Scan image with Trivy uses: aquasecurity/trivy-action@v0 with: image-ref: myapp:${{ github.sha }} format: sarif output: trivy-results.sarif - name: Upload Trivy SARIF to GitHub Security uses: github/codeql-action/upload-sarif@v2 with: sarif_file: trivy-results.sarif codeql-analysis: runs-on: ubuntu-latest needs: trivy-scan steps: - name: Checkout repository uses: actions/checkout@v4 - name: Initialize CodeQL uses: github/codeql-action/init@v2 with: languages: javascript,python - name: Run CodeQL analysis uses: github/codeql-action/analyze@v2 with: category: "/language:javascript" output: codeql-results.sarif - name: Upload CodeQL SARIF uses: github/codeql-action/upload-sarif@v2 with: sarif_file: codeql-results.sarif npm-audit: runs-on: ubuntu-latest needs: [trivy-scan, codeql-analysis] steps: - name: Checkout repository uses: actions/checkout@v4 - name: Install dependencies and run npm audit run: | npm ci npm audit --json > npm-audit.json # npm-audit の結果を SARIF に変換(audit2sarif v1.0.0 を利用) - name: Convert npm audit to SARIF run: npx audit2sarif@1.0.0 -i npm-audit.json -o dependabot-results.sarif - name: Upload npm‑audit SARIF uses: github/codeql-action/upload-sarif@v2 with: sarif_file: dependabot-results.sarif |
ポイント
- バージョン固定:
aquasecurity/trivy-action@v0、github/codeql-action/*@v2など、安定版タグを使用して将来的な互換性リスクを回避。 - SARIF 変換ツール:
audit2sarifは npm パッケージとして公式に提供されており、バージョンを明示できるので信頼性が高い。
Trivy ステップのベストプラクティス
| 項目 | 推奨設定 |
|---|---|
| DB キャッシュ | actions/cache@v3 で ~/.cache/trivy をキャッシュし、ダウンロード時間を約2分短縮 |
| スキャン対象 | ローカルでビルドしたイメージをプッシュせずにスキャン(docker run --rm でも可) |
| 脆弱性レベルの絞り込み | --severity HIGH,CRITICAL オプションで重要度の高いものだけをレポート |
CodeQL ステップのベストプラクティス
- 初期化時に
queriesディレクトリを指定し、社内カスタムクエリを同梱できる。 - 分析結果は必ず SARIF で出力し、
upload-sarifアクションだけでチェックランが自動生成されるので追加作業は不要。
npm audit → SARIF 変換ステップの注意点
audit2sarifは Node.js 環境に依存するため、node-versionを明示的に指定すると安定します(例:uses: actions/setup-node@v3)。- 出力ファイル名は
.sarif拡張子で統一し、upload-sarifが正しく検出できるようにする。
シークレット管理と最小権限設定
セキュリティスキャンが外部レジストリやプライベートパッケージへアクセスする場合、シークレットは最小権限で扱うことが重要です。
ワークフローレベルの permissions 設定例
|
1 2 3 4 5 6 |
permissions: contents: read # ソースコード読み取りのみ許可 security-events: write # SARIF アップロードに必要 packages: read # プライベート Docker レジストリからイメージを pull id-token: write # OIDC トークン取得が必要な場合(例:AWS ECR) |
ジョブ単位での権限制御
|
1 2 3 4 5 |
jobs: trivy-scan: permissions: packages: read # Docker Hub の認証情報は不要なら省略 |
このようにジョブごとに権限を絞ることで、万が一アクションが乗っ取られた際の被害範囲を最小化できます。
シークレットの登録例
| シークレット名 | 用途 |
|---|---|
DOCKER_USERNAME |
プライベートレジストリへの認証 |
DOCKER_PASSWORD |
同上(GitHub Secrets に暗号化保存) |
GH_TOKEN |
カスタム API 呼び出しや外部サービス連携時に使用 |
アーティファクトとしての結果保存と可視化
|
1 2 3 4 5 6 7 8 9 |
- name: Upload SARIF reports as artifacts uses: actions/upload-artifact@v3 with: name: security-reports path: | trivy-results.sarif codeql-results.sarif dependabot-results.sarif |
アーティファクトはジョブ完了後に UI から手動で取得でき、外部へ自動転送しなければ情報漏洩リスクは低減します。
チェックランへの自動コメント例(GitHub Script)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
- name: Post summary comment on PR if: failure() uses: actions/github-script@v6 with: script: | const fs = require('fs'); const sarif = JSON.parse(fs.readFileSync('trivy-results.sarif','utf8')); const count = sarif.runs[0].results.length; github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: `🔎 Trivy が ${count} 件の脆弱性を検出しました。詳細は Checks タブをご確認ください。` }); |
スキャン失敗時の制御・キャッシュ活用・トラブルシューティング
必須チェックでマージをブロックする手順
- リポジトリ設定 → Branches → 保護ルール を開く。
- 「Require status checks to pass before merging」を有効化し、
Security Scan (trivy-scan),Security Scan (codeql-analysis)などのチェック名を選択。
これにより、いずれかのスキャンが失敗した PR はマージできません。
ジョブ停止とステータスマネジメント
- デフォルトではジョブがエラーで終了すると
needsがある後続ジョブは自動的に skipped になります。 - 明示的に「失敗時も次のジョブへ」進めたい場合は
continue-on-error: trueを設定し、結果に応じたカスタムロジック(例:Slack 通知)を追加します。
Trivy DB のキャッシュ例
|
1 2 3 4 5 6 7 8 |
- name: Cache Trivy vulnerability database uses: actions/cache@v3 with: path: ~/.cache/trivy key: trivy-db-${{ runner.os }}-${{ hashFiles('**/Dockerfile') }} restore-keys: | trivy-db-${{ runner.os }}- |
キャッシュを有効にすると、毎回 DB をダウンロードする時間(約2分)が削減され、CI の実行コストが低下します。
よくあるエラーと対処法
| エラー例 | 原因 | 推奨対策 |
|---|---|---|
docker pull がタイムアウト |
ネットワーク障害またはレジストリ認証失敗 | services: docker を追加し、DOCKER_USERNAME/DOCKER_PASSWORD をシークレットで提供 |
npm audit が ENOTFOUND エラー |
プロキシ未設定または DNS 解決不可 | 環境変数 HTTP_PROXY/HTTPS_PROXY と NO_PROXY を env: で明示 |
| SARIF 出力が期待通りでない | 使用ツールのバージョン差異 | アクション・パッケージを固定バージョン (@v2, audit2sarif@1.0.0) に更新し、format: sarif オプションを必ず指定 |
まとめ
- セキュリティスキャンは CI の必須要素 – GitHub Actions と標準 Security 機能だけでも早期検出が可能です。
- ツール選定は言語対応・CI 連携・レポート形式・コストの4軸で判断し、イメージは Trivy、コードは CodeQL、依存関係は Dependabot 系列で網羅的にカバーします。
- 実装例 workflow は 3 つのジョブを
needsで連結し、すべて SARIF 形式で GitHub Checks に自動アップロードする構成がベストプラクティスです。 - シークレットは最小権限で管理し、ワークフロー全体の
permissionsを明示的に設定することでリスクを低減できます。 - 失敗時のブロック設定・キャッシュ活用・トラブルシューティング により、開発フローへの影響を最小限に抑えつつ安定運用が実現します。
本稿で示したベストプラクティスとサンプルコードを自プロジェクトへ取り入れれば、GitHub Actions を活用した 包括的なセキュリティスキャン がすぐにでも始められるはずです。ぜひご活用ください。