iptable で http ポートへのアクセス制限をした記録
VPS で運用している nginx を自宅と sim 端末からだけアクセスできるようにした。事前準備として必要なことが1点。iptables の設定ミスで ssh が不通になった場合に備え、VPS のコンソールが取れ、 root でログインできることを確認すること。
まず自宅から VPS で動かしている sshd と nginx へアクセスできるようにするには、こんな感じの設定ファイルを作成する。
*filter:INPUT DROP [0:0]:FORWARD DROP [0:0]:OUTPUT ACCEPT [0:0]-A INPUT -s <Home IPAddress>-p tcp -m tcp --dport 22 -j ACCEPT -A INPUT -s <Home IPAddress>-p tcp -m tcp --dport 80 -j ACCEPT -A INPUT -p icmp -j ACCEPT-A INPUT -i lo -j ACCEPT-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPTCOMMIT
- 1行目はルールを記載するテーブル として filter を指定している。これがデフォルトのテーブルであり、この備忘録ではおまじないと考えることにする。
- 2行目では INPUT チェインのポリシーを DROP に設定。入ってきたパケットは全て捨てるポリシーを指定している。この後、受け取りたいパケットのルール(例外)を登録する。
- 3行目では FORWARD チェインのポリシーを DROP に設定。転送はしない。
- 4行目はVPS から外へ出て行くパケットは全て許可。
- 5行目は ssh を開けている。 -A INPUT では、ルールを登録するチェインとして INPUT を指定している。チェインはパケットの選択ルールを登録するためのリストである。デフォルトテーブル filter で VPS へのアクセス制限をする場合、組み込みチェインは INPUT, OUTPUT, FORWARD の3つになる。この他にユーザ定義チェインを作ることもできるが、それについては一旦置いておく。この行では VPS に入るパケットを選ぶルールを指定したいので、INPUT チェーンに対してルールを設定する。-s でアクセス元の自宅 IP アドレスを指定、ssh を 22 番ポートで動かしているので --dport 22 としている。末尾の -j オプションは --jump の省略形で、ACCEPT という組み込みターゲットを指定している。入ってきたパケットが -s で指定したアドレスからで、22 番ポート宛であれば、この行がマッチして、 -j で ACCEPT と指定しているので、パケットは VPS 内の sshd に届く。
- 6行目は http を開けている。5行目と同様に INPUT チェインに対してルールを設定している。
- 7行目は ping を受けとる。
- 8行目は自分自身へのパケットを受け取るようにしている。
- 9行目はVPS から外部ホストへアクセスした結果、返ってくるパケットを受けとるようにしている。
設定ファイルを例えば /etc/iptables.up.rules として保存して、 iptables-restore で以下のように読み込ませれば、その時点からアクセス制限がかかる。
iptables-restore < /etc/iptables.up.rules
但し iptables-restore コマンドは、オプションを指定しないと、すでに登録されていたルールが全て消える。例えば ssh 許可のルールが登録されている状況で、オプション無しで実行すると、ssh が不通になる。既存のルールをフラッシュせずにルールを追加するにはオプション --noflush を付ける。
次にSIM 端末からのアクセスはどうするか。現在使っている SIM は iijmio で、APN をみると vmobile.jp とある。そこで WHOIS で IIJNET を調べ、そのうちで vmobile.jp である IP アドレスを調べてみる
ずらずらと出てくる(結果は省略)。この中から vmobile.jp なアドレスを拾う ruby スクリプトを作った。whois -h whois.apnic.net IIJNET | grep inetnum
require 'ipaddr'NSLOOKUP = '/usr/bin/nslookup'WHOIS = '/usr/bin/whois'GREP = '/bin/grep'class IPAddrclass << selfdef ipcount(ip1, ip2)bit = 0ip = ip1.duploop {while ! ( (ip >> bit) == (ip1 >> bit) )bit += 1endif ip == ip2breakendip = ip.succ}"#{ip1}/#{32 - bit}"endendendmodule Netclass << selfdef hostname(ip)`#{NSLOOKUP} #{ip}` =~ /name = (\S+)\./m$1enddef get_ranges(netname)ranges = `#{WHOIS} -h whois.apnic.net #{netname} | #{GREP} inetnum`.split(/\n/)ranges.map {|line|line =~ /inetnum:\s+(\S+) - (\S+)/(IPAddr.new($1) .. IPAddr.new($2))}endendendrules = open('/etc/iptables.d/nginx.rules', 'w')rules.puts <
*filter-F nginxEOFranges = Net.get_ranges('IIJNET')ranges.each do |rg|host = Net.hostname(rg.first.to_s)if host && host =~ /vmobile/m = IPAddr.ipcount(rg.first, rg.last)rules.puts "-A nginx -s #{m} -p tcp -m tcp -j ACCEPT"endendrules.puts <<EOF
COMMITEOFrules.close
このスクリプトを動かすと下記の /etc/iptables.d/nginx.rules というファイルが作られる。
*filter-F nginx-A nginx -s <IPAddress range 1>-p tcp -m tcp -j ACCEPT -A nginx -s <IPAddress range 2>-p tcp -m tcp -j ACCEPT -A nginx -s <IPAddress range 3>-p tcp -m tcp -j ACCEPT COMMIT
- 1行目はおまじない
- 2行目は -F で nginx というユーザ定義チェインのルールをフラッシュしている。この nginx というユーザ定義チェインについては後でまた触れる。
- 3行目以降でユーザ定義チェイン nginx にたいしルールを追加している。iijmio のアドレスレンジは幾つかあるので、それぞれを -s で指定し、-j ACCEPT で許可している。
このルールをロードする前に、ユーザ定義チェイン nginx を作成する。ユーザ定義チェインの作成は -N <チェイン名> で行う。詳細は後述するが、-N nginx でチェインを作成したら以下のコマンドでチェイン nginx にルールを登録できる。
この段階では、チェイン nginx が評価されることはない。このチェインを評価させるにはチェイン INPUT で、ポート 80 番へのパケットが来た時にチェイン nginx に jump するよう指示すればよい。そこで一番最初に作った設定ファイル /etc/iptables.up.rules に2行追加する。iptables-restore --noflush < /etc/iptables.d/nginx.rules
追加したのは 5 行目の -N nginx と 8 行目である。5 行目で チェイン nginx を作成し、8 行目では、80番ポートに来たパケットのうち自宅 IP アドレスにマッチしなかった( 7 行目でマッチしなかった)ものは、-j nginx で、チェイン nginx に飛ばすように指定している。*filter:INPUT DROP [0:0]:FORWARD DROP [0:0]:OUTPUT ACCEPT [0:0]-N nginx-A INPUT -s <Home IPAddress> -p tcp -m tcp --dport 22 -j ACCEPT-A INPUT -s <Home IPAddress> -p tcp -m tcp --dport 80 -j ACCEPT-A INPUT -p tcp -m tcp --dport 80 -j nginx-A INPUT -p icmp -j ACCEPT-A INPUT -i lo -j ACCEPT-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPTCOMMIT
後は、起動時に /etc/iptables.up.rules と /etc/iptables.d/nginx.rules を順に読み込むスクリプトを書くなりすればいい。
#!/bin/bash/sbin/iptables-restore < /etc/iptables.up.rules/sbin/iptables-restore --noflush < etc/iptables.d/nginx.rules
0 件のコメント:
コメントを投稿