コードを書いている最中に発見された脆弱性は、修正に数分しかかかりません。同じ脆弱性が本番環境で見つかると、スプリント全体を消費します。そして攻撃者に先に発見されれば、数百万ドルのコストが発生します。これがshift-leftセキュリティの核心的な主張です - セキュリティチェックを開発ライフサイクルのできるだけ早い段階に前倒しするという考え方です。
DevSecOpsはこのアイデアを実践に変えます。セキュリティは最後にある独立したフェーズではなく、コードの最初の一行から本番デプロイまで、開発のあらゆる段階に織り込まれた継続的なプロセスです。
遅いセキュリティのコスト
IBMのデータ侵害コストレポートは、セキュリティ問題の修正コストが発見の遅れに比例して指数関数的に増大することを一貫して示しています。
| 段階 | 修正コスト | 修正時間 |
|---|---|---|
| IDE / ローカル開発 | 数分 | 数秒から数分 |
| コードレビュー / PR | 数時間 | 数分から数時間 |
| CI/CDパイプライン | 数日 | 数時間から数日 |
| ステージング / QA | 数週間 | 数日 |
| 本番環境 | 数ヶ月 | 数週間から数ヶ月 |
| 侵害後 | 数百万ドル | 数ヶ月から数年 |
結論は明確です。セキュリティを一段階前倒しするごとに、コストと時間が桁違いに削減されます。
DevSecOpsパイプライン
成熟したDevSecOpsパイプラインは、あらゆる段階にセキュリティチェックを統合します。
各段階を具体的なツールと設定で解説していきましょう。
ステージ1: IDEでのセキュリティ
最も高速なフィードバックループです。ファイルを保存する前に脆弱性を検出します。
推奨ツール
- Semgrep: OWASPの脆弱性に対応したコミュニティルールを持つ軽量静的解析ツール
- Snyk IDE Extension: リアルタイムの依存関係脆弱性スキャン
- GitLens + GitLeaks: エディタ内でのsecret検出
- ESLint Security Plugins: Node.js向けの
eslint-plugin-security、DOM XSS向けのeslint-plugin-no-unsanitized
例: ESLintセキュリティ設定
{ "extends": ["eslint:recommended"], "plugins": ["security", "no-unsanitized"], "rules": { "security/detect-object-injection": "warn", "security/detect-non-literal-regexp": "warn", "security/detect-unsafe-regex": "error", "security/detect-buffer-noassert": "error", "security/detect-eval-with-expression": "error", "security/detect-no-csrf-before-method-override": "error", "security/detect-possible-timing-attacks": "warn", "no-unsanitized/method": "error", "no-unsanitized/property": "error" } }
ステージ2: Pre-commit Hooks
第二の防衛線です。すべてのcommitの前に自動実行され、危険なコードがリポジトリに入るのを防ぎます。
Gitleaks: Secretがgitに入る前にキャッチ
コードベースで最も一般的なセキュリティミスは、secretのcommitです - APIキー、データベースパスワード、トークンなど。一度secretがgit履歴に入ると、完全に削除するのは非常に困難です(force pushしても、forkやキャッシュに残る可能性があります)。
# .pre-commit-config.yaml repos: - repo: https://github.com/gitleaks/gitleaks rev: v8.21.0 hooks: - id: gitleaks - repo: https://github.com/semgrep/semgrep rev: v1.90.0 hooks: - id: semgrep args: ['--config', 'auto']
インストールと有効化:
pip install pre-commit pre-commit install
これでgit commitするたびに、漏洩したsecretと一般的な脆弱性が自動的にスキャンされます。何か見つかった場合、commitはブロックされます。
カスタムGitleaksルール
組織固有のsecretに対するカスタムパターンを追加できます。
# .gitleaks.toml title = "Custom Gitleaks Config" [[rules]] id = "internal-api-key" description = "Internal API key detected" regex = '''INTERNAL_KEY_[A-Za-z0-9]{32}''' tags = ["key", "internal"]
ステージ3: CI/CDパイプラインセキュリティ
ここが本格的な作業の場です。CIパイプラインは、すべてのpull requestに対して複数のセキュリティスキャンを実行すべきです。
SAST (Static Application Security Testing)
SASTツールはソースコードを実行せずに解析し、脆弱性を示すパターンを探します。
# .github/workflows/security.yml name: Security Scan on: pull_request: branches: [main] jobs: sast: name: Static Analysis runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run Semgrep uses: semgrep/semgrep-action@v1 with: config: >- p/owasp-top-ten p/typescript p/nodejs p/react generateSarif: true - name: Upload SARIF uses: github/codeql-action/upload-sarif@v3 with: sarif_file: semgrep.sarif
Semgrepのp/owasp-top-tenルールセットは、最も一般的な脆弱性を検出します: SQL injection、XSS、SSRF、path traversal、insecure deserializationなど。
SCA (Software Composition Analysis)
SCAは依存関係の既知の脆弱性をスキャンします。これは非常に重要です - 現代のアプリケーションコードの80%以上はオープンソースの依存関係から来ています。
dependency-scan: name: Dependency Audit runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run Snyk uses: snyk/actions/node@master env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: args: --severity-threshold=high - name: npm audit run: npm audit --audit-level=high
Trivyによるコンテナセキュリティ
Dockerイメージをビルドする場合、脆弱性のスキャンは不可欠です。Trivyは最も人気のあるオープンソースコンテナスキャナーです。
container-scan: name: Container Security runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build image run: docker build -t my-app:${{ github.sha }} . - name: Run Trivy uses: aquasecurity/trivy-action@master with: image-ref: my-app:${{ github.sha }} format: 'sarif' output: 'trivy-results.sarif' severity: 'CRITICAL,HIGH' exit-code: '1' - name: Upload Trivy SARIF uses: github/codeql-action/upload-sarif@v3 with: sarif_file: trivy-results.sarif
SBOM生成
Software Bill of Materials (SBOM) は、アプリケーション内のすべてのコンポーネントの完全な目録です。コンプライアンスフレームワークや政府規制によってますます要求されるようになっています(米国のサイバーセキュリティに関する大統領令は、連邦ソフトウェアにSBOMを義務付けています)。
sbom: name: Generate SBOM runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Generate SBOM with Syft uses: anchore/sbom-action@v0 with: format: spdx-json output-file: sbom.spdx.json - name: Upload SBOM uses: actions/upload-artifact@v4 with: name: sbom path: sbom.spdx.json
ステージ4: セキュアなDockerイメージ
本番用のDockerイメージは最小権限の原則に従うべきです。強化されたDockerfileの例を示します。
# Build stage FROM node:22-alpine AS builder WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci COPY . . RUN npm run build # Production stage FROM node:22-alpine AS runner WORKDIR /app # Install dumb-init before dropping root RUN apk add --no-cache dumb-init # Don't run as root RUN addgroup -S app && adduser -S app -G app # Copy only what's needed COPY /app/dist ./dist COPY /app/node_modules ./node_modules COPY /app/package.json ./ # Drop to non-root user USER app ENTRYPOINT ["dumb-init", "--"] # Health check HEALTHCHECK \ CMD wget -qO- http://localhost:3000/health || exit 1 EXPOSE 3000 CMD ["node", "dist/server.js"]
主要なプラクティス:
- マルチステージビルドを使用: builderステージには開発依存関係、runnerステージには本番コードのみ
- rootで実行しない: 非rootユーザーを作成して切り替え
- Alpineイメージを使用: 攻撃対象領域が小さい(デフォルトでインストールされるパッケージが少ない)
- イメージバージョンを固定: サプライチェーン攻撃を避けるため、
node:latestではなくnode:22-alpineを使用 npm ciを使用: lockファイルからの決定論的インストール、npm installではなく
ステージ5: Secret管理
ハードコードされたsecretは、開発者起因のインシデントにおける侵害の最大の原因です。
やってはいけないこと
// NEVER do this const API_KEY = "sk-1234567890abcdef"; const DB_PASSWORD = "supersecret123"; const client = new Client({ connectionString: `postgres://admin:${DB_PASSWORD}@db.example.com/prod` });
代わりにやるべきこと
// Use environment variables const client = new Client({ connectionString: process.env.DATABASE_URL }); // Or use a secret manager import { SecretManagerServiceClient } from '@google-cloud/secret-manager'; const client = new SecretManagerServiceClient(); const [version] = await client.accessSecretVersion({ name: 'projects/my-project/secrets/db-password/versions/latest', }); const dbPassword = version.payload?.data?.toString();
Secret管理の階層
OWASP Top 10: クイックリファレンス
すべての開発者がOWASP Top 10を知っておくべきです。要約版:
| # | 脆弱性 | 概要 | 対策 |
|---|---|---|---|
| 1 | Broken Access Control | ユーザーがアクセスすべきでないリソースにアクセスする | デフォルトで拒否、サーバー側で検証 |
| 2 | Cryptographic Failures | 弱い暗号化、平文データ | 強力なアルゴリズム(AES-256、bcrypt)を使用、TLSをあらゆる場所で |
| 3 | Injection | SQL、NoSQL、OSコマンドインジェクション | パラメータ化クエリ、入力検証 |
| 4 | Insecure Design | 欠陥のあるアーキテクチャ | 脅威モデリング、セキュアデザインパターン |
| 5 | Security Misconfiguration | デフォルト認証情報、公開されたクラウドバケット | 強化されたデフォルト、自動化された設定監査 |
| 6 | Vulnerable Components | 依存関係の既知のCVE | SCAスキャン、定期的な更新 |
| 7 | Auth Failures | 弱いパスワード、壊れたセッション | MFA、レート制限、セキュアなセッション管理 |
| 8 | Data Integrity Failures | 未署名の更新、信頼できないCI/CD | コード署名、SBOM、パイプライン整合性 |
| 9 | Logging Failures | 監査証跡がない | 構造化ログ、異常に対するアラート |
| 10 | SSRF | Server-side request forgery | 送信先URLのallowlist、入力検証 |
完全なGitHub Actionsセキュリティワークフロー
上記すべてを組み合わせた、本番対応のワークフロー:
# .github/workflows/security.yml name: Security Pipeline on: pull_request: branches: [main] push: branches: [main] permissions: contents: read security-events: write jobs: secrets-scan: name: Secret Detection runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: gitleaks/gitleaks-action@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} sast: name: Static Analysis (SAST) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: semgrep/semgrep-action@v1 with: config: p/owasp-top-ten p/typescript p/nodejs dependency-audit: name: Dependency Scan (SCA) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 - run: npm ci - run: npm audit --audit-level=high - uses: snyk/actions/node@master env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: args: --severity-threshold=high continue-on-error: true container-scan: name: Container Scan runs-on: ubuntu-latest needs: [sast, dependency-audit] steps: - uses: actions/checkout@v4 - run: docker build -t app:${{ github.sha }} . - uses: aquasecurity/trivy-action@master with: image-ref: app:${{ github.sha }} severity: CRITICAL,HIGH exit-code: '1' sbom: name: SBOM Generation runs-on: ubuntu-latest needs: [container-scan] steps: - uses: actions/checkout@v4 - uses: anchore/sbom-action@v0 with: format: spdx-json output-file: sbom.spdx.json
追跡すべきメトリクス
DevSecOpsプログラムが機能しているかどうかをどう判断するか?以下のメトリクスを追跡しましょう。
- 平均修復時間 (MTTR): 検出後の脆弱性修正速度
- 脆弱性エスケープ率: 本番環境に到達した脆弱性の割合
- False positive率: false positiveが多すぎるとアラート疲れと警告の無視につながる
- 依存関係の鮮度: 依存関係の平均経過年数(古いほど既知のCVEが存在する可能性が高い)
- SBOMカバレッジ: 最新のSBOMを持つプロジェクトの割合
始め方: 実践的なロードマップ
すべてを一度に導入しようとしないでください。段階的なアプローチが効果的です。
まとめ
DevSecOpsは、パイプラインにツールを追加することではありません - セキュリティをソフトウェア構築の自然な一部にすることです。目標は、すべてのPRをセキュリティ警告でブロックすることではなく、コードがまだ頭の中に新鮮なうちに問題を修正できるよう、開発者に迅速なフィードバックを提供することです。
基本から始めましょう: secretのためのpre-commit hooks、CIでの依存関係スキャン、Dockerイメージのコンテナスキャン。そしてチームの必要に応じて反復改善していきましょう。
セキュリティは一度だけリリースする機能ではありません。すべてのcommitに組み込む実践です。
DevSecOpsスターターチェックリスト:
- Gitleaks pre-commit hooksのインストール
- .envとsecretファイルを.gitignoreに追加
- CIパイプラインにSemgrep SASTを導入
- Snykまたはnpm auditによる依存関係スキャン
- Trivyによるコンテナイメージスキャン
- Dockerfileで非rootユーザーを使用
- 環境変数またはsecret managerにsecretを保管
- リリースごとのSBOM生成
- チーム全体でのOWASP Top 10の理解