nftablesでdockerを使ってみました
February 22, 2020
Linux 3.13 から利用可能な、 iptables を置き換える(ことを目的とした)パケット分類フレームワークの(ファイアーウォール?) nftables を、 docker を使っている環境で使ってみました。
インストール・有効化
Docker から使うには、 iptables の互換フロントエンドをインストールする必要があります。
nftables と一緒にインストールするには、以下を実行します。
(iptables-nft
は iptables
を置き換えます。)
sudo pacman -S nftables iptables-nft
nftables.service
を起動すると、 /etc/nftables.conf
から設定を読み込みます。
起動・自動的に起動するようにするには、以下を実行します。
sudo systemctl enbale --now nftables
ArchLinux の nftables パッケージの etc/nftables.conf
には、
シンプルでセキュアなファイアーウォールが設定されています。
1:0.9.3-1 時点での設定内容は以下の通りです。
#!/usr/bin/nft -f
# ipv4/ipv6 Simple & Safe Firewall
# you can find examples in /usr/share/nftables/
table inet filter {
chain input {
type filter hook input priority 0;
# allow established/related connections
ct state {established, related} accept
# early drop of invalid connections
ct state invalid drop
# allow from loopback
iifname lo accept
# allow icmp
ip protocol icmp accept
ip6 nexthdr icmpv6 accept
# allow ssh
tcp dport ssh accept
# everything else
reject with icmpx type port-unreachable
}
chain forward {
type filter hook forward priority 0;
drop
}
chain output {
type filter hook output priority 0;
}
}
# vim:set ts=2 sw=2 et:
Docker を使用するための設定
標準のままだと、 Docker コンテナとの通信は forward チェインのルールにより drop されてしまいます。
docker エンジンによって作成される DOCKER-USER
チェインのパケットを accept するには、以下のコマンドを実行します。
# ip ファミリーに filter テーブルを作成し、 DOCKER-USER チェインを追加する
$ sudo nft add table ip filter :(
$ sudo nft add chain ip filter DOCKER-USER
$ sudo nft add rule ip filter DOCKER-USER mark set 1
# inet filter forward の drop ルールの handle を確認する (この場合は `handle 12`)
$ sudo nft list ruleset -a
table inet filter { # handle 25
chain input { # handle 1
type filter hook input priority filter; policy accept;
ct state { established, related } accept # handle 5
ct state invalid drop # handle 6
iifname "lo" accept # handle 7
ip protocol icmp accept # handle 8
ip6 nexthdr ipv6-icmp accept # handle 9
tcp dport 22 accept # handle 10
reject # handle 11
}
chain forward { # handle 2
type filter hook forward priority filter; policy accept;
drop # handle 12
}
chain output { # handle 3
type filter hook output priority filter; policy accept;
}
}
table ip filter { # handle 26
chain DOCKER-USER { # handle 1
meta mark set 0x00000001 # handle 2
}
}
# drop ルールの前に insert する(ここの `handle 12` は上で確認した handle に変更してください)
$ sudo nft insert rule inet filter forward handle 12 mark 1 accept
# ルールを /etc/nftables.conf に保存する
$ sudo nft list ruleset | sudo tee /etc/nftables.conf
table inet filter {
chain input {
type filter hook input priority filter; policy accept;
ct state { established, related } accept
ct state invalid drop
iifname "lo" accept
ip protocol icmp accept
ip6 nexthdr ipv6-icmp accept
tcp dport 22 accept
reject
}
chain forward {
type filter hook forward priority filter; policy accept;
meta mark 0x00000001 accept
drop
}
chain output {
type filter hook output priority filter; policy accept;
}
}
table ip filter {
chain DOCKER-USER {
meta mark set 0x00000001
}
}
nftables の設定の保存が完了したら、 docker.service
を再起動することで
docker によりファイアウォールルールが作成されます。
(docker は iptables フロントエンドを使用するため、 iptables-nft
パッケージに付属する iptables
コマンドを使用して
ルールが追加されます。)
念のため nftables.service
も再起動して、今保存したルールを再読み込みします。
sudo systemctl restart nftables docker
docker.service
が正常に起動したら、 docker のルールが追加され、コンテナとの通信ができるようになっているはずです。
nftables インストール前の iptables ルールの参照
iptables
コマンドの代わりに iptables-legacy
コマンドを使用することで、
iptables で使っていたルールを確認することができます。
docker のルールもこちらからインポートしようかなと思ったのですが、そうすると iptables-nft の互換性が壊れてしまって docker.service の起動に失敗したので、 ArchWiki の方法に従いました。