LoginSignup
0
0

More than 3 years have passed since last update.

Dockerコンテナからのネットワークアクセスを禁止する(CentOS Stream 8)

Posted at
docker run --rm -it centos curl https://example.com

を弾きたい。それだけなら--net=noneで簡単なのだけれど、

docker run --rm -it -p 8080:80 nginx

で外部からのアクセスは受け付けるようにしたい。

一時的に弾く。

sudo iptables -F DOCKER-USER
sudo iptables -A DOCKER-USER -m state --state RELATED,ESTABLISHED -j RETURN
sudo iptables -A DOCKER-USER -s 172.17.0.0/12 -j REJECT
sudo iptables -A DOCKER-USER -j RETURN

元に戻す。

sudo iptables -F DOCKER-USER
sudo iptables -A DOCKER-USER -j RETURN

永続化する。

sudo systemctl enable nftables

で、

[Service]
ExecStartPost=iptables -F DOCKER-USER
ExecStartPost=iptables -A DOCKER-USER -m state --state RELATED,ESTABLISHED -j RETURN
ExecStartPost=iptables -A DOCKER-USER -s 172.17.0.0/12 -j REJECT
ExecStartPost=iptables -A DOCKER-USER -j RETURN

を書き込む。

iptablesで何かするときは、ミスるとその瞬間にSSHも繋がらなくなるので、ネットワーク以外のバックアップ手段を確認しておくべき。

詳細

ホストはCentOS Stream 8。CentOS 8はサポートが1年になってしまったので、おとなしくStreamを使います。

$ cat /etc/os-release
NAME="CentOS Stream"
VERSION="8"
 :

Dockerは20.10.3。

$ docker -v
Docker version 20.10.3, build 48d30b5

なぜこんなことをしたいのかというと、CTFの問題サーバーを立てるためである。当然外から接続を受け付ける必要がある。攻撃に成功した人は(たいていは)任意のコードが実行できるようになるので、それでどこかの掲示板に犯罪予告を投稿するとかされるのを避けたい。

まあ、どこかのCTFでconnect back shellを使った覚えがあるし、webのXSSに関する問題だと自分のサーバーにリクエストを飛ばすこともあるし、そこまで気にする必要は無く、記録を残しておいて何かがあったときに「犯人はこいつです」と言えれば良いのかもしれないが。

外向きのアクセスだけを弾く

単にIPレベルで外向きのものを弾くと、内向きのリクエストに対するレスポンスも弾いてしまう。RELATED,ESTABLISHEDな外向きのパケットは通し、それ以外の外向きのパケットを弾けば良い。

コンテナからcurlとか全部消しておけば?

bashがあればTCPアクセスはできてしまう。

$ exec 3<>/dev/tcp/example.com/80; printf "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n" >&3; cat <&3
HTTP/1.1 200 OK
Accept-Ranges: bytes
 :

そもそも、任意のコードが実行できるなら、TCPアクセスするようなコードも動かせる。

コンテナの中で何とかする

コンテナ内のiptablesでそういう設定をしたり、あるいは攻撃対象のプロセスをseccompで制限したりという手はあるかもしれない。でも、コンテナ内で複雑なことはしたくないし、コンテナ内のrootが取られたときにもアクセスを防ぎたい。最近もsudoに権限昇格の脆弱性があった

Dockerのネットワークで何とかする

-p 8080:80で指定したポートだけ不思議な力で繋がってくれれば良かったのだけど、-net=none -p 8080:80は繋がらない。docker network create --internal internal_netして、-net=internal_net -p 8080:80もダメ。

--internalなネットワークAと、外に繋がるネットワークBを作り、AとB両方に繋がるコンテナにプロキシさせるという手はあるかもしれない。コンテナ立ち上げ時に複数のネットワークを指定することはできないものの、後付けはできるらしい。

docker - Start container with multiple network interfaces - Stack Overflow

ホストの外のファイアウォールで防ぐ

これが一番安心。でも、使っている環境にそういうファイアウォールがあるかという話があり、別にファイアウォール代わりのマシンを借りるとお金が掛かってしまう。また、ホストマシンからもインターネットアクセスができなくなってしまうのは不便。

ホストのiptables

ということでホストのiptablesで防ぐ。

Dockerもiptablesを使って色々やっているが、ユーザーが処理を挟めるように、DOCKER-USERが用意されている。

Docker and iptables | Docker Documentation

sudo iptables -F DOCKER-USER
sudo iptables -A DOCKER-USER -m state --state RELATED,ESTABLISHED -j RETURN
sudo iptables -A DOCKER-USER -s 172.17.0.0/12 -j REJECT
sudo iptables -A DOCKER-USER -j RETURN
  • -F DOCKER-USER
    • とりあえず中身を全部消す
  • -A DOCKER-USER -m state --state RELATED,ESTABLISHED -j RETURN
    • 確立済みTCPセッションならば処理をDockerに戻す
  • -A DOCKER-USER -s 172.17.0.0/12 -j REJECT
    • それ以外で送信元がDocker内部のパケットは破棄
      • サブネットを変えれば、特定のDockerネットワークは弾き、他のものは通すこともできそう
  • -A DOCKER-USER -j RETURN
    • それ以外は処理をDockerに戻す

コマンドの実行順序がそのままフィルタの適用順序になるので、順番が重要。

永続化

iptablesの設定は再起動すると消えてしまう。

iptablesと言っているけれど、CentOS 8ではnftablesに換わっている。iptablesコマンドで設定ができているのは互換インタフェースが提供されているかららしい。正攻法で永続化するには、/etc/sysconfig/nftables.confに

table ip filter {
    chain DOCKER-USER {
        ct state related,established return
        ip saddr 172.16.0.0/12 counter reject
        return
    }
}

を書き込み、systemctl enable --now nftablesでnftablesを有効化する(パケットのフィルタリングにnftablesを使っていることと、nftablesデーモンが立ち上がっていることはイコールではない……?)。

しかし、これが良いのかが分からない。Dockerはnftablesの設定を永続化しないので、systemctl reload nftablesとかでDockerが設定した分が全部飛んで繋がらなくなる。

設定をnftablesにさせるのではなく、Dockerの起動直後に設定をするほうが良いのかもしれない。sudo systemctl edit dockerをして、

[Service]
ExecStartPost=iptables -F DOCKER-USER
ExecStartPost=iptables -A DOCKER-USER -m state --state RELATED,ESTABLISHED -j RETURN
ExecStartPost=iptables -A DOCKER-USER -s 172.17.0.0/12 -j REJECT
ExecStartPost=iptables -A DOCKER-USER -j RETURN

を書き込んでおけば起動直後に設定が有効になる。これならば、nftablesからまた別の何かに換わってもiptablesの互換機能さえ提供してくれていればそのまま動くはず。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0