Closed noraworld closed 1 year ago
iptables
を使ったブロック方法: https://www.cyberciti.biz/faq/how-to-use-iptables-with-multiple-source-destination-ips-addresses/
一つのコマンドで複数の IP アドレスを同時に指定できることがわかった。サブネットマスクもそのまま指定できるので便利。
最終的には -A
ではダメだということに気づき、-I
を使った。
-A
だと、ping
は通らなくできるんだけど、git pull
は実行できてしまった。ブロックしたはずの IP アドレスを直で指定しているのに。
もしかしたらそれに関しては -p all
オプションを最初は付け忘れていたのが原因だったかもしれないが、いずれにしても -A
ではダメだった。
https://api.github.com/meta から拾ってきた IP アドレス一覧を iptables
に一括で流し込める形式に文字列を整形するのがまあ大変だった。
結局なんか sed
や grep
だけだと正規表現の指定の仕方がよくわからんかったので perl
を使うことに。まあ Ubuntu にデフォで入っているので使ってもいいでしょ。
JSON データの整形をシェルスクリプトでやるなら jq
を使うのが一般的だがこれはデフォルトではインストールされていた。なるべくデフォルト環境で実装したかったので別の方法でやることにして調べたのだが、愚直に grep
とか sed
とか tr
とかを使ってやるしかなかった。
grep
でマッチさせた文字列だけを抽出する方法について: https://stackoverflow.com/questions/5080988/how-to-extract-string-following-a-pattern-with-grep-regex-or-perl
grep -P
で最短マッチができる。
iptables
の DROP と REJECT の違いについて: https://serverfault.com/questions/157375/reject-vs-drop-when-using-iptables
REJECT を使ったほうがいい。ちなみに最初は DROP を使っていたんだけどこれだとタイムアウトを迎えるまで git pull
が終わらなくなってしまう。無駄に待たされるのは時間の無駄。パケット捨ててるならそれを通知してとっとと失敗してほしい。
とりあえずまあなんかいい感じにできた。
https://github.com/noraworld/cron-conf/commit/195a73cf8266a2fe1945b87c956e493154b4e28b
あんまり差分はないけどこれだけでもいろいろ調べながら正規表現こねこねしながらで結構時間がかかった。
このスクリプトは 10 分おきに実行されるんだけど、例によって一時的に無効化して git pull
とかされちゃったら意味がない。iptables
の設定変更を検知してなんかする的なことをしたかったんだけど、残念ながらそれは現実的ではないことがわかった。ファイルに記述していくタイプならそのファイルを監視すれば良いが、iptables
はコマンドで設定が変更できてしまう上にそれがファイルと連動するわけでもないので iptables
にそういう機構がない限りは実質的にフックは無理だという結論に至った。
もうそうなると、設定を変更させないようにするっていうのは無理なので、設定を無断で変更したら SSH から締め出すなどのペナルティ形式を採用するしかない。
git push
と git pull
に制限をかけるやつを不正に解除したらペナルティが課されるように実装できた。
https://github.com/noraworld/cron-conf/commit/4978f662a4eea2d948e289392477765e09649a66
ちょっとファイルの移動とかめんどくさかったけどまあわりとすんなりうまくいった。
0 〜 3 時のあいだだけ git pull
と git push
ができる。これ以外の時間帯は実行できないので、GitHub のウェブページからファイルをいじってもそれを Raspberry Pi に反映させることはできなくなった。つまりあとファイル監視も再稼働させれば、夜中の 3 時間以外はほぼ設定が変えられない環境になった!!
今のところの懸念点としては、GitHub の IP アドレス一覧を GitHub API から毎回拾ってきているけど、サーバがダウンしていたりしたときにたぶん失敗しちゃうからどうにかしないといけない。
各設定ファイルの監視も再稼働させた。これでもう設定はほぼ変えられないぞ!
実装意図:
git pull
が Raspberry Pi 上で簡単にできちゃうとブラウザから GitHub のページにアクセスしてファイルを更新することでいつでも簡単に設定ファイルの内容が変更できてしまう。これでは抑止にならない。かといって Mac とかで日中ずっと GitHub をブロックするわけにはいかない。でも Raspberry Pi なら別に日中ずっとブロックしておいても特に実害はない。Mac ではふつうに GitHub にアクセスできるようにしつつ、Raspberry Pi では日中はずっとブロックしておきたい。そうすれば実用上は影響が出ないし Raspberry Pi 上では気軽に
git pull
できなくなるのでちょうどいい。最初は DNS レベルでブロックして名前解決できないようにしようと思ったが、GitHub の IP アドレスを調べて
~/.ssh
の設定ファイルに直で IP アドレスを指定することで簡単に回避できてしまうことに気づいた。~/.ssh
内のファイル変更監視をしたところで、コマンドから直接リモートの IP アドレスを指定されたら意味がない。なので IP アドレスレベルでブロックする必要があった。IP アドレスレベルでブロックするにはもう
iptables
かufw
しか選択肢がない。iptables
のOUTPUT
(FORWARD
ではない) をREJECT
すれば、Mac では問題なく GitHub にアクセスできるが、Raspberry Pi ではパケットが届かないようにできる。この方針で進めることに決めた。