iptables と netfilterを勉強し直す(ゼロからのfirewall構築)その1
私はもう20年以上Linux(*1)を使っているのですが、iptables周りに関してはいままで大して勉強してきておらず、いろいろ込み入った事はしているものの、基礎的な部分がかなりあやふやなまま設定を行っていました。これではいかーんと最近思い立って、仮想マシンなどを利用してゼロから勉強し直してみることにしました。
作業環境
常用しているノートパコン (Lenovo Thinkpad E17, Xubuntu 22.04)上の Oracle VirtualBox上に、Debian 10 (Buster) をインストールして作業を開始する。
必要なソフトウエア
まず最初に、以下のソフトウエアが入っている事を確認する。入ってなければ aptでインストールする。作業に必要なツール類はご自由に。
iptables
iptables-persistent
nftables
netfilter
netfilter-persistent
iptables と netfilterの役割
Debian 10 では、iptables に変わってnetfilter というツールが通信セキュリティ周りを担っているが、netfilter 自体の設定はほぼ不要。というのも、いまのところは netfilterへの完全移行は進んでおらず、結局は内部で iptablesの設定を読み込んで使っているからである。
初期状態
初期状態では、以下の確認コマンドを打つとこのような返事が帰ってくるはずである。ひとまずここでは、iptablesだけを考える。
現在の iptables 設定を確認
iptables -L
以下のような結果となる
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
これは、INPUT (外から入ってくる通信)の基本ポリシーは「受け入れ」(ACCEPT)であり、FORWARD(通信の転送)も「受け入れ」であり、OUTPUT(外に出ていく通信)も基本は「受け入れ」であることを示す。つまりこの段階では、なんのフィルタリングも行っていない。
フィルタリングを行うには、まずこのポリシーの変更からである。基本的に、INPUTとFORWARDはDROP(破棄)とし、OUTPUTはACCEPTにすべきである。
ポリシーの変更
まずはポリシーの変更の仕方である。最初に、FORWARD(通信の転送)を DROPにする。
iptables -P FORWARD DROP
また iptables -L を確認すると、以下のような結果となる。5行目がDROPに変わっていることを確認。
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy DROP)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
ここでINPUTもDROPにしてしまってもよいのだが、直にコンソールを触れない環境(VPSなど)でそれをやれば当然頓死するので、今の時点ではやらないでおく。
処理を追加する
iptablesの INPUTに処理を追加する。まずすべきはこの2点である。
1.外部からの ssh通信を許可。INPUTチェインの中に、 TCPの宛先22番ポートを「受け入れ」にする。まぁいまどきポート番号は変えておくべきだが。
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
2.すでに確立した通信は以降すべて許可とする。
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
1.は簡単な話だが、2.がわかりにくいと思う。これは何かと言うと、このマシンから外に出すリクエスト(WEBサイトの閲覧だとか、aptでのパッケージ入手だとか)は OUTPUTが ACCEPTだから通るのだが、それに対する外部サーバからの返答は、INPUTが DROPになっていると受け取れなくなってしまう。それを避けるために「自分から開始した通信は例外として、最後の切断を行うまで自由に通過させる」ということなのである。実際にこれを設定しないまま INPUT を DROPにして aptでパッケージの取得をしてみると、「パッケージを取りに行く」ところまでは動くのだが、そこで止まってしまうのである。
追加した処理を確認
現在の iptables 設定を確認
iptables -L
以下のような結果となる
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
Chain FORWARD (policy DROP)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
4行目と5行目が追加されていればOKである。これで外部からssh接続はできるようになった(sshdは当然立ち上げておくこと)し、自分から主導的に行った通信はできる状態なので、ここでINPUTのポリシーをDROPに変更する。
iptables -P INPUT DROP
iptables -L を確認すると、以下のような結果となっているはずである
Chain INPUT (policy DROP)
target prot opt source destination
ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
Chain FORWARD (policy DROP)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
動作確認
いちいちコマンドは書かないが、ここでサーバ自体から外部に向かって何らかの通信が(aptでのパッケージ取得だとか、w3mでのWEBサイト閲覧だとかが完全に)でき、また外部から22番ポートへの sshアクセスができていることを確認しておく。
現在のルールを保存
ふつうは保存コマンドといえば iptables-save > [ファイル名] を使うのだが、Debian10以降の場合はここで netfilterの出番となる。
netfilter-persistent save
以下のような表示が出る。
run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables save
run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables save
上記のコマンドの結果としては表示されないが(2つのファイル 15-ip4tablesと、25-ip6tablesを見ればまぁだいたいわかる通り)、以下のファイルに iptables の設定が書き込まれているのである。
cat /etc/iptables/rules.v4
# Generated by xtables-save v1.8.2 on Tue Jan 11 17:32:39 2022
*filter
:INPUT DROP [27986:4093146]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [16836:1923674]
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
COMMIT
# Completed on Tue Jan 11 17:32:39 2022
この後はサーバを再起動しても設定は消えないようになる。
/etc/iptables/rules.v6 には ipv6用の設定が書き込まれるが、ここでは触れない。
ルールすべての消し方
以下のコマンドでルールはすべて消える(ファイルに保存されたものは残る)。
iptables -F
注意してほしいのだが、このコマンドではチェインのポリシーはクリアされない、INPUT が DROPのまま、このコマンドで22番ポートのACCEPTを消してしまうと外部からのsshログインは頓死し、以降できなくなる。
チェインのポリシーまですべて一気にクリアしてくれるのは、このコマンドである。netfilterが動いている環境ではこれを使うべきであろう。
netfilter-persistent flush
なおこのコマンドは、 stop, start, reload, flush のオプションが使える。間違えてflushしてしまった場合は、reloadを使ってやればよい。
ルールの修正や順番変更や削除など
ルールの修正や削除などはコマンドラインからも行うことができるが、上記の netfilter-persistent flush/reload コマンドがせっかくあるので(もちろん iptables-restore コマンドでもいいが)、エディタで直に /etc/iptabels/rules.v4を編集して、netfilter-persistent reloadを使うのが面倒がなくてよい。詳しくは次回触れる。
またここで「順番変更」と書いたが、iptablesのルールは上から順番に処理される。「25番ポートへのアクセスをすべての送信元に許可」のあとに、「192.168.1.250からのアクセスをDROP」と書いても、192.168.1.250からはsshアクセスできてしまうので注意されたい。
基本的にここまでが基本的な操作である。あとは細かな応用を次回見ていくことにする。
(次回につづく)
*1 20年前には iptablesなんて使われてなかった。 TCPWrapper とか hosts.allow host.denyの時代だったのだ。