2014-07-06
■[セキュリティ][Linux] デッドマンスイッチによるiptablesの安全な変更
古本屋で「Red Hat Linux Firewalls」の本を手に入れたのでパラパラしていたら、面白いiptablesのネタを見つけました。のでちょっと紹介します。
Red Hat Linux Firewalls (redhat PRESSシリーズ)
- 作者: ビルマッカーティ,Bill McCarty,中川和夫,ヴァインカーブ
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2003/04
- メディア: 単行本
- 購入: 1人 クリック: 5回
- この商品を含むブログ (4件) を見る
この本は2003年発行ということで、既にいろんな記述が古くなっているのは確か。しかしiptablesやファイアウォールの基本的な考え方などはそうそう変わるもんでもないので、今読んでも結構参考になります。
リモートホストのiptables設定時の悩み
RedHatやCentOSなどRH系Linuxのリモートホストにsshでログインして作業しているとき、iptablesを試行錯誤しながら修正したいことがあります。この場合、いきなり/etc/sysconfig/iptablesファイルをいじらずに、まずはiptablesコマンドで1行ルールを色々試してみるのが普通です。
この際、例えばもし間違えて以下のようなコマンドを打つと、sshがブチ切られて以後何も繋がらなくなってしまいます。
# iptables -I INPUT -p tcp --dport 22 -j REJECT
これは「-A INPUT」ではなく、間違って「-I INPUT」としたため、チェーンの末尾ではなく先頭にルールを追加しちゃった! という例。わざとらしいかな?
こんな場合はコンソールがあれば、万一通信不可となってしまっても、コンソールからiptablesをrestartすれば良いのですが……政治的な理由でコンソールが使えなかったり、あるいは使えないことは無いがひどく使いにくい(デザイン的に・政治的に・技術的に・スペース的に)、ということもよくあります。
さて、iptablesコマンドで設定している場合は、「# service iptables restart」さえ打てれば、/etc/sysconfig/iptablesファイルを読み込んでiptablesが再起動してくれるので、打ち込んだ1行コマンドのルールは消え失せてくれます。
というわけで先のケースでは、iptablesコマンドを打ってまずルールを1行追加して、それで通信不可になってしまったら自動的にiptablesがrestartする……という動きができればいいわけです。
そんな都合の良いことができるのか、と言われると実はシェルスクリプトを使うとできるのです。
シェルスクリプトによるiptablesデッドマンスイッチ
以下のようなスクリプトになります。
#!/bin/sh echo "iptablesを実行します。実行後、プロンプトに従いyキーを入力してください。" echo echo "iptables記述に誤りがあり通信不可となった場合は、yキー入力のリモートエコーが返りません。" echo "その場合は、10秒待てば自動的にリカバリされます。" echo # (1) 実行したいiptablesコマンド iptables -A INPUT -p tcp --dport 22 -j REJECT # (2) 10秒間待ってから、iptablesをrestartする ( sleep 10; service iptables restart; ) & echo "Enter [y] Key" read line case $line in [yY]*) # (3) yが入力されたら、iptablesのrestartをkillしてやめさせる kill $! ;; *) ;; esac
まず、(1)でiptablesコマンドを実行します。ここに試行錯誤したいルールを書いておきます。
(2)がこのスクリプトのキモで、10秒sleepしてからiptablesをrestartしています。つまり何もしないでボーっとしていると、(1)で実行したiptablesコマンドは10秒後に無効となります。ここではコマンド全体をカッコでくくってサブシェルとして、その最後に&を付けることでバックグラウンド起動としています。
(3)では、readコマンドで読み込んだキー入力がyだった時のみ、「kill $!」を実行しています。ここで$!とはシェルの特殊変数で、最後に実行されたバックグラウンドコマンドのプロセスIDが入っていいます。ここではこのプロセスIDの対象となるコマンドとは、(2)のサブシェルです。ですから$!をkillすれば(2)の処理をやめさせる、すなわちiptablesのrestartを止めることができるわけです。
readとcase
(3)のcase文は、その前のreadコマンドで読み込んだ文字列を対象としています。ここでreadコマンドは、Enterキーによる改行が無いと終了しないので、もしiptablesコマンドが間違っていてリモートホストとの接続がブチ切られてしまった場合には(3)の手前のreadコマンドで処理が止まってしまいます。結果として、(2)が10秒後に実行されてiptablesがrestartされ、(1)のiptablesコマンドがリセットされる……という仕組みです。
いやはや、なかなか面白いやり方を考えるものですね。実用性で言うと微妙だけど、何かの役に立つかもしれない。
余談
ここで出てきたデッドマンスイッチ(デッドマン装置)とは、元は「運転士が突然死しても車両が暴走するのを防ぐ」という車両の安全装置です。ここではリモート接続が切れることによってデッドマン装置が発動し、iptablesをリカバリする、という動作を指しています。
デッドマン装置は、身近なところにも結構あります。例えば鉄オタには常識なのですが、電車というのは基本的に無操作ではブレーキがかかるようになっています。このため、突然運転士が倒れたり車外に放り出されても、無操作となればそのうちブレーキがかかり、列車は停止します。
この他にも、最近のフォークリフトは基本的に常にブレーキがかかっており、「ブレーキペダルを踏んでブレーキを解除」することで動くのが普通です。これはデッドマンブレーキと呼ばれます。
ちなみにこの辺の設計思想は、現代の自動車(AT車)とは大違いですね。無操作ではエンストして止まるMT車に対し、無操作では延々とクリープ現象で動き続けるAT車というのは、機械工学的に根本的な欠陥品なんじゃないかなぁ(そのせいで踏切侵入事故もありましたね)。
- 23 https://www.google.co.jp/
- 9 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=14&ved=0CDoQFjADOAo&url=http://d.hatena.ne.jp/ozuma/20140413/1397397632&ei=sh64U4fCPMnikAXlgoHoBA&usg=AFQjCNGg1w9rhKWcaYTx4MVtsaPiJYzMxw&sig2=H2yjkkDM0X1NdUeCopqlGQ&bvm=bv.70138588
- 6 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=3&cad=rja&uact=8&ved=0CCkQFjAC&url=http://d.hatena.ne.jp/ozuma/20130427/1367073843&ei=Hyy4U5ilEs_m8AXyp4HgDA&usg=AFQjCNEVlUoFzdqcAfdTvhbgWXiDlcO9LQ&sig2=leAXNDSUnTNlj3V26xalww&bvm=
- 3 http://pipes.yahoo.com/pipes/pipe.info?_id=02db597254ec68550537866a2fca2ce6
- 3 http://pipes.yahoo.com/pipes/pipe.info?_id=VPw6npu13RGKo15vBRNMsA
- 3 http://t.co/04f7hNfPSy
- 3 http://t.co/wxgFJdZrZQ
- 3 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&ved=0CCcQFjAB&url=http://d.hatena.ne.jp/ozuma/20120711/1342014448&ei=pCe4U6KEE8nGkAXHqYCABQ&usg=AFQjCNEqj9EZkTc72DZCWAaILLk9tlalVA&sig2=trsl32_2qYjVo16nzPB7sA&bvm=bv.70138588,d.d
- 2 http://ariel.s8.xrea.com/news/2014_06.htm
- 2 http://reader.livedoor.com/reader/