Docker セキュリティ設定:root 実行を避ける本番向け完全ガイド
先月、知人の会社のコンテナ設定を見に行き、手元で docker inspect を叩いてみました——全部 root で動いていて、--privileged まで付いていました。2 週間後、コンテナが突破され、ハッカーはコンテナ脱出でホストを直接制御しました。
大げさな話ではありません。2024 年 1 月に公表された CVE-2024-21626 が典型例です。攻撃者はコンテナの「作業ディレクトリ」パラメータを制御するだけで、漏洩したファイル記述子を悪用し、ホストのファイルシステムを自在に操作できました。さらに衝撃的なのが、NSFOCUS(绿盟科技)の調査——Docker Hub 上のイメージの 76% にセキュリティ脆弱性があり、67% は高危険度です。
以前はあまり気にしていませんでした——Dockerfile も FROM ubuntu から RUN apt-get install だけ。コンテナの中だから隔離されているはず、と。負荷試験環境のコンテナが侵入されるまで。ログにハッカーがホストのディスクを mount するコマンドが残っていたとき、背筋が冷えました。
実は、コンテナを root から非 root ユーザーに切り替えるのは、思っているほど難しくありません。今日は次を整理します:なぜデフォルトの root が危険なのか、Dockerfile で非 root ユーザーを作る方法、--user の使い方、Capabilities や AppArmor の設定。読み終えれば、本番コンテナのセキュリティリスクを少なくとも 80% 下げられます。
なぜ root でコンテナを実行してはいけないのか?
コンテナ脱出:サンドボックスからホストへ一歩
多くの人は「コンテナ=サンドボックス」と考え、中で何をしてもホストに影響しないと思っています。しかし現実は、コンテナの隔離は Linux の namespace と cgroup に依存しており、VM のようなハードウェアレベルの隔離ではありません。設定ミスやカーネル脆弱性があれば、この壁は紙のように破れます。
CVE-2024-21626 は血の教訓です。攻撃者は runc(Docker の低レベルランタイム)が作業ディレクトリを処理する際、ホストファイルシステムを指すファイル記述子を漏洩させることを突き止めました。技術的に言えば、コンテナ内からホストの任意ファイルを読み書きでき、/usr/bin/bash のような重要バイナリを上書きすることも可能でした。Web アプリのコンテナが乗っ取られ、ホスト上の全コンテナがマイニング用に差し替えられる——仮説ではなく、実際に起きたことです。
より一般的な攻撃経路が --privileged モードです。このパラメータは、Docker に「ホストの全権限をこのコンテナに渡せ」と指示するのと同義です。コンテナ内 root はデバイス mount、カーネルモジュールロード、ネットワーク設定変更など、ホスト root の能力をすべて持ちます。NSFOCUS の報告では、攻撃者が特権コンテナから mount /dev/sda1 /mnt 一行でホスト HDD をマウントし、cron job でデータを定期送信——10 分もかかりませんでした。
もう一つ見落としがちなリスクが Docker Socket のマウントです。コンテナ内で Docker コマンドを使いたくて /var/run/docker.sock をマウントすると、ホスト上の全コンテナを制御する鍵を渡すことになります。侵入後、新しい特権コンテナを作って脱出し、ホストを制御する——Tencent Cloud のセキュリティチームもこの攻撃チェーンを記録しています。
なぜ root ユーザーが最大の突破口なのか?
核心はシンプルです:コンテナ内 root(UID 0)とホスト root(UID 0)は同一ユーザー。
「namespace で隔離されているのでは?」——確かにありますが、UID namespace はデフォルトで無効(互換性のため)です。カーネル脆弱性や設定ミスで namespace が効かなくなると、コンテナ内 root プロセスはホスト上でも root 権限を持ちます。私も SYS_ADMIN Capability 付きコンテナで root ユーザーがホストの procfs を mount し、/proc/sys/kernel/core_pattern にリバースシェルを書き込むテストを行い、ホスト root を取得——想像よりずっと簡単でした。
Alibaba Cloud のセキュリティ報告でも、コンテナ脱出の主な 5 原因はカーネル脆弱性、設定ミス、不安全なイメージ、権限乱用、不安全なコンテナ間通信——うち 4 つが root 権限と直結しています。非 root で実行するだけで、少なくとも 3 つのリスクを大幅に下げられます。
よくあるシナリオ:Node.js アプリが 80 番ポートをリッスンしたく、1024 未満は root が必要なので root で実行。Express にパストラバーサル脆弱性があれば /etc/passwd を読まれ、SSH でホストへ——コンテナ脱出すら不要です。
怖い話に聞こえますが、解決策は複雑ではありません。最小権限の原則——必要な権限だけ与え、安易に root を渡さない。
非 root ユーザーの設定:Dockerfile から始める
Docker コンテナ非 root ユーザーセキュリティ設定
Dockerfile で非 root ユーザーを作成し、ランタイムセキュリティパラメータを設定する完全ガイド。コンテナのセキュリティリスクを 80% 低減
Estimated time: PT30M
-
1
Step 1: Dockerfile で非 root ユーザーを作成
専用ユーザーとグループを作成: -
2
Step 2: ポートバインド問題への対処
ポートバインド問題への対処: -
3
Step 3: ランタイムセキュリティパラメータ
ランタイムセキュリティパラメータ: -
4
Step 4: Capabilities による権限の最小化
Capabilities による権限の最小化: -
5
Step 5: AppArmor/SELinux の有効化
Debian/Ubuntu は AppArmor(docker-default profile)、RHEL/CentOS は SELinux。デフォルト profile はすでに厳格で、多くの場合カスタム不要。 -
6
Step 6: イメージスキャンと継続監視
Trivy や Docker scan で定期的に脆弱性スキャン。高危険度は修正必須。異常再起動やリソース使用の監視、設定の定期監査。
非 root ユーザーの正しい作り方
標準的な書き方:
FROM node:18-alpine
# 専用ユーザーとグループを作成(UID/GID を指定)
RUN addgroup -g 5000 appgroup \
&& adduser -D -u 5000 -G appgroup appuser
# 作業ディレクトリ設定
WORKDIR /app
# ファイルをコピーして所有者を設定(重要!)
COPY --chown=appuser:appgroup package*.json ./
RUN npm install
COPY --chown=appuser:appgroup . .
# 非 root ユーザーに切り替え(以降のコマンドは appuser 権限)
USER appuser
# アプリ起動
CMD ["node", "server.js"]
シンプルに見えますが、各行に意味があります。
なぜ UID/GID を指定する? useradd で数字を指定せず自動割り当てにすると、コンテナごとに UID がずれ、データボリュームマウント時に権限不一致が起きやすくなります。固定 UID(例:5000)にすれば、ファイル権限の問題が大幅に減ります。
COPY --chown の利点 普通の COPY のあと RUN chown だと、root でコピーしたレイヤーと chown レイヤーの 2 段になります。--chown はコピー時に所有者を設定——レイヤーが省け、より安全です。chown を忘れて「Permission denied」で 30 分ハマった経験があります。
USER 命令の位置 その前のコマンド(RUN npm install など)は root、その後が appuser です。USER を早く書きすぎるとインストールが全部失敗します。root が必要な操作はすべて USER の前——これだけ覚えてください。
よくある落とし穴と対処
落とし穴 1:ポートバインド
非 root に変更して起動すると:Error: listen EACCES: permission denied 0.0.0.0:80。1024 未満は特権ポートです。
対処:
- 高ポートを使う(推奨):3000 や 8080 をリッスンし、Nginx や LB でリバースプロキシ
- NET_BIND_SERVICE Capability:後述。非 root でも低ポートをバインド可能
# アプリは 3000 をリッスン
EXPOSE 3000
USER appuser
CMD ["node", "server.js"] # 内部は 3000
docker-compose や K8s でマッピング:
ports:
- "80:3000" # ホスト 80 → コンテナ 3000
落とし穴 2:ログと一時ファイルの書き込み
Python アプリを非 root にしたら、/var/log への書き込み権限がなく起動失敗——半日調査した経験があります。
# アプリ用ログディレクトリを作成して権限付与
RUN mkdir -p /var/log/myapp && \
chown -R appuser:appgroup /var/log/myapp
USER appuser
より良い方法:stdout/stderr に出力し、Docker や K8s でログ収集。
# ファイルログではなく
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
落とし穴 3:マウントボリュームの権限不一致
ホストの /data が root 所有で、コンテナ内 appuser(UID 5000)が読めない。
# 悪い例
docker run -v /data:/app/data myapp
# コンテナ内 appuser は /app/data を読み書きできない
2 つの解決策:
# 方法 1:ホストで事前に権限設定
sudo chown -R 5000:5000 /data
# 方法 2:名前付きボリューム(Docker が権限管理)
docker volume create appdata
docker run -v appdata:/app/data myapp
ランタイムセキュリティパラメータ:—user とその他
—user でイメージ設定を上書き
サードパーティイメージに USER がなく root だけ——再ビルドが面倒なら、--user で実行時に指定できます。
# 方法 1:UID:GID を直接指定
docker run --user=1001:1001 nginx:latest
# 方法 2:ホストの現在ユーザー(開発環境向け)
docker run --user="$(id -u):$(id -g)" -v "$PWD:/app" node:18 npm test
# 方法 3:既知のユーザー名(イメージ内に存在する場合)
docker run --user=nobody redis:alpine
方法 2 はローカル開発で特に便利。コンテナ内テストで生成したファイルがホストで正しい UID になり、sudo 削除が不要です。
注意:—user は Dockerfile の USER を上書きします。非 root 設定済みイメージを --user=0:0 で root に戻すと意味がありません。使用前にイメージのデフォルト設定を確認してください。
読み取り専用ファイルシステム:書き込みを封じる
侵入されても、ファイルシステムが読み取り専用なら、マルウェア植入や設定改ざんの大半が無効化されます。
# 最もシンプルな読み取り専用設定
docker run -d --read-only nginx:alpine
# 一時ファイルが必要な場合
docker run -d \
--read-only \
--tmpfs /tmp \
--tmpfs /var/run \
nginx:alpine
--tmpfs はメモリ上のファイルシステム。再起動で消え、一時ファイルに最適。API サービスはログを stdout、セッションを Redis に——永続書き込み不要なら読み取り専用で、シェル取得後もやれることが限られます。
権限昇格禁止:no-new-privileges
setuid/setgid などによる権限昇格を防ぎます。SUID 付き /bin/su があっても root に昇格できません。
docker run --security-opt=no-new-privileges myapp
このオプション付きコンテナで sudo を実行すると「effective uid is not 0」で失敗——権限昇格攻撃への有効な対策です。
本番向け:組み合わせ設定
パラメータを組み合わせた本格的なセキュリティ設定:
docker run -d \
--name secure-webapp \
--user=5000:5000 \ # 非 root ユーザー
--read-only \ # 読み取り専用 FS
--tmpfs /tmp:size=64M \ # 64MB 一時領域
--security-opt=no-new-privileges \ # 権限昇格禁止
--cap-drop=ALL \ # 全 Capabilities 削除
--cap-add=NET_BIND_SERVICE \ # 必要なポートバインドのみ
-p 443:8443 \ # ポートマッピング
-v appdata:/app/data \ # データボリューム(唯一の書き込み先)
--memory=512m \ # メモリ制限
--cpus=1.0 \ # CPU 制限
myapp:1.0.0
パラメータは多いですが、それぞれ目的が明確です。本番のコアサービスはこのテンプレートで 2 年以上、セキュリティ事故ゼロ。トレードオフはデバッグの手間——コンテナ内でファイルを直接編集できない——その代償は十分に見合います。
K8s ユーザーは Pod の SecurityContext で同様の設定が可能:
securityContext:
runAsNonRoot: true
runAsUser: 5000
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
add: ["NET_BIND_SERVICE"]
権限の細分化:Capabilities メカニズム
Capabilities とは?root より安全な理由
従来の Linux 権限は「全部かゼロか」——root か一般ユーザーか。Capabilities は root のスーパー権限を 40 以上の独立した「能力」に分割し、必要なものだけ付与できます。
例えるなら、root は全室のマスターキー、Capabilities は必要な部屋の鍵だけ。侵入されても、権限のある部屋にしか入れません。
Docker はデフォルトで 14 個の Capabilities を保持:
- CHOWN:ファイル所有者変更
- NET_BIND_SERVICE:1024 未満ポートのバインド
- SETUID/SETGID:ユーザー/グループ ID 変更
- KILL:他プロセスへのシグナル送信
- DAC_OVERRIDE:ファイル読み書き権限チェックのバイパス
多くのアプリには十分ですが、いくつかは特に危険——必ず drop してください。
危険な Capabilities 一覧(絶対に付与するな!)
SYS_ADMIN — root の半分
mount、namespace 変更、カーネルモジュールロードなど。SYS_ADMIN 付きコンテナで unshare してホストディスクを mount されたら終わりです。
# 絶対にやるな!
docker run --cap-add=SYS_ADMIN myapp # ❌ 危険!
NET_ADMIN — ネットワーク設定の制御
ルーティング、ファイアウォール、パケットキャプチャ。VPN やソフトルータ以外には不要。
SYS_MODULE — カーネルモジュールのロード
カーネルにコードを挿入できる——危険度は言うまでもありません。
最小権限の実践
戦略 1:全削除してから必要分だけ追加(推奨)
docker run -d \
--cap-drop=ALL \ # 全 Capabilities 削除
--cap-add=NET_BIND_SERVICE \ # ポートバインドのみ(必要なら)
--cap-add=CHOWN \ # chown のみ(必要なら)
myapp
最もよく使う戦略。Capability 不足でエラーが出たら追加。setuid() で「Operation not permitted」なら --cap-add=SETUID。
戦略 2:危険なものだけ削除(手早い強化)
docker run -d \
--cap-drop=SYS_ADMIN \
--cap-drop=NET_ADMIN \
--cap-drop=SYS_MODULE \
--cap-drop=SYS_RAWIO \
myapp
必要な Capabilities が不明でも、明らかに危険なものを外すだけの手早い方法。
必要な Capabilities の判断方法
方法 1:試行錯誤(愚直だが有効)
# ステップ 1:drop all でエラー確認
docker run --cap-drop=ALL myapp
# エラー:bind: permission denied
# ステップ 2:NET_BIND_SERVICE を追加
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE myapp
# 起動成功!
方法 2:capsh で分析
コンテナ内で capsh --print:
$ docker run --rm -it --cap-drop=ALL ubuntu capsh --print
Current: =
# 空、Capabilities なし
$ docker run --rm -it ubuntu capsh --print
Current: = cap_chown,cap_dac_override,cap_fowner,...
# デフォルト 14 個
方法 3:一般的なアプリ要件表
| アプリ種別 | 必要な Capabilities | 説明 |
|---|---|---|
| Web アプリ(高ポート) | なし | 3000+ は特別な権限不要 |
| Web アプリ(低ポート) | NET_BIND_SERVICE | 80/443 リッスンに必要 |
| DB(MySQL/Postgres) | なし | デフォルトは高ポート |
| Nginx/Caddy | NET_BIND_SERVICE | 80/443 直接リッスン時 |
| VPN/ネットワークツール | NET_ADMIN | ルーティング/NIC 設定 |
ほとんどの業務アプリは drop all だけで動き、必要なら NET_BIND_SERVICE を 1 つ足す程度です。
強制アクセス制御:AppArmor と SELinux
何をするもの?一言で
Capabilities は「プロセスが何をできるか」、AppArmor/SELinux は「どのファイル・リソースにアクセスできるか」を制御。OS レベルの MAC(強制アクセス制御)で、root でも profile ルールを破れません。
例えるなら、社長(root)でもサーバールームには IC カードが必要——AppArmor/SELinux がその IC カードシステムです。
システムの選び方:
- Debian/Ubuntu:AppArmor がデフォルト
- RHEL/CentOS:SELinux がデフォルト
- 両方同時は不可(競合する)
AppArmor:シンプルで十分(初心者向け)
Docker は docker-default profile を自動適用。多くの場合、何も設定しなくてもバックグラウンドで保護してくれます。
# コンテナの AppArmor profile を確認
docker inspect mycontainer | grep -i apparmor
# "AppArmorProfile": "docker-default"
docker-default の制限:
- ファイルシステムの mount 不可
- カーネルパラメータ(/proc/sys/ 以下)の変更不可
- ホストの機密デバイス(/dev/ の大部分)へのアクセス不可
- AppArmor 自身の設定変更不可
AppArmor 有効コンテナでは、root でも mount /dev/sda1 /mnt は「Permission denied」。Capabilities + AppArmor の二重防御で、脱出難度は指数関数的に上がります。
SELinux:より強力だが複雑
各ファイル・プロセスに「ラベル」を付け、ポリシーでラベル間のアクセスを定義します。
# コンテナプロセスの SELinux ラベル
docker inspect mycontainer | grep -i selinux
# "ProcessLabel": "system_u:system_r:container_t:s0:c123,c456"
c123,c456 はカテゴリ——コンテナごとに固有の組み合わせで、コンテナ A がコンテナ B のファイルに触れないようにします。
SELinux の設定ハードルは高く、エラーメッセージも分かりにくい。Ubuntu なら AppArmor で十分。RHEL なら SELinux がデフォルトで保護していることが多く、触らなくてよい場合も多いです。
実践:どれを使う?どう使う?
シナリオ 1:開発環境
- デバッグのため一時無効(
apparmor=unconfinedやlabel=disable)もあり - ただし:開発で無効にしたら、本番で有効に戻すのを忘れないか?
シナリオ 2:テスト環境
- 必ず有効、デフォルト profile を使用
- セキュリティ設定とアプリ機能の衝突を早期発見
シナリオ 3:本番環境
- 必ず有効、妥協なし
- デフォルト profile、十分な理由がなければカスタムしない
- ログを定期監査し、違反アクセス試行を確認
経験上、DENIED の 99% は拒否されるべきもの——攻撃か、アプリ設計の問題。権限緩和が本当に必要な場面は極めて稀です。
完全なセキュリティチェックリスト
ここまでを実行可能な Checklist にまとめます。これに従えば、コンテナセキュリティは上位 20% に入れます。
イメージビルド段階
Dockerfile セキュリティチェック:
- ✅ 公式または信頼できるベースイメージ(出所不明は避ける)
- ✅ イメージバージョン固定(
node:latestではなくnode:18.17-alpine) - ✅ 専用非 root ユーザーを作成し UID/GID を指定
- ✅
COPY --chownでファイル所有者を設定 - ✅
USERはインストール後・起動前 - ✅ 高ポート(3000+)リッスン、または Capabilities を設定
- ✅ マルチステージビルドでイメージサイズと攻撃面を削減
- ✅ イメージに機密情報(鍵・パスワード)を含めない——環境変数や secrets で注入
イメージスキャン段階
必須のセキュリティスキャン:
# Docker 標準 scan(Snyk ベース)
docker scan myapp:latest
# Trivy(より高速・包括的、推奨)
trivy image myapp:latest
# Clair(CI/CD 統合)
# Harbor リポジトリで自動スキャン設定
Docker Hub 上 76% のイメージに脆弱性——定期スキャンは必須です。私たちのチーム規則:
- 高危険度:修正必須でないとデプロイ不可
- 中危険度:リスク評価と監視が必要
- 低危険度:記録して定期 review
ランタイム設定チェック
docker-compose 本番テンプレート:
services:
myapp:
image: myapp:1.0.0
user: "5000:5000" # 非 root ユーザー
read_only: true # 読み取り専用 FS
tmpfs:
- /tmp:size=64M # 一時ファイル用メモリマウント
security_opt:
- no-new-privileges:true # 権限昇格禁止
- apparmor=docker-default # AppArmor profile
cap_drop:
- ALL # 全 Capabilities 削除
cap_add:
- NET_BIND_SERVICE # 必要分のみ追加
volumes:
- appdata:/app/data:rw # 読み書き権限を明示
deploy:
resources:
limits:
cpus: '1.0' # CPU 制限
memory: 512M # メモリ制限
ports:
- "8080:8080"
本番運用チェック
日常監視:
- ✅ コンテナの異常再起動(攻撃によるクラッシュの可能性)
- ✅ リソース使用の異常(マイニングは CPU を食い尽くす)
- ✅ 監査ログでコンテナ操作を記録
定期監査:
- ✅ 実行中イメージも毎月スキャン(新規だけでなく)
- ✅
--privilegedや危険 Capabilities を使うコンテナがないか - ✅ ネットワークポリシーと公開ポートの見直し
よくある質問と解決策
Q1: 非 root にしたら起動時に権限エラーが出る
診断手順:
- エラー内容を確認(ファイル権限かポートバインドか)
- ファイル権限なら Dockerfile の
--chownとディレクトリ権限を確認 - ポートバインドなら高ポートに変更、または NET_BIND_SERVICE を追加
よくあるエラーと修正:
# エラー:Error: EACCES: permission denied, open '/app/logs/app.log'
# 原因:ログディレクトリに appuser の書き込み権限がない
# 修正:
RUN mkdir -p /app/logs && chown appuser:appgroup /app/logs
# エラー:Error: listen EACCES: permission denied 0.0.0.0:80
# 原因:非 root は低ポートをバインドできない
# 修正 1:3000 をリッスンしポートマッピング
EXPOSE 3000
# 修正 2:Capability 追加
docker run --cap-add=NET_BIND_SERVICE myapp
Q2: データボリュームマウント後に権限が合わない
最頻出の問題。3 つの解決策:
方法 1:ホストで UID/GID を事前設定(推奨)
# ホストで 5000:5000 に設定(コンテナユーザー UID と一致)
sudo chown -R 5000:5000 /data
docker run -v /data:/app/data myapp
方法 2:名前付きボリュームで Docker に権限管理
docker volume create --opt o=uid=5000,gid=5000 appdata
docker run -v appdata:/app/data myapp
Q3: root が本当に必要な場面は?ほぼない
「root が必要」と思われがちな場面にも代替があります:
| シナリオ | root 不要の方法 |
|---|---|
| 80/443 ポートバインド | NET_BIND_SERVICE、または高ポート + LB マッピング |
| システムパッケージインストール | Dockerfile の USER 前にインストール。実行時インストールは避ける |
| システム設定変更 | 環境変数や設定ファイルで注入。実行時変更しない |
| Docker Socket アクセス | 極めて危険!必要なら Docker API や K8s API を検討 |
唯一妥当だった root ケース:レガシー DB 移行ツールがベンダー都合で root 必須で、コード変更不可——使い捨ての隔離コンテナで実行し、完了後即削除。長期稼働は避けました。
Q4: サードパーティイメージが root の場合
優先順位:
- 公式の非 root 版を探す(
-rootlessや-nonrootタグ) --userで上書き
docker run --user=65534:65534 third-party-image # 65534 は nobody
- 元イメージをベースに Dockerfile で USER を追加
FROM third-party-image:latest
RUN adduser -D -u 5000 appuser
USER appuser
- メンテナに非 root 版を依頼(コミュニティへの貢献!)
結論
核心は一言:コンテナを root で動かす=ハッカーにバックドアを残す。
要点のおさらい:
- コンテナ脱出は理論ではない——CVE-2024-21626、特権コンテナ mount は実際の攻撃経路
- Dockerfile に USER、実行時に —user——コストは低く、効果は大きい
- Capabilities で権限を精密制御、drop all + 必要分追加がベストプラクティス
- 読み取り専用 FS、no-new-privileges、AppArmor の組み合わせで多層防御
- 76% のイメージに脆弱性——定期スキャンは必須
今日から 3 つ:
- Dockerfile を確認——USER がなければ追加
- 本番環境を監査——
--privilegedや root 実行のコンテナを特定し、変更可能なものは即修正 - イメージスキャンを CI/CD に組み込む——セキュリティチェックを自動化
セキュリティは一度きりではなく継続プロセス。まず root から非 root へ——その一歩で、すでに大多数より前に進めます。突破されてから後悔する前に——知人の会社の教訓は、そこにあります。
FAQ
なぜ root で Docker コンテナを実行してはいけないのですか?
CVE-2024-21626 などのコンテナ脱出脆弱性が示すように、コンテナ隔離は絶対安全ではありません。Docker Hub 上のイメージの 76% に脆弱性があり、67% は高危険度です。非 root ユーザーで実行すれば、コンテナのセキュリティリスクを 80% 低減できます。
Dockerfile で非 root ユーザーを設定するには?
root 権限が必要な操作はすべて USER の前に実行します。固定 UID/GID を指定すれば、データボリュームマウント時の権限問題を避けられます。
非 root ユーザーが 80/443 ポートをバインドできない場合は?
1) 高ポート番号を使う(推奨):
• アプリは 3000 や 8080 をリッスン
• Nginx やロードバランサでリバースプロキシ
• ポートマッピングでホスト 80 をコンテナ 3000 に転送
2) NET_BIND_SERVICE Capability を使う:
• 非 root でも低ポートをバインド可能
• root で 80/443 を直接リッスンするのを避けられる
Capabilities とは?最小権限をどう設定する?
ベストプラクティス:
• まず --cap-drop=ALL で全 Capabilities を削除
• 必要に応じて追加(例:ポートバインド用 NET_BIND_SERVICE)
• SYS_ADMIN、NET_ADMIN、SYS_MODULE など危険な Capabilities は絶対に付与しない
ほとんどの業務アプリは drop all だけで動き、必要なら NET_BIND_SERVICE を 1 つ足す程度です。
本番環境ではどのセキュリティパラメータを設定すべき?
• --user=5000:5000 で非 root ユーザー
• --read-only で読み取り専用ファイルシステム + --tmpfs で一時ディレクトリをマウント
• --security-opt=no-new-privileges で権限昇格を禁止
• --cap-drop=ALL で全 Capabilities を削除し、必要分だけ追加
• AppArmor/SELinux による強制アクセス制御を有効化
K8s ユーザーは Pod の SecurityContext で同様のポリシーを設定できます。
データボリュームマウント後に権限が合わない場合は?
1) ホスト側で UID/GID を事前設定(推奨):
• sudo chown -R 5000:5000 /data
• コンテナユーザーの UID と一致させる
2) 名前付きボリュームで Docker に権限管理を任せる:
• docker volume create --opt o=uid=5000,gid=5000 appdata
3) Dockerfile でアプリユーザー用ディレクトリを作成して権限付与
アプリに必要な Capabilities をどう判断する?
1) 試行錯誤:
• まず --cap-drop=ALL で実行し、エラーを確認
• エラー内容に応じて追加
2) capsh ツールで分析:
• docker run --rm -it ubuntu capsh --print で現在の Capabilities を確認
3) 一般的なアプリ要件を参照:
• Web アプリ(高ポート):特別な権限不要
• Web アプリ(低ポート):NET_BIND_SERVICE が必要
• VPN/ネットワークツール:NET_ADMIN が必要
8分で読めます · 公開日: 2025年12月18日 · 更新日: 2026年6月8日
Docker 実践ガイド
検索からこのページに来た場合は、前後の記事もあわせて読むと同じテーマの理解がかなり早く深まります。
前の記事
Dockerイメージのセキュリティスキャンと修正:Trivy実践チュートリアルとCI/CD統合ガイド
Docker Hubの76%のイメージにセキュリティ脆弱性が存在します。Trivyスキャンツールの実践的な使い方、体系的な脆弱性修正方法、CI/CD自動化統合まで解説。完全なコマンド例付きで、安全なコンテナアプリ構築を支援します。
第 29 / 37 記事
次の記事
Docker Secrets完全ガイド:コンテナのパスワードとAPIキーを安全に管理するベストプラクティス
データベースのパスワードをDockerfileに書くのはもうやめましょう。Docker Secretsで機密情報を安全に扱う方法、Docker/K8s/Vaultなどの選び方、本番向けチェックリストまで解説します。
第 31 / 37 記事
関連記事
Dockerfile入門:ゼロから最初の Docker イメージを作る(実例付き)
Dockerfile入門:ゼロから最初の Docker イメージを作る(実例付き)
Docker vs 仮想マシン:5分で理解する性能差とシーン別選び方ガイド
Docker vs 仮想マシン:5分で理解する性能差とシーン別選び方ガイド
Docker インストールの落とし穴ガイド 2025:permission denied から正常起動までの完全解決策
コメント
GitHubアカウントでログインしてコメントできます