ファイアウォールの罠:Dockerが密かに「裏口」を開ける時
VPSを借りて、意気揚々とUFWをインストールし、ufw deny 8080コマンドでサーバーを「閉鎖」したとします。しかし、-p 8080:80パラメータを指定してDockerを実行した瞬間、閉じたはずのポートが全世界に開放されてしまいます。信じてください、これは新人SysAdminが多く経験する「手痛い教訓」です。
実際、これはソフトウェアのバグではありません。DockerがLinuxカーネルと直接「対話」する仕組みの結果です。油断していると、ファイアウォールが厳格に動作していると思い込んでいる間に、RedisやMongoDBのような機密性の高いコンテナがハッカーの「格好の標的」になってしまいます。
紛争の本質:Docker vs iptables
UFWは、iptablesコマンドを扱いやすくするための装飾層(フロントエンド)に過ぎないと考えてください。一方で、Dockerは強力な「プレイヤー」であり、自らもiptablesを使用してコンテナへのデータフローを制御します。
Dockerが起動すると、iptablesの優先順位1位に自分のルールを「割り込ませ」ます。パケットがVPSに届くと、UFWの保護層に触れる前にDockerのルールに衝突します。その結果、DockerはUFWが外で絶叫しているのを尻目に、ゲストを「どうぞ」と招き入れてしまうのです。
実戦経験から言えば、これは致命的な脆弱性です。UFWがstatus: activeと表示されているにもかかわらず、6379ポートが露出してからわずか2時間で、顧客のRedisサーバーがデータを「一掃」され、ランサムウェアに感染したのを目撃したことがあります。
解決策1:ポートをLocalhostに縛り付ける(手軽で効果的)
同じサーバー上の別のアプリケーション(リバースプロキシとしてのNginxなど)のためにコンテナが必要なだけなら、決して通常のパブリックポート公開を使わないでください。
次のコマンドを実行する代わりに:
docker run -d -p 8080:80 nginx
次のように修正してください:
docker run -d -p 127.0.0.1:8080:80 nginx
このテクニックにより、Dockerはサーバー内部からのリクエストのみを「リッスン」するようになります。DockerがUFWをすり抜けたとしても、パブリックIPアドレスには存在しないため、インターネット上の悪意のあるユーザーが8080ポートを見つけることはできません。私はこの方法を会社の全マイクロサービススタックに適用しており、非常に安心で管理も簡単です。
解決策2:ufw-dockerを使用する(プロフェッショナルで正攻法)
UFWの「手軽で強力」なスタイルでDockerを管理したいなら、ufw-dockerが最適です。これは、Dockerとファイアウォールのルールを完璧に同期させるスクリプトです。
まず、スクリプトをダウンロードします:
sudo wget -O /usr/local/bin/ufw-docker https://github.com/chaifeng/ufw-docker/raw/master/ufw-docker
sudo chmod +x /usr/local/bin/ufw-docker
次に、初期化コマンドを実行して、スクリプトにiptablesのチェーンを自動再構成させます:
ufw-docker install
これで、ufw allowの代わりにufw-docker allowを使用できるようになります。例えば、web-appという名前のコンテナに対してポート80を開放するには:
ufw-docker allow web-app 80/tcp
すべてが期待通りに動作します。UFWが主導権を握り、Dockerが勝手に「ドアを開ける」ことはもうありません。
解決策3:DOCKER-USERを手動で調整する
深く「いじり倒す」のが好きな人のために、Dockerはカスタムルールを挿入するためのDOCKER-USERという専用エリアを用意しています。ここのルールは、Dockerがパケットを処理する前に常に優先的に実行されます。
UFWの設定ファイルを開きます:
sudo nano /etc/ufw/after.rules
そして、ファイルの末尾に次のコードを追加します:
# デフォルトで外部からDockerへのアクセスをすべてブロック
*filter
:DOCKER-USER - [0:0]
-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16
# オフィスIP(例:1.2.3.4)のみポート8080へのアクセスを許可
-A DOCKER-USER -p tcp -m tcp --dport 8080 -s 1.2.3.4 -j RETURN
# それ以外の見知らぬユーザーをすべてブロック
-A DOCKER-USER -p tcp -m tcp --dport 8080 -j DROP
COMMIT
軽い警告:設定ミスを避けるために、内部IP範囲(例:172.17.0.0/16)を正しく理解しておく必要があります。ここでの小さなミスが、コンテナをインターネットから完全に「孤立」させてしまう可能性があります。
まとめとアドバイス
Dockerが勝手にポートを開放するのは、アプリを即座に動作させるための機能ですが、本番環境(Production)ではリスクとなります。データを失ってから慌ててポートを閉じる方法を探すようなことにならないようにしましょう。
要約すると、以下の3つの黄金律を覚えておいてください:
- 内部サービス:常にポートを
127.0.0.1にバインドする。 - 集中管理:プロフェッショナルな管理のために
ufw-dockerを使用する。 - 厳戒態勢:Dockerのネットワークシステムが崩壊するのを防ぐため、
daemon.jsonファイルでiptables: falseを絶対に設定しない。
サーバーセキュリティは長い道のりです。今日開放する一つ一つのポートを厳格に管理することから始めましょう。

