こんにちは
今回は Docker on VM で稼働している状態でIP制限を実施してみたので、そちらの備忘録となります
※Dockerコンテナ自体についての説明はしませんので、あらかじめご了承ください
■動機
実務で Docker on EC2 でコンテンツを動かしていたのですが、いくらfirewalldでIP制限をかけても一向にwebアクセス制限がかからず、
これは何か別のことをする必要があると思ったからです
■IP制限方法について
Docker on VM の構成でIP制限を実施する場合、通常のfirewalldコマンドではなく、Dockerによって管理されている iptables の DOCKER-USER チェインを利用します
※DOCKER チェインも存在しますが、こちらは今回は変更しません
また、常に入力側のパケットは、これら2つのチェインによるチェックが第一に行われるので、
手動 あるいは他の ipables をベースとするファイアウォール(firewalldを含む)によって追加されたものは、
これらの Docker が追加したチェインの後で処理されるようになり、firewalldなどで追加したIP制限ルールは実質的に迂回されます
まとめると、Docker を通してポート(httpやhttpsなど)を公開している場合、ファイアウォールによってどのようなルールが追加されていてもポート公開やIP制限を実施することはできず、
Docker で公開しているポートに対して何らかのIP制限ルールなどを適用したい場合は、 DOCKER-USER チェインに「必ず」追加する必要があります
なお、デフォルトでは全ての外部ソース IP アドレスから Docker ホストへの接続が可能となっているため、
例えば コンテナに対して特定の IP アドレスもしくはネットワークからのみ許可するには、 DOCKER-USER フィルタ チェインの一番上にルールを追加していきます
■やってみた
それでは、実際に Docker on VM の構成でIP制限を実施してみます
環境のプラットフォームはAWSのEC2(OS:Almalinux9)を利用し、コンテンツは以前のこちらの記事のものを丸々利用して、docker-composeで稼働させています
1. コンテナ起動確認
まずは各Dockerコンテナが正常に起動しているかどうか確認します
docker container ps
[root@ip-10-0-10-144 conf]# docker container ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 01121105ef4b docker-web01 "/docker-entrypoint.…" About an hour ago Up About an hour 0.0.0.0:80->80/tcp, [::]:80->80/tcp web01-container 9c3496dfb01a docker-app01 "docker-php-entrypoi…" About an hour ago Up About an hour 0.0.0.0:9000->9000/tcp, [::]:9000->9000/tcp app01-container e5f415132621 docker-db01 "docker-entrypoint.s…" About an hour ago Up About an hour 33060/tcp, 0.0.0.0:3307->3306/tcp, [::]:3307->3306/tcp db01-container
→ 起動は大丈夫そうです
2. firewalldでIP制限を追加する
それでは一度 firewalld のみでIP制限を追加し、追加後も問題なくブラウザ上からコンテンツが見れることを確認します
まずは現行の設定を確認します
sudo firewall-cmd --list-all
[root@ip-10-0-10-144 conf]# sudo firewall-cmd --list-all public (active) target: default icmp-block-inversion: no interfaces: eth0 sources: services: cockpit dhcpv6-client ssh ports: protocols: forward: yes masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:
→ httpなどへのIP制限はないですね
特定IPからのhttpアクセスをブロックするルールを追加します
※address=”xxxx.xxxx.xxxx.xxxx” は実際のIPアドレスに変更してください
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="xxxx.xxxx.xxxx.xxxx" service name="http" reject'
firewall-cmd --reload
sudo firewall-cmd --list-all
[root@ip-10-0-10-144 conf]# sudo firewall-cmd --list-all
public (active)
target: default
icmp-block-inversion: no
interfaces: eth0
sources:
services: cockpit dhcpv6-client ssh
ports:
protocols:
forward: yes
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
rule family="ipv4" source address="xxxx.xxxx.xxxx.xxxx" service name="http" reject
→ リッチルールで追加されました
それでは、IP制限を実施したIPアドレスからコンテンツを確認してみます
→ 問題なくコンテンツが見えているので、やはり Dockerコンテナでポートを公開しているコンテンツには、firewalldで追加したルールは効かないようです
一旦追加したルールを削除しておきます
firewall-cmd --permanent --remove-rich-rule='rule family="ipv4" source address="xxxx.xxxx.xxxx.xxxx" service name="http" reject'
firewall-cmd --reload
3. DOCKER-USER チェインにIP制限ルールを追加する
ついに DOCKER-USER チェインを利用したIP制限を実施してみます
今回は分かりやすいように特定のIPからの接続はブロックし、それ以外は許可するようなルールを追加してみます
まず始めに、現在のルールを確認してみます
sudo iptables -L -n -v | grep -A7 "DOCKER-USER"
9226 18M DOCKER-USER all -- * * 0.0.0.0/0 0.0.0.0/0 9226 18M DOCKER-FORWARD all -- * * 0.0.0.0/0 0.0.0.0/0 Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain DOCKER (2 references) pkts bytes target prot opt in out source destination -- Chain DOCKER-USER (1 references) pkts bytes target prot opt in out source destination
→ DOCKER-USER チェインには特段ルールが設定されていません
次に特定IPからはhttpアクセスをブロックし、それ以外は許可するようなルールを追加してみます
iptables -I DOCKER-USER -s xxxx.xxxx.xxxx.xxxx -p tcp --dport 80 -j DROP
→ DOCKER-USER のチェインルールに対して、ソースIPが xxxx.xxxx.xxxx.xxxx からの80番ポートへのアクセスをドロップするようにしています
設定を確認してみます
sudo iptables -L -n -v | grep -A7 "DOCKER-USER"
[root@ip-10-0-10-144 conf]# sudo iptables -L -n -v | grep -A7 "DOCKER-USER" 9282 18M DOCKER-USER all -- * * 0.0.0.0/0 0.0.0.0/0 9254 18M DOCKER-FORWARD all -- * * 0.0.0.0/0 0.0.0.0/0 Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain DOCKER (2 references) pkts bytes target prot opt in out source destination -- Chain DOCKER-USER (1 references) pkts bytes target prot opt in out source destination 28 1456 DROP tcp -- * * xxxx.xxxx.xxxx.xxxx 0.0.0.0/0 tcp dpt:80
→ DOCKER-USER にルールが設定されました
それでは、ブラウザ上から動作確認してみましょう
→ ERR_CONNECTION_TIMED_OUT となり、IP制限が効いてそうです
※ネットワークを変えた場合は、正常にコンテンツの画面が表示されたことを確認しました
なお、今回の場合だと iptables を再起動するとルールが消えてしまうので、永続化する場合は下記で保存してください
dnf install iptables-services
service iptables save
[root@ip-10-0-10-144 conf]# service iptables save iptables: Saving firewall rules to /etc/sysconfig/iptables: [ OK ]
■最後に
いかがでしたでしょうか
AWSを利用している場合は、基本的にはセキュリティグループを利用したIP制限になると思うので、あまりiptablesなどは利用しないと思います
ただ、VM単体で動いているDocker環境だとまだまだiptablesを利用したIP制限などは利用するかと思うので、本記事がお力になれば幸いです

