這是承接上一篇的內(nèi)容
在某些情況下,我們可能需要創(chuàng)建更復(fù)雜的規(guī)則,而不僅僅是允許區(qū)域中的某些端口或服務(wù)。例如,我們可能想要創(chuàng)建一條規(guī)則來阻止來自特定機器的某種類型的流量。這就是rich規(guī)則的意義所在。規(guī)則基本上由兩部分組成:在第一部分中,我們指定要應(yīng)用規(guī)則必須滿足的條件,在第二部分中,指定要執(zhí)行的操作:accept、drop或reject
實驗?zāi)康?/h3>
在下面的實驗拓網(wǎng)絡(luò)拓撲中,防火墻的 ens33網(wǎng)卡是分配到external區(qū)域,ens34網(wǎng)卡分配的internal區(qū)域

我們的實現(xiàn)目的是防止特定外網(wǎng)(用192.168.168.0/24來模擬)的主機192.168.168.105訪問我們防火墻的ssh服務(wù)
我們先來看看防火墻本身的一些以下是external區(qū)域的預(yù)配置

以下是internal區(qū)域的預(yù)配置

攔截來自外部網(wǎng)路中IP為192.168.168.105主機的流量:我們將如何組成我們的規(guī)則,事實上,就是iptables規(guī)則的一種變相語法:
firewall-cmd --zone=external --add-rich-rule="rule \
family="ipv4" \
source address=192.168.168.105 \
service name=ssh
reject \"
rich規(guī)則詳解
- --add-rich-rule選項,將該規(guī)則描述為其參數(shù)。規(guī)則以rule關(guān)鍵字開頭。
- family:我們指定該規(guī)則僅應(yīng)用于IPv4數(shù)據(jù)包:如果未提供此關(guān)鍵字,則該規(guī)則將同時應(yīng)用于IPv4和IPv6。
- source address:我們提供數(shù)據(jù)包必須具有的源地址,才能使用源地址觸發(fā)規(guī)則。
- service,我們指定了規(guī)則的服務(wù)類型,在本例中為ssh。
- reject/drop/accept,我們提供了數(shù)據(jù)包與規(guī)則匹配時要執(zhí)行的操作,在本例中為reject.
當我們將上面的rich規(guī)則添加的external區(qū)域,我們192.168.168.105再也無法訪問到防火墻的外部接口192.168.168.106了。這是rich規(guī)則的一個簡單用法

上面的一個非常簡單,但是規(guī)則可能變得非常復(fù)雜。您應(yīng)該查看firewalld文檔,以查看所有可用設(shè)置和選項的范圍。
rich規(guī)則的其他命令行參數(shù)
可以查看如下表,里面列舉了rich規(guī)則常用的方法

我這里沒必要一一列出示例,我們先將剛才添加的rich規(guī)則刪掉
firewall-cmd --zone=external --remove-rich-rule=" \
rule family="ipv4" \
source address="192.168.168.105" \
service name="ssh" \
reject"
Rich規(guī)則的優(yōu)先級
首先我們在解析這個問題,仍然使用上面的例子,比如我們希望只有192.168.50.17的主機能夠遠程ssh到防火墻,而同一網(wǎng)絡(luò)192.168.50.0/24的其他主機我們禁止其他訪問。

在寫rich規(guī)則時,往往會遇到兩條沖突的規(guī)則。例如,為了只允許來自192.168.50.0/24網(wǎng)絡(luò)的一臺主機192.168.50.17允許通過ssh訪問防火墻,顯然下面的規(guī)則是不可取的
- 規(guī)則1:-拒絕來自192.168.50.0/24網(wǎng)絡(luò)的所有主機(drop/reject)
- 規(guī)則2:-允許來自192.168.50.17的主機(accept)
由于192.168.50.17主機也屬于192.168.50.0/24這個網(wǎng)絡(luò)號,因此這兩個規(guī)則都將應(yīng)用于該主機,如果你對iptables規(guī)則熟悉的話,可能會去如下這樣理解防火墻匹配規(guī)則的行為。
- 僅處理入站的數(shù)據(jù)包。
-
數(shù)據(jù)包始終以從上到下的方向進行處理。
- Step1:一旦數(shù)據(jù)包與規(guī)則匹配,將立即對該數(shù)據(jù)包執(zhí)行關(guān)聯(lián)操作(允許或拒絕)。
- Step2:數(shù)據(jù)包將不可用于進一步處理。
然后可能就許就這樣定義防火墻的規(guī)則:
- 規(guī)則1:允許來自192.168.50.17的主機(accept)
- 規(guī)則2:拒絕來自192.168.50.0/24網(wǎng)絡(luò)的所有主機(drop/reject)
規(guī)則精確度越高的放在規(guī)則列表的最前,邏輯上應(yīng)該是先設(shè)定accept行為的規(guī)則,然后再設(shè)定drop/reject行為的規(guī)則,這樣的邏輯在iptables是正確,甚至其他傳統(tǒng)的防火墻也是這樣行為邏輯的。但你要搞清楚,到了firewalld的rich規(guī)則就不適用了。為了證實這一說法,我么參考了firewalld.org的技術(shù)文檔,請好好理解圖中劃黃線的一段話。

中文的翻譯:
當前的rich規(guī)則的一個問題是,它們是基于規(guī)則操作來組織的。 日志規(guī)則始終在拒絕規(guī)則之前發(fā)生。 拒絕規(guī)則總是發(fā)生在允許規(guī)則之前。 這導(dǎo)致用戶感到困惑,因為它隱式地對規(guī)則進行了重新排序。 這也使得不可能添加全面的rich規(guī)則來拒絕流量。
因此firewalld的rich規(guī)則執(zhí)行邏輯如下:
- 日志規(guī)則
- drop/reject規(guī)則
- accept規(guī)則
實驗示例
目標:驗證rich規(guī)則的潛在問題
- 我們允許192.168.50.0/24所有網(wǎng)絡(luò)訪問局域網(wǎng)的10.10.10.1上的遠程桌面
- 允許192.168.50.17的主機通過ssh訪問防火墻
- 拒絕192.168.50.0/24其他主機通過ssh訪問防火墻
- 拒絕所有來自192.168.50.0/24對防火墻的ping請求
進行上面的拓撲實驗前,我們檢測一下防火墻的狀態(tài)

在Linux管理配置防火墻時,先在文本編輯器將你的思路理順了,然后一條條命令拷貝到shell中回車,是一種很好的習(xí)慣,這些命令能出錯的話,我們部署到生產(chǎn)環(huán)境再寫成shell或python腳本程序。
rich規(guī)則有兩種書寫方法,你不得不吐嘈:"這些地球上最丑陋的命令形式,沒有之一",你不管使用那種形式,都很容易出錯,所以建議你在文件編輯器修改到?jīng)]有毛病才粘貼到shell終端窗口中。
- 不換行風(fēng)格--add-rich-rule=之后的規(guī)則內(nèi)容用單引號括起來,見下圖第一個的命令
-
換行風(fēng)格,需要了解一些shell解析器的基礎(chǔ),說明見下圖第二個命令
允許192.168.50.0/24所有主機網(wǎng)絡(luò)訪問局域網(wǎng)的10.10.10.1上的遠程桌面
firewall-cmd --zone=external --add-forward-port=\
port=3389:proto=tcp:toport=3389:toaddr=10.10.10.1
允許192.168.50.17的主機通過ssh訪問防火墻
firewall-cmd --zone=external --add-rich-rule="rule \
family="ipv4" \
source address="192.168.50.17" \
service name="ssh" \
log prefix=\"ssh connect from:\" \
level="notice" \
accept"
拒絕192.168.50.0/24的其他主機訪問防火墻的ssh服務(wù)
firewall-cmd --zone=external --add-rich-rule="rule \
family="ipv4" \
source address="192.168.50.0/24" \
service name="ssh" \
log prefix=\"ssh reject from:\" \
level="notice" \
drop"
拒絕所有來自192.168.50.0/24對防火墻的ping請求
firewall-cmd --zone=external --add-rich-rule="rule \
protocol value="icmp" \
reject"
ok,整個過程沒出錯

我們使用以下命令查看,剛才在external區(qū)域配置的rich規(guī)則
firewall-cmd --zone=external --list-rich-rules
實驗的重點:就是要驗證第一條rich的規(guī)則是否會被優(yōu)先執(zhí)行,還是第二條drop規(guī)則會先于第一條accept規(guī)則執(zhí)行?

我們在192.168.50.17的主機上測試一下能否ssh到防火墻?如下圖ssh請求無響應(yīng)且沒有錯誤提示返回,這里至少已經(jīng)證實
- 即便在規(guī)則列表中accept規(guī)則位置先于drop規(guī)則,但是drop規(guī)則總是會優(yōu)先于accept規(guī)則被匹配。
-
已經(jīng)無法ping通防火墻,并且由防火墻返回錯誤信息。
防火墻的端口轉(zhuǎn)發(fā)測試,192.168.50.17是一臺Ubuntu主機,我們使用Remmina遠程桌面軟件連接到內(nèi)網(wǎng)10.10.10.1的主機

OK,端口轉(zhuǎn)發(fā)也是成功的

那么實現(xiàn)遺留的問題,就是rich規(guī)則如何能如我們所愿地定的規(guī)則順序執(zhí)行?這正是本文的重點
Rich規(guī)則的priority字段
新版的firewalld添加了新的priority字段。它可以是-32768到32767之間的任何數(shù)字,其中數(shù)字越小,優(yōu)先級越高。此范圍足夠大,以允許從腳本或其他實體自動生成規(guī)則。
那么就非常簡單:只需在你想優(yōu)先執(zhí)行的rich規(guī)則中給priority字段定義一個足夠小的負數(shù),就能確保能優(yōu)先于其他drop/reject規(guī)則被firewalld匹配。如下圖所示

Ok,此時,accept的規(guī)則優(yōu)先于其他drop/reject規(guī)則被匹配,這正是我們所希望的。

按照我上面的實驗步驟,應(yīng)該沒什么問題,能達到預(yù)期實驗的目地,結(jié)束本篇之前,要記得
將上面的運行時配置轉(zhuǎn)化為持久配置,執(zhí)行下面命令
firewall-cmd --runtime-to-permanent
小結(jié)
目前,rich規(guī)則的定義,至少目前來說我算是全簡書里解說地很清楚了,但rich規(guī)則的語法是非常令人惡心的,這點不容否認。

