Linux save iptables on Docker Host Environment - 在安裝了 Docker 的環境處理 iptables 的儲存
===
###### tags: `blog`
> iptables 是在 Linux 系統上實用的防火牆、NAT、封包管理系統,但如果需要在複雜的環境當中使用 iptables ,並且將 iptables 的規則保存的話,就需要使用一些技巧
## Context
以往在 Linux 當中,我們可以透過 iptables 來當作防火牆使用,只要透過 iptables 中預設的 filter tables,即可做到封包的過濾功能。
但 iptables 的資料是於執行時新增規則,如果想要將規則存檔,並於開機時自動載入的話,我們就需要透過 `iptables-save` 與 `iptables-restore` 這兩個指令來完成。
根據 `Debian Wiki`[^debian-wiki-iptables] 中提到的方法,可以使用 `iptables > /etc/iptables.up.rules` 的方式將 iptables 的 rule 匯出至檔案,再透過 `iptables < /etc/iptable.up.rules` 指令將規則檔案還原。
文中也提到,可以在 `/etc/network/if-pre-up.d/` 路徑中,放置 bash 檔案,這樣就會在網卡啟動前,呼叫 `iptables-restore` 指令,載入 iptables 的規則。
## Problem
問題來了,傳統作法中,所使用的 iptables-save 指令,會將目前所有的規則匯出,但是如果主機環境中有安裝 Docker 的話, Docker 會建立許多橋接器 (Bridge) ,並透過 iptables 的 filter 、 nat 這兩張表,建立 container 的網路與連線關係。
而 Docker 的環境不清楚他會在何時啟動,並更改 iptables 的狀況下,如果冒然執行 `iptables-restore` 指令,勢必會破壞原先 docker 所建立的規則。
## Solution
如果無法透過 `iptables-restore` 指令直接匯入規則檔的話,還可以透過另一個方式:使用 iptables 指令動態新增規則。
不過這邊要注意的是,要注意目前 iptables 中的規則是否已經存在,免得重複新增規則。
使用 iptables 的 check 指令可以根據回傳值得之規則是否存在
> iptables [-t ++table++] -C ++chain++ ++rule-specification++'
一樣將 bash 檔案寫在 `/etc/network/if-pre-up.d/` 中,
透過 if 判斷欲新增的規則是否已經存在於 iptables 中,
如果沒有找到的話,再使用 `iptables` 指令動態增加新的規則。
以下是 bash 的範例,透過 function 的方式判斷規則存不存在,不存在則新增規則
```bash
#!/bin/sh
# check iptables rule specification is exist,
# if not add it
check_and_add_iptables()
{
RULE_SPEC=$@
iptables -C $RULE_SPEC > /dev/null 2>&1
EXIST=$?
if [ $EXIST -ne 0 ]; then
iptables -A $@
fi
}
check_and_add_iptables INPUT -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPT
check_and_add_iptables INPUT -p tcp --dport 22 -j DROP
```
## Conclusion
`iptables` 是一個很好用的防火牆軟體,不過在一些複雜的環境當中,無法單純使用 restore 指令套用規則,就得使用動態增加的方式,使用動態增加的方式又得顧慮到該指令重複執行會造成的影響,所以還需要透過一些 test 的方式判斷目前的環境 (Context) 是否可以新增規則。
## References
[^debian-wiki-iptables]: <https://wiki.debian.org/iptables>