Dockerコンテナセキュリティ強化:2026年イメージからランタイムまで8層防御の完全ソリューション
あなたのコンテナ、本当に安全ですか?
コンテナ化デプロイはデリバリを高速化しましたが、セキュリティ負債も急速に蓄積しています。デフォルト設定のDockerコンテナはrootで実行し、Docker Socketをマウントし、リソース制限がありません——攻撃者がコンテナ境界を突破すると、ホストのroot権限を取得できます。サプライチェーン攻撃が頻発し、悪意あるイメージが本番環境に混入;環境変数からの機密情報漏洩;ランタイム権限昇格脆弱性の悪用……これらは仮定のシナリオではなく、毎日発生しているセキュリティインシデントです。
2026年、コンテナセキュリティは「オプション」から「必須」になりました。本記事では8層防御体系を構築し、イメージビルドからランタイム保護まで、コンテナセキュリティの死角をなくします。
8層防御体系概要
| 層 | 防御対象 | コア技術 |
|---|---|---|
| 第1層 | イメージセキュリティ | マルチステージビルド、distroless、イメージスキャン |
| 第2層 | サプライチェーンセキュリティ | イメージ署名、SBOM、不変タグ |
| 第3層 | 最小権限 | 非rootユーザー、読み取り専用ファイルシステム、ケイパビリティ削減 |
| 第4層 | ネットワーク分離 | ネットワークポリシー、Service Mesh、egress制御 |
| 第5層 | リソース制限 | CPU/メモリ制限、PIDs制限、OOMポリシー |
| 第6層 | システムコールフィルタリング | Seccompプロファイル、AppArmorポリシー |
| 第7層 | ランタイム監視 | 脆弱性検出、異常行動アラート、ファイル完全性 |
| 第8層 | コンプライアンス監査 | CISベンチマーク、セキュリティベースライン、監査ログ |
問題の深掘り:コンテナセキュリティの8つの脅威
| 脅威 | 攻撃経路 | 影響範囲 | 防御層 |
|---|---|---|---|
| 悪意あるベースイメージ | サプライチェーン汚染 | 全コンテナ | 第1-2層 |
| コンテナエスケープ | カーネル脆弱性悪用 | ホスト | 第3-6層 |
| 権限昇格 | root実行+過剰ケイパビリティ | ホスト | 第3層 |
| 横展開 | ネットワーク分離なし | クラスタ内全サービス | 第4層 |
| リソース枯渇 | リソース制限なし | 同ノード全コンテナ | 第5層 |
| 機密情報漏洩 | 環境変数/設定ファイル | データ漏洩 | 第3層 |
| サプライチェーン改ざん | イメージタグ上書き | 全コンテナ | 第2層 |
| ランタイム攻撃 | 既知脆弱性悪用 | コンテナ内サービス | 第7層 |
第1層:イメージセキュリティ
マルチステージビルド + distroless
FROM golang:1.23-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/server .
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=builder /app/server /server
USER 65532:65532
ENTRYPOINT ["/server"]
イメージスキャン
trivy image --severity HIGH,CRITICAL --exit-code 1 registry.example.com/app:v1.0.0
grype registry.example.com/app:v1.0.0 --fail-on critical
docker scout cves registry.example.com/app:v1.0.0
第2層:サプライチェーンセキュリティ
# イメージ署名
cosign sign --key cosign.key registry.example.com/app:v1.0.0
cosign verify --key cosign.pub registry.example.com/app:v1.0.0
# SBOM生成
syft registry.example.com/app:v1.0.0 -o spdx-json > sbom.json
不変タグ
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-latest-tag
spec:
validationFailureAction: Enforce
rules:
- name: require-image-tag
match:
resources:
kinds: [Pod]
validate:
message: "イメージは特定バージョンタグを使用してください"
pattern:
spec:
containers:
- image: "!*:latest"
第3層:最小権限
セキュアなDockerfile
FROM node:20-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --chown=appuser:appgroup . .
USER appuser
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
EXPOSE 3000
CMD ["node", "server.js"]
セキュアなdocker-compose.yml
version: "3.9"
services:
app:
image: registry.example.com/app:v1.0.0
security_opt:
- no-new-privileges:true
- seccomp:seccomp-profile.json
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
read_only: true
tmpfs:
- /tmp:noexec,nosuid,size=100m
user: "65534:65534"
deploy:
resources:
limits:
cpus: "1.0"
memory: 512M
pids: 100
networks:
- app-network
volumes:
- app-data:/app/data:noexec
networks:
app-network:
driver: bridge
internal: true
第4層:ネットワーク分離
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: app-network-policy
spec:
podSelector:
matchLabels:
app: web-app
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- port: 3000
egress:
- to:
- namespaceSelector:
matchLabels:
name: database
ports:
- port: 5432
第5層:リソース制限
apiVersion: v1
kind: LimitRange
metadata:
name: production-limits
spec:
limits:
- default:
cpu: "500m"
memory: "256Mi"
defaultRequest:
cpu: "100m"
memory: "128Mi"
max:
cpu: "2"
memory: "2Gi"
type: Container
第6層:システムコールフィルタリング
Seccompプロファイル
{
"defaultAction": "SCMP_ACT_ERRNO",
"defaultErrnoRet": 1,
"architectures": ["SCMP_ARCH_X86_64"],
"syscalls": [
{
"names": [
"accept", "bind", "brk", "close", "connect", "epoll_wait",
"exit", "exit_group", "fcntl", "fstat", "futex", "mmap",
"mprotect", "munmap", "open", "openat", "read", "recvfrom",
"sendto", "setgid", "setuid", "socket", "stat", "write"
],
"action": "SCMP_ACT_ALLOW"
}
]
}
AppArmorポリシー
#include <tunables/global>
profile docker-apparmor flags=(attach_disconnected,mediate_deleted) {
network inet tcp,
network inet udp,
/app/** r,
/app/data/** rw,
/tmp/** rw,
deny /proc/*/mem rw,
deny /sys/** rw,
deny /etc/shadow r,
capability net_bind_service,
deny capability sys_admin,
deny capability sys_ptrace,
}
第7層:ランタイム監視
apiVersion: falco.org/v1
kind: FalcoRule
metadata:
name: container-security-rules
spec:
rules:
- rule: Read sensitive file
desc: 機密ファイルの読み取りを検出
condition: >
container and open_read and fd.name in (/etc/shadow, /etc/passwd, /root/.ssh/id_rsa)
output: 機密ファイル読み取り (container=%container.name file=%fd.name)
priority: CRITICAL
- rule: Unexpected outbound connection
desc: 許可リスト外のアウトバウンド接続を検出
condition: >
container and outbound and not fd.sip in (10.0.0.0/8, 172.16.0.0/12)
output: 予期しないアウトバウンド (container=%container.name)
priority: WARNING
第8層:コンプライアンス監査
# CIS Docker Benchmark監査
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
docker/docker-bench-security
# kube-bench
kube-bench run --targets master,node,etcd,policies
# Docker daemonセキュリティ設定
cat > /etc/docker/daemon.json << 'EOF'
{
"log-driver": "json-file",
"log-opts": { "max-size": "10m", "max-file": "3" },
"storage-driver": "overlay2",
"userns-remap": "default",
"no-new-privileges": true
}
EOF
よくある落とし穴ガイド
落とし穴1:Rootlessモードでボリュームマウントの権限エラー
RootlessモードではコンテナUIDがホストのサブUID範囲にマッピングされます。
解決策:cat /etc/subuidでサブUID範囲を確認、ボリュームディレクトリの権限を調整。
落とし穴2:Seccomp設定が厳しすぎてアプリがクラッシュ
デフォルトですべてのシステムコールを拒否すると、アプリに必要なコールがブロックされます。
解決策:straceで必要なシステムコールを収集、緩やかな設定から始めて段階的に厳格化。
落とし穴3:AppArmor設定が反映されない
AppArmorプロファイルが正しくロードされていない。
解決策:aa-statusで確認、apparmor_parser -rで手動ロード。
落とし穴4:読み取り専用ファイルシステムで書き込み失敗
read_only: trueによりアプリが一時ファイルやキャッシュを書き込めない。
解決策:tmpfsマウントとvolumesを追加。
落とし穴5:イメージスキャンの誤検出が多すぎる
スキャンツールが大量の低重大度脆弱性を報告し、真の問題が埋もれる。
解決策:HIGHとCRITICALレベルのみに注目、.trivyignoreで既知の誤検出を除外。
エラートラブルシューティング
| # | エラーメッセージ | 原因 | 解決方法 |
|---|---|---|---|
| 1 | permission denied: Docker daemon socket |
Dockerグループ権限なし | sudo usermod -aG docker $USER |
| 2 | OCI runtime: rootfs propagation error |
Rootlessマウント競合 | ボリュームパスとUIDマッピングを確認 |
| 3 | seccomp: unknown syscall |
Seccompにシステムコール不足 | 許可リストに追加 |
| 4 | AppArmor: denied |
AppArmorポリシーがブロック | AppArmorプロファイルを更新 |
| 5 | write /proc/self/attr/current: permission denied |
no-new-privilegesとSELinuxの競合 | SELinuxポリシーを調整 |
| 6 | read-only file system |
読み取り専用ルートで書き込み | tmpfsまたはvolumeを追加 |
| 7 | OOMKilled |
メモリ制限が小さすぎる | メモリ制限を増加 |
| 8 | certificate verify failed |
レジストリ証明書検証失敗 | 信頼証明書を設定 |
| 9 | image signature verification failed |
イメージ署名検証失敗 | cosign署名と公開鍵を確認 |
| 10 | no space left on device |
イメージレイヤ過多 | docker system prune -a |
高度な最適化
1. Rootless Dockerデプロイ
dockerd-rootless-setuptool.sh install
echo "export DOCKER_HOST=unix:///run/user/$UID/docker.sock" >> ~/.bashrc
2. ビルド-署名-スキャンCIパイプライン
name: Build and Sign Image
on:
push:
tags: ['v*']
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: docker build -t registry.example.com/app:${{ github.ref_name }} .
- run: trivy image --exit-code 1 --severity HIGH,CRITICAL registry.example.com/app:${{ github.ref_name }}
- uses: sigstore/cosign-installer@v3
- run: cosign sign --yes --key env://COSIGN_KEY registry.example.com/app:${{ github.ref_name }}
3. 自動化ランタイムセキュリティポリシー
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: pod-security-defaults
spec:
validationFailureAction: Enforce
rules:
- name: require-non-root
match:
resources:
kinds: [Pod]
validate:
message: "コンテナは非rootで実行してください"
pattern:
spec:
containers:
- securityContext:
runAsNonRoot: true
- name: drop-all-capabilities
match:
resources:
kinds: [Pod]
mutate:
patchStrategicMerge:
spec:
containers:
- (name): "?*"
securityContext:
capabilities:
drop:
- ALL
比較分析
| 次元 | Dockerデフォルト | CIS Level 1 | CIS Level 2 | Rootless | Podman |
|---|---|---|---|---|---|
| root実行 | はい | いいえ | いいえ | いいえ | いいえ |
| ケイパビリティ削減 | なし | drop ALL | drop ALL+最小add | 自動制限 | 自動制限 |
| 読み取り専用FS | いいえ | 推奨 | 強制 | いいえ | いいえ |
| Seccomp | デフォルト | デフォルト | カスタム | デフォルト | デフォルト |
| AppArmor | なし | 推奨 | 強制 | なし | なし |
| イメージスキャン | なし | 推奨 | 強制 | 推奨 | 推奨 |
| イメージ署名 | なし | なし | 推奨 | 推奨 | 推奨 |
| ネットワーク分離 | なし | 推奨 | 強制 | 推奨 | 推奨 |
| リソース制限 | なし | 推奨 | 強制 | 推奨 | 推奨 |
| セキュリティレベル | 低 | 中 | 高 | 高 | 高 |
まとめ:Dockerコンテナセキュリティは単一技術ではなく、8層の防御深度システムです。イメージビルド段階のマルチステージビルドと脆弱性スキャンから、ランタイムのSeccomp/AppArmorポリシーとFalco監視まで、各層が攻撃面を縮小します。2026年のベストプラクティスは:デフォルト非root実行、読み取り専用ファイルシステム、最小ケイパビリティセット、イメージ署名検証、継続的脆弱性スキャンです。CIS Level 1ベースラインから始め、段階的にLevel 2にアップグレードし、最終的にRootlessデプロイを実現することをお勧めします。セキュリティに終点はなく、継続的な改善のみがあります。
オンラインツールおすすめ
- JSONフォーマッター:/ja/json/format — Seccomp設定とDocker APIレスポンスのフォーマット
- Base64エンコード/デコード:/ja/encode/base64 — Docker Registry認証トークンとSecretのエンコード/デコード
- Curl to Code:/ja/dev/curl-to-code — Docker APIデバッグcurlをコードに変換
ブラウザローカルツールを無料で試す →