スクリプトでNATルータ/Firewall (firehol)

iptablesを手で書くのはつらいので、fireholを使う。
日本語での紹介記事を見かけないが、NATルータ/ファイアウォール/ロードバランサを細かく定義したいときにはとても便利。ラズパイで簡易NATルータする時も使える。

インストール(Debian系):

sudo apt install firehol
準備:/etc/default/firehol
START_FIREHOL=YES
/etc/firehol.conf:
### NATルータでポート転送(IPマスカレード)するfirehol.conf雛形
### 準備:
### /etc/default/firehol にて、START_FIREHOL=YES とすること。

## IPv4専用ならversion 5。IPv6もやるならversion 6、但し、下記の書式も変わる。
version 5

## ローカル変数定義 XXX_G=GLOBAL側 XXX_P=PRIVATE側
# 物理ポート名を変数に代入
ETH_G="eth0"
ETH_P="eth1"
# GLOBAL IPアドレスを変数に代入
ADR_G="10.0.0.111"
# PRIVATE側で通信許可するネットワーク範囲またはIPアドレスを変数に代入
NET_P="192.168.1.3 192.168.1.4 192.168.1.128/25"
# GLOBAL側でのICMP(ping)受付範囲またはIPアドレスを変数に代入
ICMP_ACCEPT_FROM="10.0.0.0/24 10.0.1.0/24 10.0.2.151"

## 独自のサービス(ポート番号)を定義する。
## https://firehol.org/services/ でデフォルトで定義されて
## いないサービス(ポート番号)を定義する。

# rdpplus(tcp/33239)
# リモートデスクトップのポート転送を独自定義してみる(33239)
server_rdpplus_ports="tcp/33239"
client_rdpplus_ports="default"

# SSHのポート転送を定義してみる(PORT:33222〜33330)
server_ssh333xx_ports="tcp/33322:33330"
client_ssh333xx_ports="default"

## ポート転送のPREROUTING ・・・ポート番号を変換するサービスはここで定義。
## 以下、GLOBAL側から「10.0.0.111:33239」にリモートデスクトップ接続すると、
## NAT内側PC(192.168.1.240)にポート転送してリモートデスクトップ接続する例。
## ポート転送はIPマスカレードとも言う。
dnat to 192.168.1.240:3389 inface $ETH_G proto tcp dst $ADR_G dport 33239
## SSHを同様にポート転送する。
dnat to 192.168.1.247:22   inface $ETH_G proto tcp dst $ADR_G dport 33322
dnat to 192.168.1.248:22   inface $ETH_G proto tcp dst $ADR_G dport 33324

##
## 各ポートのポリシー/フィルタ定義
##

# PRIVATE側からの入力は、"NET_P"で定義した送信元に限定する。
# (限定しない場合は"src"以降を削除する。)
interface $ETH_P mylan src $NET_P
  # 2017Jan追記:マルウェア感染後の振る舞いを想定すると、
  # server samba dropなどと、危ないサービスを封鎖するか、
  # 下記のGLOBAL側設定と同様に、許可するサービスだけ列挙する方が良い。
     policy accept

# GLOBAL側からの入力は厳しくフィルタする。
interface $ETH_G myglobal
    policy drop
    protection strong
  # ICMP(ping)を送信元限定で許可
    server icmp accept src $ICMP_ACCEPT_FROM
  # このNATルータ自身のssh, http, httpsへのアクセスを許可 
    server "ssh http https" accept
  # このNATルータ自身のRDPへのアクセスを許可
    server "rdp" accept
 # ポート転送するRDPを許可
    server "rdpplus" accept
  # ポート転送するSSHを許可
    server "ssh333xx" accept

    client all accept
    server all drop 

# グローバル=>ローカルのルーティング定義
# (ポート転送が無いならこの定義はコメントアウトして良い)
router myglobal2mylan inface $ETH_G outface $ETH_P
    route all accept

# ローカル=>グローバルのルーティング定義(マスカレード)
# ★2016年9月 下記の 「src $NET_P」を追加。抜け穴を塞いだ。
# ★クリティカル運用では、この手の漏れは要注意!!

router mylan2myglobal inface $ETH_P outface $ETH_G
    masquerade
    route all accept src $NET_P
そして、fireholを再起動する。
systemctl restart firehol
その後、iptablesの設定結果を確認する。
iptables -L

あとはおまけだが、Debianの場合、iptablesのログが/var/log/messagesに書かれて邪魔なので対処する。 /etc/default/firehol にオプションを追記してfireholを再起動:
START_FIREHOL=YES
WAIT_FOR_IFACE=""
FIREHOL_LOG_PREFIX="FIREHOL:" 
/etc/rsyslog.conf
# RULES の直下
:msg,contains,"ip_tables"   -/var/log/iptables.log
:msg,contains,"ip_tables"   ~
:msg,contains,"FIREHOL"     -/var/log/iptables.log
:msg,contains,"FIREHOL"     ~ 
/var/log/iptablesのログローテーション:
/etc/logrotate.conf内、または/etc/logrotate.d/*のどれかを真似すればOK。