背景
Dockerコンテナの各サービスポートを外部からフィルター制限するファイアウォール設定についてまとめてみました。
動作環境
ホスト側
- OS:Ubuntu Server 22.04LTS
- Docker CE version 20.10.17
ファイアウォール設定する場所
全体のネットワーク構成としてサービスポートをフィルターする場所を決めます。
ホストの外側
クラウドのAWSではセキュリティグループ設定、オンプレ環境だとファイアウォール装置やルーター機器の機能が該当します。
この場合はDockerコンテナやホスト自体の管理外なので省略します。
ホスト自体
Ubuntuの場合は通常ufwが利用されますが、Dockerではiptableが使用されてufwの設定は反映されません。
ufwで設定したつもりがサービスポートが外部に開いていてハッキング攻撃を受けてしまうことがよくあります。
Dockerコンテナ
Dockerコンテナの設定でサービスポートを開放する範囲を変更出来ます。
サービスポートの場所
各DockerコンテナのサービスポートはDocker Network側とホスト側に存在します。
また各Dockerコンテナは個別の内部IPアドレス番号を持つので同じサービスポート番号が利用できます。
Dockerコンテナ同士のサービス連携ではDocker Network同士で接続が可能でホスト側にポートフォワードする必要はありません。
ホスト外部からDockerコンテナのサービスポートを利用する場合にホスト側にポートフォワード設定します。
Dockerコンテナのサービスポート設定
-pオプション
ホスト側にポートフォワードします。この場合はiptablesで設定される為、ufwの制御に関係なくサービスポートは開放されます。
mysql-server:
image: mysql:8.0
container_name: mysql-server
ports:
- "3306:33060"
上記の例の場合、Dockerコンテナ側のサービスポート番号は33060でホスト側に3306番でポートフォワードしています。
--exposeオプション
Docker Network間だけで通信してホスト外側にサービスを提供しない場合。この時はiptables設定は変更されません。
mysql-server:
image: mysql:8.0
container_name: mysql-server
expose:
- "3306"
上記の例の場合、Dockerコンテナ側のサービスポート番号は3306番で設定されホスト側には提供されません。
ホスト側iptables設定
さて本題です。
クラウドのAWSだとセキュリティグループで設定すれば良いのですがオンプレ環境などでDockerを利用する時にホスト側でファイアウォール設定します。
前に述べたようにufwの設定はDockerでは制御されずiptablesで設定します。
「iptables-persistent」インストール
ubuntuの場合iptablesの設定内容を再起動後も反映させる為に「iptables-persistent」パッケージをインストールします。
$ sudo apt install iptables-persistent
Chain DOCKER-USER
iptablesではChainのグループで順番にルールが適用されます。
Dockerのユーザー設定は「DOCKER-USER」のChainに設定します。
Dockerコンテナのネットワーク情報確認
iptables設定を行う為に必要な情報を確認します。
docker network ls
Docker Networkの一覧が表示されます。
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
95e77afXXXXX bridge bridge local
8b80a10XXXXX host host local
9bd3b4fXXXXX mysql_default bridge local
docker network inspect
Docker Networkの詳細を表示します。
ここで各DockerコンテナのIPアドレスが確認出来ます。
$ docker network inspect mysql_default
"Containers": {
"Name": "mysql-server",
"EndpointID": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"MacAddress": "01:02:03:04:05:06",
"IPv4Address": "172.20.0.2/16",
"IPv6Address": ""
}
}
iptablesルール設定
Chain DOCKER-USERにルール設定する時はホスト側インターフェースに対してDockerコンテナの内部IPアドレス番号とサービスポート番号を指定します。ホスト側では無いので注意。
- iptables -I DOCKER-USER -i [ホスト側インターフェース名] -p tcp --dport 3306 -d 172.20.0.2 -s 0.0.0.0/0 -j DROP
上記の例ではMySQLのDockerコンテナのサービスポートの3306番を内部IPアドレスとポート番号で指定してDROPで全てブロックしています。
- iptables -I DOCKER-USER -i [ホスト側インターフェース名] -p tcp --dport 3306 -d 172.20.0.2 -s 192.168.1.0/24 -j ACCEPT
次に特定の外部ネットワークだけを許可するルールを設定します。
この順番でルールを設定する事でファイアウォール設定が出来ます。
iptablesの設定確認
Chainのルールが複数あるので「DOCKER-USER」関連だけ表示させて確認してみます。
$ sudo iptables -L -n -v | grep -A7 "DOCKER-USER"
Chain DOCKER-USER (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT tcp -- eth0 * 192.168.1.0/24 172.16.20.2 tcp dpt:3306
0 0 DROP tcp -- eth0 * 0.0.0.0/0 172.16.20.2 tcp dpt:3306
iptablesの設定保存
iptablesの設定と動作が確認出来たらホストの再起動後でも有効になるように保存します。
$ sudo /etc/init.d/netfilter-persistent save