如果有人嘗試從其它的地址,如 2.2.2.2,去訪問 ssh,它不是這個(gè)源區(qū)域的,因?yàn)楹瓦@個(gè)源區(qū)域不匹配。因此,這個(gè)請求被直接轉(zhuǎn)到接口區(qū)域(public),它沒有顯式處理 ssh,因?yàn)?,public 的目標(biāo)是 default,這個(gè)請求被傳遞到默認(rèn)動作,它將被拒絕。
如果 1.1.1.1 嘗試進(jìn)行 http 訪問會怎樣?源區(qū)域(internal)不允許它,但是,目標(biāo)是 default,因此,請求將傳遞到接口區(qū)域(public),它被允許訪問。
現(xiàn)在,讓我們假設(shè)有人從 3.3.3.3 拖你的網(wǎng)站。要限制從那個(gè) IP 的訪問,簡單地增加它到預(yù)定義的 drop 區(qū)域,正如其名,它將丟棄所有的連接:
# firewall-cmd --permanent --zone=drop --add-source=3.3.3.3 # firewall-cmd --reload
下一次 3.3.3.3 嘗試去訪問你的網(wǎng)站,firewalld 將轉(zhuǎn)發(fā)請求到源區(qū)域(drop)。因?yàn)槟繕?biāo)是 DROP,請求將被拒絕,并且它不會被轉(zhuǎn)發(fā)到接口區(qū)域(public)。
一個(gè)實(shí)用的多區(qū)域示例
假設(shè)你為你的組織的一臺服務(wù)器配置防火墻。你希望允許全世界使用 http 和 https 的訪問,你的組織(1.1.0.0/16)和工作組(1.1.1.0/8)使用 ssh 訪問,并且你的工作組可以訪問 samba 服務(wù)。使用 firewalld 中的區(qū)域,你可以用一個(gè)很直觀的方式去實(shí)現(xiàn)這個(gè)配置。
public 這個(gè)命名,它的邏輯似乎是把全世界訪問指定為公共區(qū)域,而 internal 區(qū)域用于為本地使用。從在 public 區(qū)域內(nèi)設(shè)置使用 http 和 https 替換 dhcpv6-client 和 ssh 服務(wù)來開始:
# firewall-cmd --permanent --zone=public --remove-service=dhcpv6-client # firewall-cmd --permanent --zone=public --remove-service=ssh # firewall-cmd --permanent --zone=public --add-service=http # firewall-cmd --permanent --zone=public --add-service=https 然后,取消 internal 區(qū)域的 mdns、samba-client 和 dhcpv6-client 服務(wù)(僅保留 ssh),并增加你的組織為源: # firewall-cmd --permanent --zone=internal --remove-service=mdns # firewall-cmd --permanent --zone=internal --remove-service=samba-client # firewall-cmd --permanent --zone=internal --remove-service=dhcpv6-client # firewall-cmd --permanent --zone=internal --add-source=1.1.0.0/16
為容納你提升的 samba 的權(quán)限,增加一個(gè)富規(guī)則:
# firewall-cmd --permanent --zone=internal --add-rich-rule='rule family=ipv4 source address="1.1.1.0/8" service name="samba" accept'
最后,重新加載,把這些變化拉取到會話中:
# firewall-cmd --reload
僅剩下少數(shù)的細(xì)節(jié)了。從一個(gè) internal 區(qū)域以外的 IP 去嘗試通過 ssh 到你的服務(wù)器,結(jié)果是回復(fù)一個(gè)拒絕的消息。它是 firewalld 默認(rèn)的。更為安全的作法是去顯示不活躍的 IP 行為并丟棄該連接。改變 public 區(qū)域的目標(biāo)為 DROP,而不是 default 來實(shí)現(xiàn)它:
# firewall-cmd --permanent --zone=public --set-target=DROP # firewall-cmd --reload
但是,等等,你不再可以 ping 了,甚至是從內(nèi)部區(qū)域!并且 icmp (ping 使用的協(xié)議)并不在 firewalld 可以列入白名單的服務(wù)列表中。那是因?yàn)?,icmp 是第 3 層的 IP 協(xié)議,它沒有端口的概念,不像那些捆綁了端口的服務(wù)。在設(shè)置公共區(qū)域?yàn)?DROP 之前,ping 能夠通過防火墻是因?yàn)槟愕?default 目標(biāo)通過它到達(dá)防火墻的默認(rèn)動作(default),即允許它通過。但現(xiàn)在它已經(jīng)被刪除了。
為恢復(fù)內(nèi)部網(wǎng)絡(luò)的 ping,使用一個(gè)富規(guī)則:
# firewall-cmd --permanent --zone=internal --add-rich-rule='rule protocol value="icmp" accept' # firewall-cmd --reload
結(jié)果如下,這里是兩個(gè)活動區(qū)域的配置:
# firewall-cmd --zone=public --list-all public (default, active) interfaces: eno1 eno2 sources: services: http https ports: masquerade: no forward-ports: icmp-blocks: rich rules: # firewall-cmd --permanent --zone=public --get-target DROP # firewall-cmd --zone=internal --list-all internal (active) interfaces: sources: 1.1.0.0/16 services: ssh ports: masquerade: no forward-ports: icmp-blocks: rich rules: rule family=ipv4 source address="1.1.1.0/8" service name="samba" accept rule protocol value="icmp" accept # firewall-cmd --permanent --zone=internal --get-target default
這個(gè)設(shè)置演示了一個(gè)三層嵌套的防火墻。最外層,public,是一個(gè)接口區(qū)域,包含全世界的訪問。緊接著的一層,internal,是一個(gè)源區(qū)域,包含你的組織,它是 public 的一個(gè)子集。最后,一個(gè)富規(guī)則增加到最內(nèi)層,包含了你的工作組,它是 internal 的一個(gè)子集。
這里的關(guān)鍵信息是,當(dāng)在一個(gè)場景中可以突破到嵌套層,最外層將使用接口區(qū)域,接下來的將使用一個(gè)源區(qū)域,并且在源區(qū)域中額外使用富規(guī)則。
調(diào)試
firewalld 采用直觀范式來設(shè)計(jì)防火墻,但比它的前任 iptables 更容易產(chǎn)生歧義。如果產(chǎn)生無法預(yù)料的行為,或者為了更好地理解 firewalld 是怎么工作的,則可以使用 iptables 描述 netfilter 是如何配置操作的。前一個(gè)示例的輸出如下,為了簡單起見,將輸出和日志進(jìn)行了修剪:
# iptables -S -P INPUT ACCEPT ... (forward and output lines) ... -N INPUT_ZONES -N INPUT_ZONES_SOURCE -N INPUT_direct -N IN_internal -N IN_internal_allow -N IN_internal_deny -N IN_public -N IN_public_allow -N IN_public_deny -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -j INPUT_ZONES_SOURCE -A INPUT -j INPUT_ZONES -A INPUT -p icmp -j ACCEPT -A INPUT -m conntrack --ctstate INVALID -j DROP -A INPUT -j REJECT --reject-with icmp-host-prohibited ... (forward and output lines) ... -A INPUT_ZONES -i eno1 -j IN_public -A INPUT_ZONES -i eno2 -j IN_public -A INPUT_ZONES -j IN_public -A INPUT_ZONES_SOURCE -s 1.1.0.0/16 -g IN_internal -A IN_internal -j IN_internal_deny -A IN_internal -j IN_internal_allow -A IN_internal_allow -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT -A IN_internal_allow -s 1.1.1.0/8 -p udp -m udp --dport 137 -m conntrack --ctstate NEW -j ACCEPT -A IN_internal_allow -s 1.1.1.0/8 -p udp -m udp --dport 138 -m conntrack --ctstate NEW -j ACCEPT -A IN_internal_allow -s 1.1.1.0/8 -p tcp -m tcp --dport 139 -m conntrack --ctstate NEW -j ACCEPT -A IN_internal_allow -s 1.1.1.0/8 -p tcp -m tcp --dport 445 -m conntrack --ctstate NEW -j ACCEPT -A IN_internal_allow -p icmp -m conntrack --ctstate NEW -j ACCEPT -A IN_public -j IN_public_deny -A IN_public -j IN_public_allow -A IN_public -j DROP -A IN_public_allow -p tcp -m tcp --dport 80 -m conntrack --ctstate NEW -j ACCEPT -A IN_public_allow -p tcp -m tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT
在上面的 iptables 輸出中,新的鏈(以 -N 開始的行)是被首先聲明的。剩下的規(guī)則是附加到(以 -A 開始的行) iptables 中的。已建立的連接和本地流量是允許通過的,并且入站包被轉(zhuǎn)到 INPUT_ZONES_SOURCE 鏈,在那里如果存在相應(yīng)的區(qū)域,IP 將被發(fā)送到那個(gè)區(qū)域。從那之后,流量被轉(zhuǎn)到 INPUT_ZONES 鏈,從那里它被路由到一個(gè)接口區(qū)域。如果在那里它沒有被處理,icmp 是允許通過的,無效的被丟棄,并且其余的都被拒絕。
結(jié)論
firewalld 是一個(gè)文檔不足的防火墻配置工具,它的功能遠(yuǎn)比大多數(shù)人認(rèn)識到的更為強(qiáng)大。以創(chuàng)新的區(qū)域范式,firewalld 允許系統(tǒng)管理員去分解流量到每個(gè)唯一處理它的分類中,簡化了配置過程。因?yàn)樗庇^的設(shè)計(jì)和語法,它在實(shí)踐中不但被用于簡單的單一區(qū)域中也被用于復(fù)雜的多區(qū)域配置中。