LESSON 30分

ストーリー

田中VPoE
SAST、DAST、SCA — 3つのセキュリティテスト手法を学んだ。次はこれらを一つのCI/CDパイプラインに統合する。個別にツールを動かすのではなく、コードがマージされてからデプロイされるまでの全工程にセキュリティチェックを組み込む
あなた
すべてのチェックをPR時に実行すると、時間がかかりすぎませんか?
田中VPoE
いい質問だ。だから「どのチェックを」「どのタイミングで」実行するかの設計が重要なんだ。PRには高速なSAST、ステージング環境へのデプロイ後にDASTという具合に、フェーズに応じてチェックを配置する
あなた
テストピラミッドのセキュリティ版ですね
田中VPoE
まさにそうだ。軽量で高速なチェックを手前に、重量で網羅的なチェックを後ろに配置する。セキュリティテストピラミッドだ

セキュリティテストピラミッド

セキュリティテストピラミッド:

                    /\
                   /  \
                  / 手動 \        ← ペネトレーションテスト
                 / テスト  \        (四半期ごと)
                /──────────\
               /   DAST     \     ← 動的スキャン
              / (ステージング) \     (デプロイ後)
             /────────────────\
            /    SCA + SBOM     \   ← 依存ライブラリ検査
           / (ビルド時/PR時)      \   (ビルド時)
          /──────────────────────\
         /   SAST + シークレットスキャン \  ← 静的解析
        / (PR時・プリコミット)            \  (コミット/PR時)
       /──────────────────────────────\
      /   IDE プラグイン + プリコミットフック  \  ← 開発時チェック
     / (コーディング中)                        \  (リアルタイム)
    /──────────────────────────────────────\

    速い・安い ←──────────────────→ 遅い・高い
    検出範囲:狭い ←──────────────→ 検出範囲:広い

パイプライン設計

フェーズ別のセキュリティチェック

フェーズチェックツール例実行時間ブロック
コーディング中IDEリアルタイム解析Semgrep LSP, Snyk IDEリアルタイムなし(警告のみ)
プリコミットシークレットスキャン、リンターgitleaks, detect-secrets数秒コミットブロック
PR作成時SAST、SCA、ライセンスチェックSemgrep, Trivy, FOSSA2-5分マージブロック
ビルド時コンテナイメージスキャン、SBOM生成Trivy, Syft3-5分ビルドブロック
ステージングデプロイ後DAST、コンプライアンスチェックZAP, OPA10-30分デプロイブロック
本番デプロイ前最終承認、ポリシーチェックOPA, 手動承認1-5分デプロイブロック
本番運用中継続的モニタリング、WAFCloudWatch, AWS WAF常時アラート

統合パイプラインの全体像

# GitHub Actions: 統合セキュリティパイプライン
name: Security Pipeline

on:
  pull_request:
    branches: [main, develop]
  push:
    branches: [main]

jobs:
  # Phase 1: PR時の静的チェック(並列実行)
  sast:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Semgrep SAST
        uses: returntocorp/semgrep-action@v1
        with:
          config: >-
            p/owasp-top-ten
            p/typescript
            .semgrep/custom-rules/

  secret-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Gitleaks Secret Scan
        uses: gitleaks/gitleaks-action@v2

  sca:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Trivy SCA
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'fs'
          severity: 'HIGH,CRITICAL'
          exit-code: '1'

  license-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - name: License Check
        run: npx license-checker --failOn 'GPL-3.0'

  # Phase 2: ビルド時のコンテナスキャン
  container-scan:
    needs: [sast, secret-scan, sca, license-check]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build Image
        run: docker build -t myapp:${{ github.sha }} .
      - name: Trivy Image Scan
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: 'myapp:${{ github.sha }}'
          severity: 'HIGH,CRITICAL'
          exit-code: '1'
      - name: Generate SBOM
        run: |
          syft myapp:${{ github.sha }} -o cyclonedx-json > sbom.json
      - uses: actions/upload-artifact@v4
        with:
          name: sbom
          path: sbom.json

  # Phase 3: ステージング環境でのDASTスキャン(mainブランチのみ)
  dast:
    if: github.ref == 'refs/heads/main'
    needs: [container-scan]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to Staging
        run: ./scripts/deploy-staging.sh
      - name: Wait for Deployment
        run: ./scripts/wait-for-healthy.sh staging
      - name: ZAP API Scan
        uses: zaproxy/action-api-scan@v0.9.0
        with:
          target: 'https://staging.example.com'
          cmd_options: '-f openapi -O https://staging.example.com/api/openapi.json'

  # Phase 4: コンプライアンスチェック
  compliance:
    if: github.ref == 'refs/heads/main'
    needs: [dast]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: OPA Policy Check
        run: |
          opa eval --data policies/ --input scan-results.json \
            "data.compliance.allow"

セキュリティゲートの設計

ゲートポリシーの定義

ゲート条件失敗時のアクション
PR マージゲートSAST Critical = 0, SCA Critical = 0, シークレット検出 = 0マージブロック
ビルドゲートコンテナ Critical = 0, High 未対応 < 5ビルド停止
デプロイゲートDAST Critical = 0, コンプライアンス準拠デプロイ停止
リリースゲート全セキュリティチェック通過, SBOM生成完了リリース停止

例外処理(セキュリティ例外)

# security-exceptions.yaml
# 承認された例外を管理
exceptions:
  - id: "EXC-2025-001"
    vulnerability: "CVE-2024-12345"
    package: "lodash@4.17.20"
    reason: "影響を受ける関数を使用していない(確認済み)"
    approved_by: "security-team-lead"
    approved_date: "2025-01-15"
    expiry_date: "2025-04-15"
    review_date: "2025-03-15"
    jira_ticket: "SEC-456"

「例外は許可するが、有効期限と定期レビューが必須だ。『永久に例外』は存在しない」 — 田中VPoE


セキュリティスキャン結果の統合管理

SARIF(Static Analysis Results Interchange Format)

セキュリティスキャン結果の統合フロー:

[SAST]  ──→ SARIF ──┐
[DAST]  ──→ SARIF ──├──→ [GitHub Security Tab]
[SCA]   ──→ SARIF ──┤    or
[Secret]──→ SARIF ──┘    [DefectDojo]
                          or
                          [OWASP Dependency-Track]

利点:
├── 全ツールの結果を統一フォーマットで管理
├── 重複排除(同一脆弱性の複数検出をマージ)
├── ダッシュボードでの一元表示
└── トレンド分析(時系列での改善/悪化の追跡)

まとめ

ポイント内容
テストピラミッド軽量・高速(IDE/プリコミット)→ 重量・網羅的(DAST/ペンテスト)の階層
フェーズ配置PR時にSAST/SCA、ビルド時にコンテナスキャン、デプロイ後にDAST
ゲート設計各フェーズにブロック条件を設定、例外は有効期限付きで管理
結果の統合SARIFフォーマットで統一し、ダッシュボードで一元管理

チェックリスト

  • セキュリティテストピラミッドの各層を説明できる
  • フェーズ別のセキュリティチェック配置を設計できる
  • GitHub Actionsでの統合パイプラインの構成を理解した
  • セキュリティゲートと例外処理の設計方針を理解した

次のステップへ

次は演習です。実際のCI/CDパイプラインにSAST/DAST/SCAを統合するセキュリティパイプラインを設計しましょう。


推定読了時間: 30分