セルフホスティング向けDockerセキュリティの必須ヒント
自社ホストサービスを安全に、防御から監視まで!
目次
- 🧗♀️ 勇敢な方へ
- 🔄
:latestの落とし穴 - 🔐 秘密鍵管理の正しい使い方
- 🌐 ネットワークの罠
- 🛡️ アクセス制御
- 🔍 監視と検証
- ⏰ 見落としがちなTips
- 🚀 本番環境チェックリスト
- 📚 補足資料
🧗♀️ 勇敢な方へ
Dockerサービスをセルフホスティングする場合、セキュリティは雲の上の誰かに任せられない。ポートスキャンや設定ミスからあなたを守ってくれるクラウドプロバイダーは存在しない。自宅ネットワークでアプリを立ち上げる場合も、VultrやDigitalOcean、Linode、AWS、Azure、Google CloudなどのVPSを借りる場合も、すべてのセキュリティ対策を自分で固め、それが正しく機能しているかを検証する責任がある。
本ガイドではDockerセキュリティの要点を掘り下げていく。あまり知られていないテクニックから実装が難しい手法まで網羅する。カンアリトークン、リードオンリーボリューム、ファイアウォールルール、ネットワークセグメンテーションと強化、認証プロキシの追加など、実践的な対策を解説する。
このガイドでは、家庭用ネットワークとパブリッククラウド環境の比較も行い、Nginxで基本的な認証プロキシを構成する方法を示します。最後まで読み進めることで、不正アクセスを試みる者(友人や家族、場合によっては自分自身さえも)を寄せ付けないオプションをいくつか手に入れるでしょう。
相当な内容量ですが、多くの項目が関連していますので、自分の環境に最も関連性の高いものを選んで実装してください。🍀
🔄 :latestタグの落とし穴
イメージの更新を維持することはセキュリティにおいて不可欠です。ただし、:latestに依存すると、レビューなしに破壊的な変更や脆弱なビルドが導入されるリスクがあります。
安全な更新方法
pullやbuildコマンドと更新コマンドを組み合わせ、意図的にイメージをリフレッシュした後、破損に気づける期間に再起動するようにしてください。
#!/bin/bashdocker compose pull && \ docker compose up -dバージョンピンニング vs latest
適切なバージョンを固定する選択は安定性とセキュリティのバランスを取る行為です。以下は一般的な戦略です:
# ... # 精確なバージョンピンニング。重要なサービス向け image: postgres:17.2
# パッチバージョンピンニング。非重要なサービス向け image: postgres:17.2
# メジャーバージョンピンニング。趣味プロジェクト向け image: postgres:17
# 避けたい最優先タグ image: postgres:latestDependabot や Renovate を使ってレビュー可能な更新PRを生成してください。深夜に再構築したくないようなサービスは特定バージョンまたはダイジェストを固定し、自動化ツールが更新を通知するようにしてください。
定期的にDockerイメージを更新するためのお気に入りツールがあれば教えてください!
🔐 シークレット管理
シークレットの管理方法は多様ですが、守るべき最も重要なルールの1つは 「Dockerイメージにシークレットをハードコードしたり、gitにコミットしたりしないこと」 です。これは最も一般的なセキュリティミスであり、長期的なリスクを伴い、修正も面倒です。
シークレットの安全な保存は、.envファイルやDocker secrets、1Password/Bitwarden、HashiCorp VaultやAWS Secrets Managerのようなシークレットマネージャーなど、多くのオプションがあります。使用ケースに応じて、適切な「労力とセキュリティのバランス」を選びましょう。
例: Docker Compose
以下は、appサービスを127.0.0.1:8080にバインドし、両コンテナをbackendカスタムネットワークに接続する例です。
networks: backend:
services: app: networks: - backend ports: # 可能であればローカルホストにバインド - "127.0.0.1:8080:8080" # ... 他の設定 database: image: postgres:17.1 # ポートは不要;backendネットワーク内からアクセス可能 networks: - backendネットワークのベストプラクティス
- 🏆 ポートの公開は行わない 最近、これは期待以上に有用であることを学びました!ネーミングされた(ブリッジ)ネットワークを使用する場合、コンテナ間はフィルタリングなしで相互にアクセスできます。これらはローカルネットワーク( NATゲートウェイ)の背後にあるかのように動作します。
- すべてのユースケースで可能ではない場合もありますが、バッチジョブを実行するコンテナや、主に
attachやexecでアクセスされるコンテナには有用かもしれません。
- すべてのユースケースで可能ではない場合もありますが、バッチジョブを実行するコンテナや、主に
- 🥇 Dockerネットワークを使用する コンテナ間の通信を制御・分離するためにDockerネットワークを使用します。
- 🥉 ローカルホストバインディング: 完璧ではありませんが、ループバックアドレス(例:
127.0.0.1:8080:80)へのバインドが一般的に推奨されます。構成を検証することを忘れないでください。
🛡️ アクセス制御
Dockerサービスを保護するためには、コンテナの権限制限やDockerソケットへのアクセス制限など、アクセス制御が不可欠です。
コンテナの権限制限
もう一つのアクセス制御の実践は、コンテナの権限を制限することです。これにより、権限昇格やトラフィックハイジャックなどの脅威の影響範囲を縮小できます。これは万能ではありませんが、多くのコンテナが本来必要なかった権限を削除します。
権限とは何ですか? Linuxカーネルで定義された名前付きの権限や能力です。( capabilities マニュアルページにフルリストがあります。) 例としてCAP_CHOWN(ファイル所有権の変更)、CAP_NET_ADMIN(ネットワークインターフェースの設定)、CAP_KILL(任意のプロセスの終了)などがあります。
必要な権限を特定する2つの方法は:
- 試行錯誤 この遅いが効果的な方法では、最初にすべての権限を削除し、アプリが動作するまで1つずつ追加します。
- 過去の作業を検索 “
project-namecap_dropDockerfile”や”project-namecap_dropdocker-compose.yml”を検索し、他者が既に作業を終えているか確認します。LLMが起点を提案できますが、コンテナをテストし、イメージドキュメントを読むまで推測と扱ってください。
権限のベストプラクティス
- すべての権限を削除:
cap_drop: [ ALL ]を使用してコンテナからすべてのLinux権限を削除します。 - 新しい特権の禁止:
security_opt: [ no-new-privileges=true ]を使用してコンテナが新しい特権を獲得することを防ぎます。
services: database: image: postgres:17.1 networks: [ db-network ] security_opt: - no-new-privileges:true cap_drop: - ALL cap_add: - CHOWN - DAC_READ_SEARCH - FOWNER - SETGID - SETUID db-admin: image: dpage/pgadmin4:4.1 networks: [ db-network ] ports: - "8081:80" # ... 他の設定networks: db-network:これでサービスはdb-networkネットワークを通じて相互に通信できます。Docker Composeはそのネットワークを自動的に作成します。
--external/external:オプションを使用して事前に作成されたネットワークに参加します。省略すると新しいネットワークが作成されます。
Dockerソケットのアクセス
⚠️ 警告: docker.sockは基本的にホストの管理者権限に相当します
⚠️ :roオプションはソケット経由で送信されるI/Oには影響しません!
これは単にソケットパス自体を読み取り専用でマウントすることを保証するだけであり、そのソケットを通じて送信されるAPI呼び出しは依然としてコンテナを作成したりホストパスをマウントしたり、おそらく意図せずに委任された他の非常に興味深い操作を行うことができるままです。
ソケットのベストプラクティス
- 🥇 Dockerソケットのマウントは避けてください。おそらくより良い代替案があります。
- 🫣 どうしても必要なら、狭いプロキシを前面に配置し、アプリが実際に必要とするAPIエンドポイントのみを許可してください。Tecnativaが最初に開発したdocker-socket-proxyプロジェクトを確認してください。その後、拒否された呼び出しが実際に拒否されていることを確認してください。
- 🤢 いいえ、_たとえ_非常に高い信頼性と低リスクのテスト環境でも、共有するのは問題かもしれません。
国のブロック!
時折役立つかもしれませんが、実際のセキュリティ境界ではありません。
ここでは音楽ではなく、地政学的実体について話しています…
自宅や友人向けにアプリをホスティングしている場合、予期しない国からのトラフィックをブロックしたり、予期される国からのトラフィックのみを許可したりできます。これはノイズを減らしますが、VPNやプロキシ、ボットネット、忍耐力のある攻撃者を止めることはできません。
中国からのすべてのトラフィックをブロックするためのこのスクリプトを確認してください:
curl -fsSL https://www.ipdeny.com/ipblocks/data/countries/cn.zone | \ while read line; do ufw deny from $line to any; donecurl -fsSL https://www.ipdeny.com/ipblocks/data/countries/cn.zone | \ while read line; do ufw deny from $line to any; done同様に、米国からのトラフィックのみを許可することもできます:
curl -fsSL https://www.ipdeny.com/ipblocks/data/countries/us.zone | \ while read line; do ufw allow from $line to any; doneCloudFlareプロキシホストのセキュリティ強化
自宅サーバーがCloudFlare IP(プロキシ)で保護されている場合、アクセスをCloudFlare IPとローカルネットワークのみに制限できます。
これは先ほどの国別ブロッキングと似ていますが、はるかに細かい制御が可能です。
ufw default deny incoming # 入力トラフィックをすべてブロック!!!ufw default allow outgoing # 出力トラフィックをすべて許可ufw allow ssh # SSHを許可
# ホストされたサービス用に専用のDMZ/VLANを設定したローカルサブネットへのアクセスを許可ufw allow from 10.0.0.0/8 to any port 443CloudFlare IPの許可
curl -fsSL https://www.cloudflare.com/ips-v4 |
while read line; do ufw allow from $line to any port 443; done
IPv6サポートの追加
curl -fsSL https://www.cloudflare.com/ips-v6 | \
while read line; do ufw allow from $line to any port 443; done
地理ベースの変更をテストするには、目的の国に位置する場所のVPNが役立ちます。詳しくは[監視と検証](#-monitoring--verification)セクションを参照してください。
### アプリケーション層セキュリティ
[network and host are security hardened,](#-network-hazard) が完了した後でも、さらにやるべきことがあるかもしれません。
今度は、サービス自体の「アプリケーション」層について考えなければなりません。そのデータベースは有効なパスワードを持っていますか?このコンテナはHTTPS/証明書の自動化を実行していますか?アプリケーションには組み込みの認証機能がありますか?どのメールアドレスがサインアップできるかに制限がありますか?デフォルトの資格情報や変更可能な環境変数がありますか?
実際に_把握_する唯一の方法は確認することです。このケースではまずREADMEやdocker-compose.yml、Dockerfile、.env.*などの主要なファイルから始めましょう。プロジェクト内だけでなく、サポートサービス(例: Postgres、Redisなど)についても同様に確認するのが理想です。
リバースプロキシ
もう1つの防御レイヤーは基本認証です。HTTPSなしで使用しないでください。レガシーサービスの場合、管理者ルートの前に基本認証を設定するだけで、ランダムなリクエストや認証なしのクローラーによる直接アクセスを防ぐことがよくあります。
location /admin { auth_basic "Restricted Access"; auth_basic_user_file /etc/nginx/.htpasswd; proxy_pass http://internal_admin:80; proxy_set_header X-Real-IP $remote_addr;}資格情報を生成するには:
htpasswd -c /etc/nginx/.htpasswd admin基本認証プロキシを使うと、内部サービスに到達する前に攻撃者がユーザー名とパスワードという追加の障害に直面します。
もう1つのオプションとして、TraefikやCaddyといったHTTPSと基本認証を自動化できるサービスを利用する方法もあります。
多くのドメインやサービスをGUIで管理したい場合は、Nginx Proxy Managerの利用をおすすめします。
🔍 監視と検証
これは最も重要でありながら最も見過ごされがちなステップです。最高のファイアウォールやネットワーク、ベストプラクティスを持っていても、検証を行わなければそれが機能しているかどうかまったく把握できません。
さらに、数少ないコマンドの知識や、どこで調べるべきかを知っているか否かが、侵害を防ぐかどうかの差になります。ハッカー気分を味わえることは加点です。(詳細と例については、監視と検証セクションに進んでください。)
信頼せず、二重に確認する
ポートの確認
⚠️ 重要: 自分が所有していないホストのスキャンを行わないでください。
ホームネットワークやVPSどちらにいても、世界に公開されているポートを把握する必要があります。
これを行う方法は2つあります:
- ネットワークの確認(
nmap、masscan) - オペレーティングシステムへの問い合わせ(
lsof、netstat、ss)
外部ネットワークでのテスト
現在の(パブリック)IPアドレスを取得するには、ifconfig.meなどのサービスが便利です:curl https://ifconfig.me。ホスティングプロバイダーのダッシュボードで確認する方法もあります。
curl -fsSL https://ifconfig.me# --> CURRENT PUBLIC IPパブリックIPを取得したら、外部ネットワークに接続する必要があります。友人のコンピュータ、スマートフォン/5Gホットスポット、または専用サーバホストを使用できます。
target_host="$(curl -fsSL https://ifconfig.me)"
# 注: `target_host` が目的のIPであることを確認してください
# 特定のポートをスキャン:nmap -A -p 80,443,8080 --open --reason $target_host# 上位100ポート:nmap -A --top-ports 100 --open --reason $target_host# 全ポート:nmap -A -p1-65535 --open --reason $target_hostネットワーク内でのテスト
nmap の使用に慣れるために、ローカルネットワークや自分のサーバー、ルーター、プリンタ、スマート冷蔵庫などをスキャンしてみましょう。
例: スキャンコマンド
# ローカルホストのすべてのオープンポートをスキャンnmap -sT localhost
# 自分のマシンのプライベートIPでサービスをスキャンnmap -sV 192.168.1.10
# ネットワーク内のサービス詳細を検出nmap -sn 192.168.0.0/24nmap -sn 10.0.0.0/24# またはDockerの 172.18.0.1/16nmap -sn 172.18.0.1/16% nmap -A --open --reason 192.168.0.87
Starting Nmap 7.95 ( https://nmap.org ) at 2025-01-06 13:51 MSTNmap scan report for dev02.local (192.168.0.87)Host is up, received syn-ack (0.0067s latency).Not shown: 995 closed tcp ports (conn-refused)PORT STATE SERVICE REASON VERSION22/tcp open ssh syn-ack OpenSSH 9.6p1 Ubuntu 3ubuntu13.5 (Ubuntu Linux; protocol 2.0)| ssh-hostkey:|_ 256 {FINGERPRINT} (ED25519)80/tcp open http syn-ack Caddy httpd|_http-server-header: Caddy|_http-title: Dev02.DanLevy.net443/tcp open ssl/https syn-ack|_http-title: Dev02.DanLevy.net1234/tcp open http syn-ack Node.js Express framework|_http-cors: GET POST PUT DELETE PATCH|_http-title: Dev02.DanLevy.net (application/json; charset=utf-8).Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .Nmap done: 1 IP address (1 host up) scanned in 13.36 secondsオープンポートの確認
lsof に慣れましょう - macOS と Linux で利用可能です。これはネットワーク状態やディスクアクティビティを詳細に表示します。
# 特定ポートのモニタリングsudo lsof -i:80 -Pn# 確立済み接続の監視sudo lsof -i -Pn | grep ESTABLISHED# リスン状態の表示sudo lsof -i -Pn | grep LISTEN
# IPアドレスではなくネットワーク名を表示(逆引きDNS検索が非常に遅くなる可能性あり)sudo lsof -i -P | grep LISTEN
# すべてのネットワーク接続を監視sudo watch -n1 "lsof -i -Pn"サンプル出力

ファイル監視
どのプロセスが最もハードドライブ帯域幅を使用しているかを特定するには iotop を使用できます:
sudo iotop個別のファイル変更を確認するには、Linuxでは inotifywait、MacOSでは fswatch を使用できます。これはフォルダ単位またはシステム全体で不正な動作や異常な挙動を検出するのに役立ちます。
# ディレクトリ内のすべてのファイル変更を監視sudo inotifywait -m /path/to/directoryMacOSでは fswatch を使用できます:
インストールはbrew install fswatchで行う
fswatch -r /path/to/directory⏰ よく見落とされるヒント
-
認証試行や重要なエンドポイントへのレート制限
Nginxのlimit_reqモジュールやSSHアクセス用のfail2banを通じて、ブルートフォース攻撃へのスロットリングはおそらく良い考えです。私は「おそらく」と言います。IPv6や安価なボットネットの時代において、それはかつての状態とは異なっているからです。 -
可能な限り読み取り専用ボリュームを使用する
services:webapp:volumes:- ./config:/config:ro他のベストプラクティス(非rootユーザー、最小限のフォルダ権限)と組み合わせることで、
:roボリュームマウントオプションはコンテナ内からの誤った変更や一部の書き込み試行を防ぐ追加の保護を提供します。これは、すでに広範な権限を持つプロセスがホストを攻撃するのを防ぐことはできません。 -
コンテナアクセスの定期的な監査
コンテナがシークレット、ポート、マウントを必要としない場合、それらを削除しましょう! -
WiFiの不審者に注意
WiFiパスワードを変な奴らに教えてはいないでしょう?特に。しかし、友人…いや、家族にも教えていたかもしれません。彼らがどのアプリを持っているか、それがあなたのSSIDやパスワードを世界に共有していないか、あなたは決して知りません。
ホームネットワーク vs. 公共プロバイダー vs. チューニング
-
バーチャル分離/DMZ
ホームサーバーを別のVLANやDMZに配置できる場合は、それを行いましょう。これにより、サーバー側からの潜在的な侵害で内部デバイスがアクセス不能になることを防ぎます。- ホームサーバー専用のルーターまたはVLANを使用する。
- ホームサーバー専用のWiFiネットワークを使用する。
- ホームサーバー専用のサブネットを使用する。
-
クラウドプロバイダー: Hetzner、Vultr、DigitalOcean、Linode、AWS、Azure、Google Cloudはすべて異なるファイアウォール機能を提供しています。
- 一部のプロバイダーやサービスはデフォルトでポートをブロックしています。一部はオプトインや追加料金のオプションを提供しています。サービスプロバイダーのドキュメントを確認してください。
- 多くのプロバイダーは高度な監視と脅威検出サービスを提供しています。
-
VPN & トンネリング: 公開インターネットにサービスを露出せずにインターネット上でセキュアに接続するため、VPNに類似したオプションやトンネリングサービスの使用を検討してください。
- TailScale、ngrok、ZeroTier。
- WireGuard、OpenVPN。
🚀 本番環境チェックリスト
- シークレット: すべてのシークレットはランダムに生成され、安全に保存されている
- アップデート: コンテナのアップデート戦略が文書化され、自動化されている(テキストファイルに数行のコマンドでも構いません)
- ネットワーク: 必要なポートのみ公開され、内部ネットワークが設定されている
- ファイアウォールルール: デフォルトで拒否、明示的な許可、必要に応じて国ごとのブロック
- リバースプロキシー: Nginx、Caddy、Traefikで基本認証のレイヤーを追加
- キャニスターコイン: 実際に調査する可能性のある機密ファイルや資格情報を近くに配置する
- 監視:
nmap、lsof、inotifywait、glancesなどでシステムを把握する - バックアップ戦略: テスト済みで、好ましくは自動化されており、オフサイト保存されている
- 最小限の特権: ルートでないコンテナユーザー、読み取り専用のボリューム
📚 補足資料
ありがとう
熱心なRedditユーザーに感謝します:
読んでもらってありがとう!このガイドがお役に立てたなら大変嬉しく思います。ご質問や提案があれば、以下のSNSからご連絡ください。あるいは「GitHubで編集」リンクをクリックしてPRを作成していただければ幸いです!❤️