- Published on
DevSecOps完全ガイド2025:Shift-Leftセキュリティ、SAST/DAST/SCA、コンテナセキュリティまで
- Authors

- Name
- Youngju Kim
- @fjvbn20031
TL;DR
- Shift-Leftセキュリティ: 開発初期にセキュリティを適用すれば欠陥修正コストが30倍削減
- SAST: SonarQube、Semgrep、CodeQLでコードレベルの脆弱性(ぜいじゃくせい)を検出
- DAST: OWASP ZAP、Burp Suiteでランタイム脆弱性を発見
- SCA: Snyk、Dependabotで依存関係(いぞんかんけい)の脆弱性を自動パッチ
- コンテナセキュリティ: Trivy、Grypeでイメージスキャン、最小ベースイメージ使用
- サプライチェーン: SBOM生成、SLSAレベル達成、Sigstore署名(しょめい)
- シークレット検出: GitLeaks、TruffleHogでコミットされた秘密情報を検出
- GitHub Actions: 統合セキュリティパイプラインで全段階を自動化
目次
- DevSecOpsとは何か
- Shift-Leftセキュリティ戦略
- SAST - 静的解析
- DAST - 動的解析
- SCA - ソフトウェア構成分析
- コンテナセキュリティ
- シークレット検出
- サプライチェーンセキュリティ - SBOMとSLSA
- Policy-as-Code
- GitHub Actions統合セキュリティパイプライン
- 実践クイズ
- 参考資料
1. DevSecOpsとは何か
1.1 従来のセキュリティの限界
従来(じゅうらい)のソフトウェア開発では、セキュリティは最後の段階で追加されていました。開発が終わりデプロイ直前にセキュリティチームがレビューする方式でした。このアプローチの問題点は明確です。
| 問題 | 影響 |
|---|---|
| 遅い発見 | 修正コスト30倍増加 |
| ボトルネック | セキュリティチームが全プロジェクトをレビュー |
| 開発者の無関心 | 「セキュリティはセキュリティチームの仕事」マインド |
| リリース遅延 | 脆弱性発見時にスケジュール全体が遅延 |
| コンテキスト不足 | セキュリティチームがコードの意図を理解していない |
1.2 DevSecOpsの核心原則
DevSecOpsはDevelopment + Security + Operationsの造語(ぞうご)で、セキュリティをソフトウェア開発ライフサイクル(SDLC)全体に統合する文化であり実践方法です。
5つの核心原則:
- 全員がセキュリティに責任: セキュリティはセキュリティチームだけの仕事ではない
- 自動化優先: 手動レビューの代わりに自動化ツールを活用
- 迅速なフィードバック: 開発者がコードを書く時点でセキュリティフィードバック
- 継続的改善: セキュリティメトリクスの測定と継続的な改善
- 共有責任: 開発、運用、セキュリティチーム間の知識共有
1.3 DevSecOpsツールエコシステム概要
┌─────────────────────────────────────────────────────────────┐
│ DevSecOps パイプライン │
├──────────┬──────────┬──────────┬──────────┬────────────────┤
│ Plan │ Code │ Build │ Test │ Deploy/Run │
├──────────┼──────────┼──────────┼──────────┼────────────────┤
│ Threat │ SAST │ SCA │ DAST │ Runtime │
│ Modeling │ Semgrep │ Snyk │ ZAP │ Protection │
│ │ CodeQL │ Trivy │ Burp │ Falco │
│ Security │ SonarQube│ OSV │ Nuclei │ Container │
│ Require │ │ │ │ Security │
│ ments │ Secret │ SBOM │ Fuzzing │ Network │
│ │ Detect │ Signing │ │ Policy │
├──────────┼──────────┼──────────┼──────────┼────────────────┤
│ Policy-as-Code (OPA / Kyverno / Conftest) │
└─────────────────────────────────────────────────────────────┘
2. Shift-Leftセキュリティ戦略
2.1 Shift-Leftとは?
Shift-Leftはセキュリティ活動を開発プロセスの左側(初期段階)に移動(いどう)させる戦略です。
従来の方式:
Plan -> Code -> Build -> Test -> Deploy -> [セキュリティレビュー] -> Release
^ ここで発見 = コスト高
Shift-Left方式:
Plan -> [セキュリティ] -> Code -> [セキュリティ] -> Build -> [セキュリティ] -> Test -> Deploy
^ ここから開始 = コスト低
2.2 Shift-Left ROI分析
IBM Systems Sciences Instituteの研究によると、欠陥修正コストは発見時点によって指数関数的(しすうかんすうてき)に増加します。
| 発見段階 | 相対コスト | 例 |
|---|---|---|
| 要件定義 | 1x | セキュリティ要件の漏れを発見 |
| 設計 | 5x | アーキテクチャ脆弱性を発見 |
| 実装 | 10x | コードレベル脆弱性を発見 |
| テスト | 20x | QA段階で発見 |
| 運用 | 30x | 本番環境で発見 |
| インシデント発生後 | 100x+ | データ漏洩事故 |
2.3 Shift-Left実装ステップ
ステップ1: セキュリティチャンピオンプログラム
各開発チームにセキュリティチャンピオンを指定します。
# security-champions.yaml
teams:
- name: "Backend Team"
champion: "alice@company.com"
responsibilities:
- "PRセキュリティレビュー"
- "SAST結果のトリアージ"
- "月次セキュリティ教育実施"
training:
- "OWASP Top 10"
- "Secure Coding Practices"
- "Threat Modeling基礎"
- name: "Frontend Team"
champion: "bob@company.com"
responsibilities:
- "XSS/CSRF防止レビュー"
- "依存関係脆弱性管理"
- "CSPヘッダー管理"
ステップ2: 脅威モデリング
STRIDEモデルを活用した脅威(きょうい)モデリングを設計段階で実施します。
STRIDE脅威モデル:
┌─────────────────────────────────────────┐
│ S - Spoofing(なりすまし) │
│ T - Tampering(改ざん) │
│ R - Repudiation(否認) │
│ I - Information Disclosure(情報漏洩) │
│ D - Denial of Service(サービス拒否) │
│ E - Elevation of Privilege(権限昇格) │
└─────────────────────────────────────────┘
ステップ3: IDEセキュリティプラグイン
開発者のIDEで直接セキュリティフィードバックを提供します。
// .vscode/settings.json
{
"semgrep.scan.autoScan": true,
"semgrep.scan.configuration": [
"p/owasp-top-ten",
"p/typescript",
"p/react"
],
"sonarlint.connectedMode.project": {
"connectionId": "my-sonarqube",
"projectKey": "my-project"
}
}
3. SAST - 静的解析
3.1 SASTとは?
SAST(Static Application Security Testing)はソースコード、バイトコード、バイナリを実行せずに解析してセキュリティ脆弱性を見つける技法です。
SASTが検出する主な脆弱性:
- SQLインジェクション
- クロスサイトスクリプティング(XSS)
- パストラバーサル
- ハードコードされたシークレット
- 安全でない暗号化
- バッファオーバーフロー
3.2 SonarQubeセットアップ
# docker-compose.yml - SonarQubeローカルセットアップ
version: "3.8"
services:
sonarqube:
image: sonarqube:community
ports:
- "9000:9000"
environment:
SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonarqube
SONAR_JDBC_USERNAME: sonar
SONAR_JDBC_PASSWORD: sonar
volumes:
- sonar_data:/opt/sonarqube/data
- sonar_logs:/opt/sonarqube/logs
- sonar_extensions:/opt/sonarqube/extensions
depends_on:
- db
db:
image: postgres:15
environment:
POSTGRES_DB: sonarqube
POSTGRES_USER: sonar
POSTGRES_PASSWORD: sonar
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
sonar_data:
sonar_logs:
sonar_extensions:
postgres_data:
# sonar-project.properties
sonar.projectKey=my-app
sonar.projectName=My Application
sonar.projectVersion=1.0
sonar.sources=src
sonar.tests=tests
sonar.language=ts
sonar.sourceEncoding=UTF-8
sonar.javascript.lcov.reportPaths=coverage/lcov.info
sonar.qualitygate.wait=true
3.3 Semgrep実践活用
Semgrepは軽量(けいりょう)で高速なSASTツールで、カスタムルールの作成が容易です。
# .semgrep.yml - カスタムセキュリティルール
rules:
- id: no-eval-usage
patterns:
- pattern: eval(...)
message: "eval()の使用はコードインジェクションのリスクがあります"
severity: ERROR
languages: [javascript, typescript]
metadata:
owasp: "A03:2021 Injection"
cwe: "CWE-95"
- id: no-innerHTML
patterns:
- pattern: $EL.innerHTML = $VAL
message: "innerHTMLの直接設定はXSSリスクがあります。textContentまたはDOMPurifyを使用してください"
severity: WARNING
languages: [javascript, typescript]
- id: sql-injection-risk
patterns:
- pattern: |
$DB.query(`... ${$VAR} ...`)
- pattern: |
$DB.query("..." + $VAR + "...")
message: "SQLインジェクションリスク!パラメータバインディングを使用してください"
severity: ERROR
languages: [javascript, typescript]
fix: |
$DB.query("... $1 ...", [$VAR])
- id: no-hardcoded-secrets
patterns:
- pattern: |
const $KEY = "AKIA..."
- pattern: |
const $KEY = "sk-..."
message: "ハードコードされたシークレットが検出されました。環境変数を使用してください"
severity: ERROR
languages: [javascript, typescript]
# Semgrep実行
semgrep --config auto --config .semgrep.yml src/
# 特定のルールセットのみ実行
semgrep --config p/owasp-top-ten src/
semgrep --config p/typescript src/
# CI用JSON出力
semgrep --config auto --json --output results.json src/
3.4 CodeQL高度なクエリ
GitHub CodeQLはコードをデータベースに変換してクエリする強力なツールです。
// codeql-queries/sql-injection.ql
/**
* @name SQL injection in query string
* @description ユーザー入力がSQLクエリに直接含まれている
* @kind path-problem
* @problem.severity error
* @security-severity 9.8
* @precision high
* @id js/sql-injection
* @tags security
* external/cwe/cwe-089
*/
import javascript
import DataFlow::PathGraph
class SqlInjectionConfig extends TaintTracking::Configuration {
SqlInjectionConfig() { this = "SqlInjectionConfig" }
override predicate isSource(DataFlow::Node source) {
exists(Express::RequestInputAccess input |
source = input
)
}
override predicate isSink(DataFlow::Node sink) {
exists(DatabaseAccess query |
sink = query.getAQueryArgument()
)
}
}
from SqlInjectionConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink.getNode(), source, sink,
"このクエリは$@からのユーザー入力を含みます。",
source.getNode(), "ユーザー入力"
3.5 SASTツール比較
| 機能 | SonarQube | Semgrep | CodeQL |
|---|---|---|---|
| 価格 | Community無料 | OSS無料 | OSS無料 |
| 対応言語 | 30+ | 30+ | 10+ |
| カスタムルール | Java DSL | YAML | QL Language |
| CI統合 | 良好 | 非常に良好 | GitHub最適化 |
| 速度 | 普通 | 非常に高速 | 低速(DB構築) |
| 精度 | 高い | 高い | 非常に高い |
| 学習曲線 | 普通 | 低い | 高い |
4. DAST - 動的解析
4.1 DASTとは?
DAST(Dynamic Application Security Testing)は実行中のアプリケーションに実際の攻撃をシミュレーションして脆弱性を検出します。ソースコードが不要なため「ブラックボックステスティング」とも呼ばれます。
4.2 OWASP ZAP自動化
# zap-automation.yaml
env:
contexts:
- name: "My Web App"
urls:
- "https://staging.example.com"
includePaths:
- "https://staging.example.com/.*"
excludePaths:
- "https://staging.example.com/logout"
authentication:
method: "form"
parameters:
loginUrl: "https://staging.example.com/login"
loginRequestData: "username=test&password=test123"
jobs:
- type: spider
parameters:
context: "My Web App"
maxDuration: 5
maxDepth: 10
- type: spiderAjax
parameters:
context: "My Web App"
maxDuration: 5
- type: passiveScan-wait
parameters:
maxDuration: 10
- type: activeScan
parameters:
context: "My Web App"
maxRuleDurationInMins: 5
policy: "API-Scan"
- type: report
parameters:
template: "modern"
reportDir: "/zap/reports"
reportFile: "zap-report"
reportTitle: "ZAP Security Report"
risks:
- high
- medium
- low
# DockerでZAP自動化スキャン実行
docker run --rm -v $(pwd):/zap/wrk:rw \
-t zaproxy/zap-stable \
zap.sh -cmd -autorun /zap/wrk/zap-automation.yaml
# APIスキャン(OpenAPIスペック基盤)
docker run --rm -v $(pwd):/zap/wrk:rw \
-t zaproxy/zap-stable \
zap-api-scan.py \
-t https://staging.example.com/openapi.json \
-f openapi \
-r api-report.html
4.3 DASTとSASTの比較
| 特性 | SAST | DAST |
|---|---|---|
| 分析タイミング | ビルド時 | ランタイム |
| ソースコード必要 | はい | いいえ |
| 実行環境必要 | いいえ | はい |
| 誤検知率 | 高い | 低い |
| カバレッジ | 全コード | 到達可能なパス |
| 脆弱性タイプ | コードレベル | ランタイム/設定 |
| フィードバック速度 | 高速 | 低速 |
5. SCA - ソフトウェア構成分析
5.1 なぜSCAが重要か?
現代のアプリケーションの80%以上がオープンソースコードで構成されています。Log4Shell(CVE-2021-44228)は単一のオープンソースライブラリの脆弱性(ぜいじゃくせい)が世界的な影響を与えうることを示しました。
5.2 Snyk設定
# .snyk - Snykポリシーファイル
version: v1.5
ignore:
SNYK-JS-LODASH-590103:
- '*':
reason: "該当関数を使用していない"
expires: "2026-06-01T00:00:00.000Z"
patch: {}
language-settings:
javascript:
severity-threshold: high
# Snyk CLI使用法
snyk test # 脆弱性検査
snyk monitor # 継続的モニタリング登録
snyk test --severity-threshold=high # 高い重大度のみ
snyk code test # SASTスキャン
snyk container test myimage:latest # コンテナスキャン
snyk iac test terraform/ # IaCスキャン
5.3 Dependabot設定
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "09:00"
timezone: "Asia/Tokyo"
open-pull-requests-limit: 10
reviewers:
- "security-team"
labels:
- "dependencies"
- "security"
commit-message:
prefix: "deps"
include: "scope"
groups:
security-patches:
patterns:
- "*"
update-types:
- "security"
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
labels:
- "docker"
- "dependencies"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
labels:
- "ci"
- "dependencies"
5.4 Renovate高度な設定
// renovate.json
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base",
":semanticCommits",
"group:allNonMajor",
"schedule:weekends"
],
"vulnerabilityAlerts": {
"enabled": true,
"labels": ["security"],
"schedule": ["at any time"]
},
"packageRules": [
{
"matchUpdateTypes": ["patch"],
"automerge": true,
"automergeType": "pr",
"platformAutomerge": true
},
{
"matchPackagePatterns": ["eslint", "prettier"],
"groupName": "linting tools",
"automerge": true
},
{
"matchPackagePatterns": ["^@types/"],
"groupName": "type definitions",
"automerge": true
}
],
"prConcurrentLimit": 5,
"prHourlyLimit": 2
}
6. コンテナセキュリティ
6.1 コンテナセキュリティの重要性
コンテナイメージにはOSパッケージ、ランタイム、アプリケーション依存関係がすべて含まれます。1つのイメージに数百の脆弱性が存在する可能性があります。
6.2 Trivyイメージスキャン
# 基本イメージスキャン
trivy image myapp:latest
# 重大度フィルタリング
trivy image --severity CRITICAL,HIGH myapp:latest
# 修正可能な脆弱性のみ
trivy image --ignore-unfixed myapp:latest
# SBOM生成
trivy image --format cyclonedx --output sbom.json myapp:latest
# CI用JSON出力と終了コード
trivy image --format json --output results.json \
--exit-code 1 --severity CRITICAL myapp:latest
# ファイルシステムスキャン(ビルド前)
trivy fs --security-checks vuln,secret,config .
# Kubernetesマニフェストスキャン
trivy config k8s/
6.3 安全なDockerfile作成
# BAD - セキュリティアンチパターン
FROM ubuntu:latest
RUN apt-get update && apt-get install -y python3
COPY . /app
RUN pip install -r requirements.txt
USER root
EXPOSE 8080
CMD ["python3", "app.py"]
# GOOD - セキュリティベストプラクティス
# 1. 最小ベースイメージ使用
FROM python:3.12-slim AS builder
# 2. パッケージインストール後キャッシュクリア
RUN apt-get update && \
apt-get install -y --no-install-recommends gcc && \
rm -rf /var/lib/apt/lists/*
# 3. 別のビルドステージ
WORKDIR /build
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
# 4. 最終イメージは最小化
FROM python:3.12-slim
# 5. 非rootユーザー
RUN groupadd -r appuser && useradd -r -g appuser appuser
# 6. ビルドアーティファクトのみコピー
COPY /install /usr/local
COPY . /app
WORKDIR /app
USER appuser
# 7. 読み取り専用ファイルシステムサポート
EXPOSE 8080
HEALTHCHECK \
CMD curl -f http://localhost:8080/health || exit 1
CMD ["python3", "app.py"]
6.4 GrypeとDocker Scout
# Grype - イメージ脆弱性スキャン
grype myapp:latest
grype myapp:latest --only-fixed
grype myapp:latest -o json > grype-results.json
# Docker Scout - Docker Desktop統合
docker scout cves myapp:latest
docker scout recommendations myapp:latest
docker scout quickview myapp:latest
6.5 コンテナセキュリティチェックリスト
コンテナセキュリティチェックリスト:
イメージビルド:
[x] 最小ベースイメージ(distroless, alpine, slim)
[x] マルチステージビルド
[x] 非rootユーザー実行
[x] 不要なパッケージ削除
[x] .dockerignore設定
[x] イメージ署名(cosign)
ランタイム:
[x] 読み取り専用ファイルシステム
[x] リソース制限(CPU、メモリ)
[x] capabilities最小化
[x] seccomp/AppArmorプロファイル
[x] ネットワークポリシー適用
レジストリ:
[x] プライベートレジストリ使用
[x] イメージ脆弱性スキャン
[x] タグ不変性設定
[x] イメージ署名検証
7. シークレット検出
7.1 漏洩するシークレットの現実
GitHubによると、毎年数百万件のシークレットが公開リポジトリにコミットされています。APIキー、パスワード、証明書が漏洩(ろうえい)すると数分で悪用される可能性があります。
7.2 GitLeaks設定
# .gitleaks.toml
title = "Custom Gitleaks Configuration"
[extend]
useDefault = true
[[rules]]
id = "custom-api-key"
description = "Custom API Key Pattern"
regex = '''(?i)api[_-]?key\s*[:=]\s*['"][a-zA-Z0-9]{32,}['"]'''
entropy = 3.5
secretGroup = 0
tags = ["api", "key"]
[[rules]]
id = "private-key-file"
description = "Private Key File Reference"
regex = '''(?i)(private[_-]?key|ssh[_-]?key)\s*[:=]\s*['"].*\.(pem|key|p12)['"]'''
tags = ["key", "private"]
[allowlist]
description = "Global Allowlist"
paths = [
'''\.gitleaks\.toml''',
'''test/.*''',
'''.*_test\.go''',
'''.*\.test\.(ts|js)'''
]
regexes = [
'''EXAMPLE_.*''',
'''REPLACE_ME'''
]
# GitLeaks実行
gitleaks detect --source . --verbose
gitleaks detect --source . --report-format json --report-path leaks.json
# Git履歴全体スキャン
gitleaks detect --source . --log-opts="--all"
# pre-commit hook
gitleaks protect --staged --verbose
7.3 TruffleHog活用
# リポジトリ全体スキャン
trufflehog git file://. --only-verified
# GitHub組織全体スキャン
trufflehog github --org=my-org --only-verified
# Dockerイメージスキャン
trufflehog docker --image=myapp:latest
# S3バケットスキャン
trufflehog s3 --bucket=my-bucket
7.4 pre-commit Hook設定
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: detect-private-key
- id: check-added-large-files
args: ['--maxkb=500']
- repo: https://github.com/returntocorp/semgrep
rev: v1.50.0
hooks:
- id: semgrep
args: ['--config', 'p/secrets', '--error']
8. サプライチェーンセキュリティ - SBOMとSLSA
8.1 サプライチェーン攻撃事例
| 事件 | 年 | 影響 |
|---|---|---|
| SolarWinds | 2020 | 18,000以上の機関が被害 |
| Codecov | 2021 | CIスクリプト改ざん |
| ua-parser-js | 2021 | npmパッケージハイジャック |
| Log4Shell | 2021 | 世界中のJavaアプリに影響 |
| xz utils | 2024 | Linuxバックドア試み |
8.2 SBOM生成
SBOM(Software Bill of Materials)はソフトウェアに含まれるすべての構成要素(こうせいようそ)のリストです。
# CycloneDXフォーマットSBOM生成
# npmプロジェクト
npx @cyclonedx/cyclonedx-npm --output-file sbom.json
# Pythonプロジェクト
cyclonedx-py requirements requirements.txt -o sbom.json
# コンテナイメージ
trivy image --format cyclonedx -o sbom.json myapp:latest
syft myapp:latest -o cyclonedx-json > sbom.json
# SPDXフォーマット
syft myapp:latest -o spdx-json > sbom-spdx.json
// SBOM例(CycloneDX簡略版)
{
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"version": 1,
"metadata": {
"component": {
"type": "application",
"name": "my-web-app",
"version": "2.1.0"
}
},
"components": [
{
"type": "library",
"name": "express",
"version": "4.18.2",
"purl": "pkg:npm/express@4.18.2",
"licenses": [{ "license": { "id": "MIT" } }]
},
{
"type": "library",
"name": "lodash",
"version": "4.17.21",
"purl": "pkg:npm/lodash@4.17.21"
}
]
}
8.3 SLSAフレームワーク
SLSA(Supply-chain Levels for Software Artifacts)はサプライチェーンセキュリティの成熟度(せいじゅくど)を測定するフレームワークです。
SLSAレベル:
┌──────────────┬─────────────────────────────────────┐
│ SLSA Level 0 │ セキュリティ保証なし │
│ SLSA Level 1 │ ビルドプロセス文書化(provenance) │
│ SLSA Level 2 │ ホスティングビルド、署名付きprovenance │
│ SLSA Level 3 │ 隔離ビルド、改ざん防止 │
└──────────────┴─────────────────────────────────────┘
8.4 Sigstoreでアーティファクト署名
# cosignでコンテナイメージ署名
cosign sign --key cosign.key myregistry/myapp:v1.0.0
# キーレス署名(OIDC基盤)
cosign sign myregistry/myapp:v1.0.0
# 署名検証
cosign verify --key cosign.pub myregistry/myapp:v1.0.0
# SBOM添付
cosign attach sbom --sbom sbom.json myregistry/myapp:v1.0.0
# アーティファクト証明(attestation)生成
cosign attest --predicate provenance.json \
--type slsaprovenance \
myregistry/myapp:v1.0.0
9. Policy-as-Code
9.1 OPA(Open Policy Agent)
# policy/kubernetes.rego
package kubernetes.admission
# rootコンテナ禁止
deny[msg] {
input.request.kind.kind == "Pod"
container := input.request.object.spec.containers[_]
container.securityContext.runAsUser == 0
msg := sprintf("コンテナ'%s'がrootで実行されます", [container.name])
}
# latestタグ禁止
deny[msg] {
input.request.kind.kind == "Pod"
container := input.request.object.spec.containers[_]
endswith(container.image, ":latest")
msg := sprintf("コンテナ'%s'がlatestタグを使用しています", [container.name])
}
# リソース制限必須
deny[msg] {
input.request.kind.kind == "Pod"
container := input.request.object.spec.containers[_]
not container.resources.limits
msg := sprintf("コンテナ'%s'にリソース制限がありません", [container.name])
}
# 読み取り専用ルートファイルシステム必須
deny[msg] {
input.request.kind.kind == "Pod"
container := input.request.object.spec.containers[_]
not container.securityContext.readOnlyRootFilesystem
msg := sprintf("コンテナ'%s'が読み取り専用ファイルシステムを使用していません", [container.name])
}
9.2 Kyvernoポリシー
# kyverno-policies.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-labels
spec:
validationFailureAction: Enforce
rules:
- name: require-team-label
match:
any:
- resources:
kinds:
- Pod
validate:
message: "すべてのPodには'team'ラベルが必要です"
pattern:
metadata:
labels:
team: "?*"
---
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-privileged
spec:
validationFailureAction: Enforce
rules:
- name: no-privileged-containers
match:
any:
- resources:
kinds:
- Pod
validate:
message: "Privilegedコンテナは許可されていません"
pattern:
spec:
containers:
- securityContext:
privileged: "false"
9.3 ConftestでIaC検証
# ConftestでTerraform検証
conftest test terraform/ --policy policy/
# Dockerfile検証
conftest test Dockerfile --policy policy/docker/
# Kubernetesマニフェスト検証
conftest test k8s/ --policy policy/kubernetes/
# policy/docker/dockerfile.rego
package main
deny[msg] {
input[i].Cmd == "from"
val := input[i].Value
contains(val[0], ":latest")
msg := "FROMでlatestタグの使用は禁止です"
}
deny[msg] {
input[i].Cmd == "user"
val := input[i].Value
val[0] == "root"
msg := "USER rootの使用は禁止です"
}
10. GitHub Actions統合セキュリティパイプライン
10.1 総合セキュリティワークフロー
# .github/workflows/security.yml
name: Security Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
schedule:
- cron: '0 6 * * 1' # 毎週月曜日午前6時
permissions:
contents: read
security-events: write
pull-requests: write
jobs:
# Stage 1: シークレット検出
secret-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: GitLeaks Scan
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Stage 2: SAST
sast:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Semgrep Scan
uses: returntocorp/semgrep-action@v1
with:
config: >-
p/owasp-top-ten
p/typescript
p/react
generateSarif: "1"
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: semgrep.sarif
if: always()
# Stage 3: SCA
sca:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Snyk Security Scan
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
# Stage 4: コンテナセキュリティ
container-security:
runs-on: ubuntu-latest
needs: [sast]
steps:
- uses: actions/checkout@v4
- name: Build Docker Image
run: docker build -t myapp:test .
- name: Trivy Image Scan
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:test'
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'
if: always()
# Stage 5: SBOM生成
sbom:
runs-on: ubuntu-latest
needs: [container-security]
steps:
- uses: actions/checkout@v4
- name: Generate SBOM
uses: anchore/sbom-action@v0
with:
image: myapp:test
format: cyclonedx-json
output-file: sbom.json
- name: Upload SBOM
uses: actions/upload-artifact@v4
with:
name: sbom
path: sbom.json
# 最終: セキュリティゲート
security-gate:
runs-on: ubuntu-latest
needs: [secret-scan, sast, sca, container-security]
steps:
- name: Security Gate Check
run: |
echo "All security checks passed!"
echo "Pipeline completed at $(date)"
10.2 セキュリティパイプラインメトリクス
成功するDevSecOpsプログラムで追跡すべき主要メトリクスです。
| メトリクス | 説明 | 目標 |
|---|---|---|
| MTTR | 脆弱性平均修正時間 | Critical: 24時間以内 |
| 脆弱性密度 | コード1000行あたりの脆弱性数 | 0.5以下 |
| スキャンカバレッジ | セキュリティスキャン適用リポジトリ割合 | 100% |
| 誤検知率 | 全発見中の誤検知割合 | 20%以下 |
| パイプライン通過率 | セキュリティゲート通過率 | 85%以上 |
| 依存関係最新度 | 最新バージョン依存関係の割合 | 80%以上 |
11. 実践クイズ
Q1: SASTとDASTの違いは何ですか?
回答:
- SASTはソースコードを静的に解析して脆弱性を見つけます。ビルド段階で実行され、実行環境は不要です。
- DASTは実行中のアプリケーションに攻撃をシミュレーションします。ランタイム環境が必要で、ソースコードなしでも可能です。
- SASTは誤検知率が高いですが全コードを分析でき、DASTは誤検知率が低いですが到達可能なパスのみ分析します。
- 両方を使用するのが理想的で、これをIAST(Interactive AST)とも呼びます。
Q2: Shift-Leftセキュリティがコストを削減する理由は?
回答:
- 欠陥修正コストは発見時点が遅いほど指数関数的に増加します。
- 要件段階で発見すれば1x、設計5x、実装10x、テスト20x、運用30x、インシデント後100x+のコストがかかります。
- Shift-Leftはセキュリティを開発初期(左側)に移動させ、欠陥を早期に発見するためコストが削減されます。
- また、開発者がコードを書く時点でフィードバックを受けるため、コンテキストスイッチコストも削減されます。
Q3: SBOMがサプライチェーンセキュリティで重要な理由は?
回答:
- SBOMはソフトウェアに含まれるすべての構成要素(ライブラリ、フレームワークなど)のリストです。
- Log4Shellのような脆弱性が発見された場合、SBOMで影響を受けるシステムを即座に特定できます。
- ライセンスコンプライアンスの確認にも不可欠です。
- 米国大統領令(EO 14028)では政府ソフトウェアサプライヤーにSBOM提出を義務化しました。
- CycloneDXとSPDXが代表的なSBOM標準フォーマットです。
Q4: 安全なコンテナイメージを作るためのベストプラクティス5つは?
回答:
- 最小ベースイメージ: distroless、alpine、slimイメージ使用で攻撃対象面を縮小
- マルチステージビルド: ビルドツールを最終イメージに含めない
- 非rootユーザー: USER命令でroot以外のユーザーで実行
- イメージ署名: cosignでイメージ署名と検証
- 定期的スキャン: Trivy/Grypeでイメージ脆弱性を定期スキャン
追加事項: 読み取り専用ファイルシステム、capabilities最小化、不要パッケージ削除
Q5: GitHub Actionsでセキュリティパイプラインを構成する際の実行順序は?
回答:
推奨順序:
- シークレット検出(GitLeaks)- 最速で最も重要
- SAST(Semgrep/CodeQL)- コードレベル脆弱性
- SCA(Snyk/Dependabot)- 依存関係脆弱性
- IaCスキャン(Trivy/Conftest)- インフラ設定検証
- コンテナセキュリティ(Trivy)- イメージビルド後スキャン
- SBOM生成 - アーティファクト一覧生成
- DAST(ZAP)- ステージングデプロイ後ランタイムテスト
- セキュリティゲート - 全結果を総合判断
シークレット検出とSASTは並列実行可能で、DASTはデプロイ後のみ実行可能です。
12. 参考資料
- OWASP DevSecOps Guideline
- NIST Secure Software Development Framework (SSDF)
- SLSA - Supply-chain Levels for Software Artifacts
- Sigstore - Software Signing
- Semgrep Registry
- GitHub Security Lab
- Trivy Documentation
- Snyk Learn - Security Education
- OWASP Top 10 (2021)
- CycloneDX SBOM Standard
- OPA - Open Policy Agent
- Kyverno Documentation
- CISA SBOM Resources
- Google SLSA GitHub Generator