第04章:“安全デフォルト”の作り方:テンプレ→例外だけ追加📦✨
この章のゴールはシンプルです👇
**「何も考えずに docker compose up しても、だいたい安全」**な雛形(テンプレ)を先に固定して、例外(便利だけど危険 / 必要な権限追加)は“別ファイル”に隔離します😎🔒
4-1. 発想:安全は“気合い”じゃなくて“デフォルト”で作る🧠🛡️
人間って、疲れてると👇こうなります🤣
- 「とりあえず動けばOK」😇
- 「あとで戻せばOK」😇(戻さない)
- 「今回だけ
privileged」😇(今回が増える)
だから最初からこうします👇
✅ 安全寄りのベース(base)を固定 ✅ 例外は“別ファイル”にして、毎回“明示的に”選ばせる ✅ 合成後の設定を可視化して、誤爆を早期発見👀
4-2. まず“テンプレの置き場所”を決める📁✨
おすすめ構成(最小だけど強い)👇
compose.yaml:**安全デフォルト(本体)**📦compose.override.yaml:**ローカル開発の便利設定(例外)**🛠️compose.risky.yaml:危険カード用(本当に必要な時だけ)☠️.env.example:環境変数の見本(秘密は入れない)🧾secrets/:秘密ファイル置き場(Git管理しない)🔑🚫.gitignore:secrets/や.envを除外🧹
Compose はデフォルトで compose.yaml と compose.override.yaml を読み込む設計なので、**「安全本体+開発だけの例外」**が自然に分離できます👍
(複数ファイル運用・マージの考え方は公式手順が一番安全です)(Docker Documentation)
4-3. “安全デフォルト”の核:よく効く5点セット✋🔒
ここからテンプレを作ります。まずは「アプリ(Node/TS想定)」に効く安全寄りセット👇
- rootで動かさない →
user(デフォルトはrootになりがち)(Docker Documentation) - コンテナの中を基本“読み取り専用” →
read_only(Docker Documentation) - 書き込みは“専用の一時領域”だけ →
tmpfs(/tmp とか)(Docker Documentation) - 余計な権限を落とす →
cap_drop(Docker Documentation) - PID1をちゃんとする →
init: true(地味に安定する)(Docker Documentation)
💡ポイント:「全部ON」が基本。困ったら“例外ファイル”で戻す、が正解🙆♂️
4-4. 実装:安全デフォルト compose.yaml を作る🧱✨
ここでは例として app + db(Node + Postgres)っぽい形にします。 (※dbは書き込みが必要なので、appと同じ“read_only最強セット”は使いません😄)
## compose.yaml ✅安全デフォルト(本体)
name: myapp
## ✅ 使い回す“安全寄りの共通パーツ”
x-app-security: &app_security
init: true # PID1をちゃんとする:contentReference[oaicite:6]{index=6}
user: "10001:10001" # root回避:contentReference[oaicite:7]{index=7}
read_only: true # 基本は読めるだけ:contentReference[oaicite:8]{index=8}
cap_drop:
- ALL # 余計な権限を落とす:contentReference[oaicite:9]{index=9}
tmpfs:
- /tmp # 書き込みは一時領域へ:contentReference[oaicite:10]{index=10}
restart: unless-stopped
services:
app:
<<: *app_security
build:
context: .
environment:
NODE_ENV: production
# ✅ “安全デフォルト”では外に公開しない(portsなし)
networks:
- internal
depends_on:
- db
db:
image: postgres:18
environment:
POSTGRES_DB: app
POSTGRES_USER: app
# ✅ パスワードはあとで secrets/ env で渡す(ここでは仮)
POSTGRES_PASSWORD: change_me
volumes:
- db_data:/var/lib/postgresql/data
networks:
- internal
# ✅ DBも外に公開しない(portsなし)
volumes:
db_data:
networks:
internal:
internal: true
ここが「安全デフォルト」っぽいポイント🥷
ports:を書かない=ホストへ公開されない🚪🔒internal: trueネットワーク=内部だけで話させる🕸️- appは root回避 + 読み取り専用 + tmpfs で “壊しにくい” 方向へ📦✨
4-5. “例外だけ追加”のやり方:override で開発向けに戻す🛠️🧩
開発中は、だいたい👇が必要になりますよね?
- ブラウザから叩きたい →
ports - ローカルのソースを反映したい →
volumes(bind mount) - TSビルド出力やnode_modulesが書き込みたい →
read_onlyを緩める(開発だけ)
それは compose.override.yaml に隔離します👇
## compose.override.yaml 🛠️開発だけの例外(自動で合成されやすい)
services:
app:
# ✅ 開発だけホストへ公開
ports:
- "3000:3000"
# ✅ 開発だけコード共有(必要なら)
volumes:
- ./:/workspace
# ✅ 開発だけ“書き込みOK”に戻す(本体はread_only:true)
read_only: false
environment:
NODE_ENV: development
command: ["npm", "run", "dev"]
✅「本体は安全」「開発だけ例外」 これがテンプレ化の勝ちパターンです🏆✨
4-6. 合成結果を“見える化”して事故を防ぐ👀🔍
複数ファイルはマージされます。そこで必須の習慣👇
- 今どんな設定で起動するの? →
docker compose configで確認 - 複数ファイルは
-fを重ねる(後ろが勝つ)(Docker Documentation)
例👇
## 合成後の最終形を表示(まずこれ!)
docker compose config
## 危険カードを“明示的に”足す(普段は使わない)
docker compose -f compose.yaml -f compose.risky.yaml config
4-7. マージでハマりやすい所(超重要)⚠️🧠
Compose のマージにはクセがあります。特に👇
✅ リスト(配列)は“足される”ことがある
ports / secrets / security_opt / cap_drop などは シーケンス扱いで、マージ時に結合されます(重複は消える系が多い)(Docker Documentation)
tmpfs などは結合されても重複が残るケースがある、という注意もあります(Docker Documentation)
つまり👇 「overrideで消したつもりが残ってた」事故が起きます😇
✅ “消す”には !reset / “置き換え”には !override を使う発想
このへんは公式のマージ仕様に沿ってやるのが安全です(Docker Documentation)
4-8. “危険カード”は別ファイルに隔離して、普段は触れない☠️🧱
例:docker.sock を渡す/特権が必要みたいなやつは、普段の開発ファイルに絶対混ぜない🙅♂️🔥
compose.risky.yaml を作って、使う時だけ -f で明示します👇
## compose.risky.yaml ☠️危険カード隔離(普段は使わない)
services:
app:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
そして運用ルールはこう👇
- このファイルは“起動コマンドに -f を書いた時だけ”入る
- 入れた理由をコメントで残す(未来の自分救済)📝✨
4-9. さらに強くしたい人向け:テンプレを“分割可能”にする🧩📦
テンプレが育つと compose.yaml が太ります😂
そこで👇が便利です:
- **Extensions(
x-...)や Fragments を使って“共通部品化”**すると、同じ安全設定を何度も書かずに済みます includeを使うと Composeファイルをモジュール化でき、マージより“読みやすい設計”にできます(対応バージョン要件あり)(Docker Documentation)
4-10. 章末ミニ演習(15〜25分)🧪⏱️
演習A:安全デフォルトで起動してみる✅
compose.yamlを作るdocker compose up -dappが 外部公開されてないことを確認(portsがないので基本叩けない)😄
演習B:例外(開発用)を足して動作確認🛠️
compose.override.yamlを作るdocker compose up -d --builddocker compose configを見て、portsが合成されたことを確認👀
演習C:危険カードは明示しないと入らないことを確認☠️
compose.risky.yamlを作るdocker compose up -d(←入らない)docker compose -f compose.yaml -f compose.risky.yaml up -d(←入る)
4-11. Windowsまわりの“安全の現実”も一言だけ🪟🔐
Docker Desktop を WSL2 バックエンドで使う場合、同じPC上の別WSLディストリビューションから Docker Desktop の中身に触れうる(例:wsl -d docker-desktop)という性質があります。最大限のセキュリティを求めるなら Hyper-V バックエンドの検討、という公式の注意もあります
あと、Desktop自体の脆弱性修正も普通に入るので、更新は超大事です🧯 例として、Docker Desktop のリリースノートでは CVE修正を含む更新が案内されています(Docker Documentation)
この章のまとめ📌✨
- 安全はテンプレで作る(人間の頑張りに頼らない)😄
- 本体=安全デフォルト/例外=別ファイルで分離📦🧩
docker compose configで合成後を必ず見る👀- 危険カードは
compose.risky.yamlに隔離して、-f明示でしか使えないようにする☠️🧱
次の章(第5章)は、このテンプレに対して「危険カードを具体的に捨てる(privileged / docker.sock / 秘密直書き)」を“置き換え案つき”でガッツリやると、かなり強くなりますよ😎🔥