Docker コンテナを使用する際、コンテナのポートをホストマシンにマッピングする必要が頻繁にあります。基本的なポートマッピングは "PORT:PORT" の形式で設定できます。例えば "6379:6379" は、コンテナの 6379 ポートをホストマシンの 6379 ポートにマッピングします。
しかし、この基本的なポートマッピングには重要な問題があります:デフォルトでは、ホストマシンにアクセスできるクライアントは誰でもこのポートにアクセスできます。本番環境では、通常特定の IP アドレスまたはネットワークセグメントのみがコンテナのポートにアクセスできるように制限する必要があります。
0x00 Docker ネットワークの動作原理
コンテナのポートをマッピングする際、Docker は iptables に関連するルールを追加します。データパケットの流れは以下の通りです:
flowchart TD A[クライアント] --eth0--> B[ホストマシン] --iptables NAT--> C[docker0 ブリッジ] --転送--> D[コンテナ] アクセスを制限するには、トラフィックを制御するために DOCKER-USER チェーンにルールを追加する必要があります。DOCKER-USER チェーンのルールは DOCKER チェーンのルールより前に実行されます。詳細なドキュメントは Packet filtering and firewalls を参照してください。
0x01 設定例
まずテスト用の Redis コンテナを作成します:
services:
redis:
image: redis:latest
restart: unless-stopped
ports:
- 6379:6379
volumes:
- /etc/localtime:/etc/localtime:ro
アクセシビリティをテストします
マシン1 (IP: 192.168.1.10):
マシン2 (IP: 192.168.2.10):
アクセス制御ルールの追加
以下のルールは、マシン1のネットワークセグメントのみが 6379 ポートにアクセスできるようにします:
# 既に確立された接続を許可
sudo iptables -I DOCKER-USER -m state --state ESTABLISHED,RELATED -j ACCEPT
# 特定のネットワークセグメントが特定のポートにアクセスすることを許可
sudo iptables -I DOCKER-USER -i eth0 -p tcp -s 192.168.1.0/24 --dport 6379 -j ACCEPT
# docker0 ブリッジが指定ポートへのトラフィックを転送することを許可
sudo iptables -I DOCKER-USER -i docker0 -p tcp --dport 6379 -j ACCEPT
sudo iptables -I DOCKER-USER -o docker0 -p tcp --dport 6379 -j ACCEPT
# その他のすべての該当ポートへのアクセス要求を拒否
sudo iptables -A DOCKER-USER -p tcp --dport 6379 -j DROP
# その他のポートのトラフィックを許可(オプション)
sudo iptables -A DOCKER-USER -j RETURN
複数ポート設定例
複数のポートを制限する必要がある場合は、複数ポートマッチを使用できます:
# 複数のポートへのアクセスを許可
sudo iptables -I DOCKER-USER -i eth0 -p tcp -s 192.168.1.0/24 -m multiport --dports 6379,8080,3306 -j ACCEPT
# docker0 ブリッジが複数のポートへのトラフィックを転送することを許可
sudo iptables -I DOCKER-USER -i docker0 -p tcp -m multiport --dports 6379,8080,3306 -j ACCEPT
sudo iptables -I DOCKER-USER -o docker0 -p tcp -m multiport --dports 6379,8080,3306 -j ACCEPT
# その他のすべてのこれらのポートへのアクセス要求を拒否
sudo iptables -A DOCKER-USER -p tcp -m multiport --dports 6379,8080,3306 -j DROP
ルールの検証
ルールが正しく設定されているか確認します:
# ルールリストを表示
➜ sudo iptables -L DOCKER-USER -n -v --line-numbers
Chain DOCKER-USER (1 references)
num pkts bytes target prot opt in out source destination
1 0 0 ACCEPT tcp -- * docker0 0.0.0.0/0 0.0.0.0/0 tcp dpt:6379
2 0 0 ACCEPT tcp -- docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:6379
3 28 1478 ACCEPT tcp -- eth0 * 192.168.1.0/24 0.0.0.0/0 tcp dpt:6379
4 9 540 DROP tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:6379
5 21 1107 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0
マシン1 (IP: 192.168.1.10):
マシン2 (IP: 192.168.2.10):
0x02 ルールの永続化
再起動後もルールが失われないように、設定した iptables ルールを保存する必要があります:
# Ubuntu/Debian システム
sudo netfilter-persistent save
# CentOS/RHEL システム
sudo service iptables save
0x03 ルールのクリーンアップ
ルールを削除する必要がある場合は、以下のコマンドを使用できます:
# DOCKER-USER チェーン内のすべてのルールをクリア
sudo iptables -F DOCKER-USER
# デフォルトルールに戻す(すべてのトラフィックを許可)
sudo iptables -A DOCKER-USER -j RETURN
0x04 注意事項
- ルールの順序が正しいことを確認し、ACCEPT ルールは DROP ルールの前に配置する必要があります
- ルールを追加する際には、コンテナ間の通信要件を考慮する必要があります
- カスタム Docker ネットワークを使用している場合は、ブリッジインターフェース名を適宜調整する必要があります
- 本番環境へのデプロイ前に、ルールの有効性を十分にテストすることを推奨します