【Docker】Chain DOCKER-USER を利用してIP制限をしてみる

こんにちは

今回は Docker on VM で稼働している状態でIP制限を実施してみたので、そちらの備忘録となります

※Dockerコンテナ自体についての説明はしませんので、あらかじめご了承ください

 

■動機

実務で Docker on EC2 でコンテンツを動かしていたのですが、いくらfirewalldでIP制限をかけても一向にwebアクセス制限がかからず、

これは何か別のことをする必要があると思ったからです

 

■IP制限方法について

Docker on VM の構成でIP制限を実施する場合、通常のfirewalldコマンドではなく、Dockerによって管理されている iptablesDOCKER-USER チェインを利用します

DOCKER チェインも存在しますが、こちらは今回は変更しません

また、常に入力側のパケットは、これら2つのチェインによるチェックが第一に行われるので、

手動 あるいは他の ipables をベースとするファイアウォール(firewalldを含む)によって追加されたものは、

これらの Docker が追加したチェインの後で処理されるようになり、firewalldなどで追加したIP制限ルールは実質的に迂回されます

まとめると、Docker を通してポート(httpやhttpsなど)を公開している場合、ファイアウォールによってどのようなルールが追加されていてもポート公開やIP制限を実施することはできず、

Docker で公開しているポートに対して何らかのIP制限ルールなどを適用したい場合は、 DOCKER-USER チェインに「必ず」追加する必要があります

なお、デフォルトでは全ての外部ソース IP アドレスから Docker ホストへの接続が可能となっているため、

例えば コンテナに対して特定の IP アドレスもしくはネットワークからのみ許可するには、 DOCKER-USER フィルタ チェインの一番上にルールを追加していきます

※参照:Docker と iptables

 

■やってみた

それでは、実際に 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制限などは利用するかと思うので、本記事がお力になれば幸いです

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA