Dockerの特定コンテナにアクセスできるPCを制限する
はじめに
職場で 遊んで 仕事している最中に、
Dockerで立ち上げた特定のコンテナへのアクセスを特定のPCに制限したい
という状況が発生しました。
最初はコンテナ起動のオプションでいい感じにできるだろうと思っていたのですが、
どうやらDockerのオプションだけでは細かいアクセス制御はできないようでした。
最終的にはパケットフィルタ(iptables)の設定をいい感じにすることで当初の目的を達成できたので、備忘録として残しておこうと思います。
想定環境は Linux OS です(RaspberryPi を含む)。
結論(TL;DR)
以下の設定で、指定したIPからのみ特定のコンテナ(ポート)へのアクセスを許可することができます。当たり前ですが、ルールを複数使う場合は RETURN
の後に REJECT
が来るようにしてください。
sudo iptables -I DOCKER-USER -p tcp --dport コンテナが開放しているポート番号 -m conntrack --ctorigdstport ホストPCの開放ポート番号 -j REJECT
sudo iptables -I DOCKER-USER -s 接続を許可するIPアドレス -p tcp --dport コンテナが開放しているポート番号 -m conntrack --ctorigdstport ホストPCの開放ポート番号 -j RETURN
詳細説明
iptables とは
Wikiより
iptablesは、Linuxに実装されたパケットフィルタリングおよびネットワークアドレス変換 (NAT) 機能であるNetfilter(複数のNetfilterモジュールとして実装されている)の設定を操作するコマンドのこと。Netfilterは、いわゆるファイアウォールやルータとしての役割を果たす。
誤解を恐れずに言えば、Linux のファイアウォールです。
iptables に設定したルールに基づいてパケットの受信や破棄が行われます。
フィルタルールは上から順に適用され、最初に適用されたルールが最優先となります。
Docker と iptables
Docker は iptables に DOCKER
と DOCKER-USER
という独自の チェイン(Chain)を持っています。チェインとは通信フィルタルールのグループだと思ってください。
publish オプション(-p)でコンテナを外部公開した場合、Docker は DOCKER
チェインへ自動的にフィルタルールとアドレス変換(NAT)ルールを追加します。
これが良いかどうかは各方面で議論されているようですが、この機能のおかげで何も考えずとも公開されたポートにアクセスすれば、コンテナで立ち上げたサービスを利用することができるようになっています。
しかし、publish オプション(-p)だけでは、
「パソコンAはアクセスしていいけど、パソコンBからはアクセスできないようにする」
といったコンテナへのアクセス制限(IPアドレス制限)をすることはできません。
このような複雑なパケット処理のルールを追加するためには、DOCKER-USER
チェインに独自ルールを追加する必要があります。
基本となるフィルタルールとNAT
特定PCのみアクセス許可するためには、次の2つのルールを追加する必要があります。
- パソコンAからのアクセスだったら、パケットを通すルール
- パソコンA以外からのアクセスだったら、パケットを破棄するルール
1. パソコンAからのアクセスだったら、パケットを通すルール(不完全)
特定のポート(コンテナ)へパソコンAからアクセスがあった場合は、パケットを通すルールです。プロトコルがUDPの場合は、-p udp
としてください。
sudo iptables -I DOCKER-USER -s パソコンAのIPアドレス -p tcp --dport ポート番号 -j RETURN
2. パソコンA以外からのアクセスだったら、パケットを破棄するルール(不完全)
特定のポート(コンテナ)へのアクセスを全て拒否(パケットを破棄)するルールです。
このルールは上のルールよりも下に置く必要があります。
sudo iptables -I DOCKER-USER -p tcp --dport ポート番号 -j REJECT
しかしこのままでは問題があります。
実は --dport
で指定するポート番号はコンテナ側で受け付けるポート番号になります。
例えば、nginx を以下のようなコマンドで起動したとします。
docker run -it -d -p 8080:80 --name my_nginx nginx
この場合、--dport
には ポート8080 ではなく ポート80 を指定しなければなりません。
これはフィルタルールを適用する前に、アドレス変換(NAT)の処理が入っているためです。
このままでは下記のような構成だとうまくいかなくなります。
サーバ名 | ホスト側のポート | コンテナ側のポート | ルール |
---|---|---|---|
nginx1 | 8080 | 80 | パソコンAからのみアクセス可 |
nginx2 | 8081 | 80 | すべてのPCからアクセス可 |
したがって、ホスト側のポート番号も考慮したフィルタを構成する必要があります。
ホスト側のポートも考慮したフィルタルール
iptables の conntrack
というオプションを利用します。
1. パソコンAから特定のホストポートへのアクセスだったら、パケットを通すルール
特定のポート(コンテナ)へパソコンAからアクセスがあった場合は、パケットを通すルールです。プロトコルがUDPの場合は、-p udp
としてください。
sudo iptables -I DOCKER-USER -s パソコンAのIPアドレス -p tcp --dport コンテナ側のポート番号 -m conntrack --ctorigdstport ホスト側のポート番号 -j RETURN
2. パソコンA以外から特定のホストポートへのアクセスだったら、パケットを破棄するルール
特定のポート(コンテナ)へのアクセスを全て拒否(パケットを破棄)するルールです。
このルールは上のルールよりも下に置く必要があります。
sudo iptables -I DOCKER-USER -p tcp --dport コンテナ側のポート番号 -m conntrack --ctorigdstport ホスト側のポート番号 -j REJECT
これで当初目的としていた動作が実現できました。
設定例
nginx サーバを2つ立ち上げて、片方はすべてのPCからアクセスを許可し、もう一方は特定のPCからのみアクセスを許可するように設定してみます。検証環境は以下の通りです。
項目 | バージョンなど |
---|---|
マシン | RaspberryPi4 4GB |
OS | Linux raspberrypi 5.10.17-v8+ #1421 SMP PREEMPT Thu May 27 14:01:37 BST 2021 aarch64 GNU/Linux |
Docker | Docker version 20.10.7, build f0df350 |
サーバ名 | ホスト側のポート | コンテナ側のポート | ルール |
---|---|---|---|
nginx1 | 8080 | 80 |
192.168.1.24 からのみアクセス可 |
nginx2 | 8081 | 80 | すべてのPCからアクセス可 |
初期の iptables 設定状態
$> iptables -L
(中略)
Chain DOCKER-USER (1 references)
target prot opt source destination
RETURN all -- anywhere anywhere
Chain DOCKER (2 references)
target prot opt source destination
1. iptables へのルール追加
sudo iptables -I DOCKER-USER -p tcp --dport 80 -m conntrack --ctorigdstport 8080 -j REJECT
sudo iptables -I DOCKER-USER -s 192.168.1.24 -p tcp --dport 80 -m conntrack --ctorigdstport 8080 -j RETURN
2. コンテナの立ち上げ
$> docker run -it -d -p 8080:80 --name nginx1 nginx
$> docker run -it -d -p 8081:80 --name nginx2 nginx
$> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
73fed61ceb4f nginx "/docker-entrypoint.…" 5 seconds ago Up 5 seconds 0.0.0.0:8081->80/tcp, :::8081->80/tcp nginx2
c987876549e0 nginx "/docker-entrypoint.…" 12 seconds ago Up 11 seconds 0.0.0.0:8080->80/tcp, :::8080->80/tcp nginx1
$> iptables -L
(中略)
Chain DOCKER-USER (1 references)
target prot opt source destination
RETURN tcp -- 192.168.1.24 anywhere tcp dpt:http ctorigdstport 8080
REJECT tcp -- anywhere anywhere tcp dpt:http ctorigdstport 8080 reject-with icmp-port-unreachable
RETURN all -- anywhere anywhere
Chain DOCKER (2 references)
target prot opt source destination
ACCEPT tcp -- anywhere 172.17.0.2 tcp dpt:http
ACCEPT tcp -- anywhere 172.17.0.3 tcp dpt:http
3. アクセス検証
192.168.1.24 からのアクセス結果
192.168.1.26 からのアクセス結果
狙い通り、特定のコンテナへのアクセスが制限されています。
おわりに
今回は Docker で立ち上げた特定のコンテナへのアクセスを特定のPCに制限する方法についてまとめました。
注意点として、今回の設定は PCを再起動すると全て消えます。設定の永続化をする場合は、iptables-persistent
などを使って永続化設定を行ってください。やり方は参考資料のURLを参照してください。
参考資料
- How to Whitelist IP Addresses to Access Desired Docker Containers? | by Divya Mamgai | The Startup | Medium
- Docker and iptables | Docker Documentation
- iptablesのnatでリダイレクト先ポートを外から直接アクセスできないようにする - 人間ハニーポット作戦
- Steps for limiting outside connections to docker container with iptables? - Server Fault
- Ubuntuでiptablesを再起動後にも保持する方法 - Qiita
- goto-linux.com | Linuxでの再起動後にiptablesルールを永続化する方法
Author And Source
この問題について(Dockerの特定コンテナにアクセスできるPCを制限する), 我々は、より多くの情報をここで見つけました https://qiita.com/takkaO/items/e623620649972e3093c2著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .