centos7 firewall-cmd 理解多區域配置中的 firewalld 防火牆


原文:https://www.linuxidc.com/Linux/2017-11/148795.htm

現在的新聞里充斥着服務器被攻擊和數據失竊事件。對於一個閱讀過安全公告博客的人來說,通過訪問錯誤配置的服務器,利用最新暴露的安全漏洞或通過竊取的密碼來獲得系統控制權,並不是件多困難的事情。在一個典型的 Linux 服務器上的任何互聯網服務都可能存在漏洞,允許未經授權的系統訪問。

因為在應用程序層面上強化系統以防范任何可能的威脅是不可能做到的事情,而防火牆可以通過限制對系統的訪問提供了安全保證。防火牆基於源 IP、目標端口和協議來過濾入站包。因為這種方式中,僅有幾個 IP/端口/協議的組合與系統交互,而其它的方式做不到過濾。

Linux 防火牆是通過 netfilter 來處理的,它是內核級別的框架。這十幾年來,iptables 被作為 netfilter 的用戶態抽象層(LCTT 譯注: userland,一個基本的 UNIX 系統是由 kernel 和 userland 兩部分構成,除 kernel 以外的稱為 userland)。iptables 將包通過一系列的規則進行檢查,如果包與特定的 IP/端口/協議的組合匹配,規則就會被應用到這個包上,以決定包是被通過、拒絕或丟棄。

Firewalld 是最新的 netfilter 用戶態抽象層。遺憾的是,由於缺乏描述多區域配置的文檔,它強大而靈活的功能被低估了。這篇文章提供了一個示例去改變這種情況。

 

Firewalld 的設計目標

firewalld 的設計者認識到大多數的 iptables 使用案例僅涉及到幾個單播源 IP,僅讓每個符合白名單的服務通過,而其它的會被拒絕。這種模式的好處是,firewalld 可以通過定義的源 IP 和/或網絡接口將入站流量分類到不同區域zone。每個區域基於指定的准則按自己配置去通過或拒絕包。

另外的改進是基於 iptables 進行語法簡化。firewalld 通過使用服務名而不是它的端口和協議去指定服務,使它更易於使用,例如,是使用 samba 而不是使用 UDP 端口 137 和 138 和 TCP 端口 139 和 445。它進一步簡化語法,消除了 iptables 中對語句順序的依賴。

最后,firewalld 允許交互式修改 netfilter,允許防火牆獨立於存儲在 XML 中的永久配置而進行改變。因此,下面的的臨時修改將在下次重新加載時被覆蓋:

  1. # firewall-cmd <some modification>

而,以下的改變在重加載后會永久保存:

  1. # firewall-cmd --permanent <some modification>
  2. # firewall-cmd --reload

 

區域

在 firewalld 中最上層的組織是區域。如果一個包匹配區域相關聯的網絡接口或源 IP/掩碼 ,它就是區域的一部分。可用的幾個預定義區域:

  1. # firewall-cmd --get-zones
  2. block dmz drop external home internal public trusted work

任何配置了一個網絡接口和/或一個的區域就是一個活動區域active zone。列出活動的區域:

  1. # firewall-cmd --get-active-zones
  2. public
  3. interfaces: eno1 eno2

Interfaces (接口)是系統中的硬件和虛擬的網絡適配器的名字,正如你在上面的示例中所看到的那樣。所有的活動的接口都將被分配到區域,要么是默認的區域,要么是用戶指定的一個區域。但是,一個接口不能被分配給多於一個的區域。

在缺省配置中,firewalld 設置所有接口為 public 區域,並且不對任何區域設置源。其結果是,public 區域是唯一的活動區域。

Sources (源)是入站 IP 地址的范圍,它也可以被分配到區域。一個源(或重疊的源)不能被分配到多個區域。這樣做的結果是產生一個未定義的行為,因為不清楚應該將哪些規則應用於該源。

因為指定一個源不是必需的,任何包都可以通過接口匹配而歸屬於一個區域,而不需要通過源匹配來歸屬一個區域。這表示通過使用優先級方式,優先到達多個指定的源區域,稍后將詳細說明這種情況。首先,我們來檢查 public 區域的配置:

  1. # firewall-cmd --zone=public--list-all
  2. public(default, active)
  3. interfaces: eno1 eno2
  4. sources:
  5. services: dhcpv6-client ssh
  6. ports:
  7. masquerade:no
  8. forward-ports:
  9. icmp-blocks:
  10. rich rules:
  11. # firewall-cmd --permanent --zone=public--get-target
  12. default

逐行說明如下:

  • public (default, active) 表示 public 區域是默認區域(當接口啟動時會自動默認),並且它是活動的,因為,它至少有一個接口或源分配給它。
  • interfaces: eno1 eno2 列出了這個區域上關聯的接口。
  • sources: 列出了這個區域的源。現在這里什么都沒有,但是,如果這里有內容,它們應該是這樣的格式 xxx.xxx.xxx.xxx/xx。
  • services: dhcpv6-client ssh 列出了允許通過這個防火牆的服務。你可以通過運行 firewall-cmd --get-services得到一個防火牆預定義服務的詳細列表。
  • ports: 列出了一個允許通過這個防火牆的目標端口。它是用於你需要去允許一個沒有在 firewalld 中定義的服務的情況下。
  • masquerade: no 表示這個區域是否允許 IP 偽裝。如果允許,它將允許 IP 轉發,它可以讓你的計算機作為一個路由器。
  • forward-ports: 列出轉發的端口。
  • icmp-blocks: 阻塞的 icmp 流量的黑名單。
  • rich rules: 在一個區域中優先處理的高級配置。
  • default 是目標區域,它決定了與該區域匹配而沒有由上面設置中顯式處理的包的動作。

 

一個簡單的單區域配置示例

如果只是簡單地鎖定你的防火牆。簡單地在刪除公共區域上當前允許的服務,並重新加載:

  1. # firewall-cmd --permanent --zone=public--remove-service=dhcpv6-client
  2. # firewall-cmd --permanent --zone=public--remove-service=ssh
  3. # firewall-cmd --reload

在下面的防火牆上這些命令的結果是:

  1. # firewall-cmd --zone=public--list-all
  2. public(default, active)
  3. interfaces: eno1 eno2
  4. sources:
  5. services:
  6. ports:
  7. masquerade:no
  8. forward-ports:
  9. icmp-blocks:
  10. rich rules:
  11. # firewall-cmd --permanent --zone=public--get-target
  12. default

本着盡可能嚴格地保證安全的精神,如果發生需要在你的防火牆上臨時開放一個服務的情況(假設是 ssh),你可以增加這個服務到當前會話中(省略 --permanent),並且指示防火牆在一個指定的時間之后恢復修改:

  1. # firewall-cmd --zone=public--add-service=ssh--timeout=5m

這個 timeout 選項是一個以秒(s)、分(m)或小時(h)為單位的時間值。

 

目標

當一個區域處理它的源或接口上的一個包時,但是,沒有處理該包的顯式規則時,這時區域的目標target決定了該行為:

  • ACCEPT:通過這個包。
  • %%REJECT%%:拒絕這個包,並返回一個拒絕的回復。
  • DROP:丟棄這個包,不回復任何信息。
  • default:不做任何事情。該區域不再管它,把它踢到“樓上”。

在 firewalld 0.3.9 中有一個 bug (已經在 0.3.10 中修復),對於一個目標是除了“default”以外的源區域,不管允許的服務是什么,這的目標都會被應用。例如,一個使用目標 DROP 的源區域,將丟棄所有的包,甚至是白名單中的包。遺憾的是,這個版本的 firewalld 被打包到 RHEL7 和它的衍生版中,使它成為一個相當常見的 bug。本文中的示例避免了可能出現這種行為的情況。

 

優先權

活動區域中扮演兩個不同的角色。關聯接口行為的區域作為接口區域,並且,關聯源行為的區域作為源區域(一個區域能夠扮演兩個角色)。firewalld 按下列順序處理一個包:

  1. 相應的源區域。可以存在零個或一個這樣的區域。如果這個包滿足一個富規則rich rule、服務是白名單中的、或者目標沒有定義,那么源區域處理這個包,並且在這里結束。否則,向上傳遞這個包。
  2. 相應的接口區域。肯定有一個這樣的區域。如果接口處理這個包,那么到這里結束。否則,向上傳遞這個包。
  3. firewalld 默認動作。接受 icmp 包並拒絕其它的一切。

這里的關鍵信息是,源區域優先於接口區域。因此,對於多區域的 firewalld 配置的一般設計模式是,創建一個優先源區域來允許指定的 IP 對系統服務的提升訪問,並在一個限制性接口區域限制其它訪問。

 

一個簡單的多區域示例

為演示優先權,讓我們在 public 區域中將 http 替換成 ssh,並且為我們喜歡的 IP 地址,如 1.1.1.1,設置一個默認的 internal 區域。以下的命令完成這個任務:

  1. # firewall-cmd --permanent --zone=public--remove-service=ssh
  2. # firewall-cmd --permanent --zone=public--add-service=http
  3. # firewall-cmd --permanent --zone=internal --add-source=1.1.1.1
  4. # firewall-cmd --reload

這些命令的結果是生成如下的配置:

  1. # firewall-cmd --zone=public--list-all
  2. public(default, active)
  3. interfaces: eno1 eno2
  4. sources:
  5. services: dhcpv6-client http
  6. ports:
  7. masquerade:no
  8. forward-ports:
  9. icmp-blocks:
  10. rich rules:
  11. # firewall-cmd --permanent --zone=public--get-target
  12. default
  13. # firewall-cmd --zone=internal --list-all
  14. internal (active)
  15. interfaces:
  16. sources:1.1.1.1
  17. services: dhcpv6-client mdns samba-client ssh
  18. ports:
  19. masquerade:no
  20. forward-ports:
  21. icmp-blocks:
  22. rich rules:
  23. # firewall-cmd --permanent --zone=internal --get-target
  24. default

在上面的配置中,如果有人嘗試從 1.1.1.1 去 ssh,這個請求將會成功,因為這個源區域(internal)被首先應用,並且它允許 ssh 訪問。

如果有人嘗試從其它的地址,如 2.2.2.2,去訪問 ssh,它不是這個源區域的,因為和這個源區域不匹配。因此,這個請求被直接轉到接口區域(public),它沒有顯式處理 ssh,因為,public 的目標是 default,這個請求被傳遞到默認動作,它將被拒絕。

如果 1.1.1.1 嘗試進行 http 訪問會怎樣?源區域(internal)不允許它,但是,目標是 default,因此,請求將傳遞到接口區域(public),它被允許訪問。

現在,讓我們假設有人從 3.3.3.3 拖你的網站。要限制從那個 IP 的訪問,簡單地增加它到預定義的 drop 區域,正如其名,它將丟棄所有的連接:

  1. # firewall-cmd --permanent --zone=drop --add-source=3.3.3.3
  2. # firewall-cmd --reload

下一次 3.3.3.3 嘗試去訪問你的網站,firewalld 將轉發請求到源區域(drop)。因為目標是 DROP,請求將被拒絕,並且它不會被轉發到接口區域(public)。

 

一個實用的多區域示例

假設你為你的組織的一台服務器配置防火牆。你希望允許全世界使用 http 和 https 的訪問,你的組織(1.1.0.0/16)和工作組(1.1.1.0/8)使用 ssh 訪問,並且你的工作組可以訪問 samba 服務。使用 firewalld 中的區域,你可以用一個很直觀的方式去實現這個配置。

public 這個命名,它的邏輯似乎是把全世界訪問指定為公共區域,而 internal 區域用於為本地使用。從在 public 區域內設置使用 http 和 https 替換 dhcpv6-client 和 ssh 服務來開始:

  1. # firewall-cmd --permanent --zone=public--remove-service=dhcpv6-client
  2. # firewall-cmd --permanent --zone=public--remove-service=ssh
  3. # firewall-cmd --permanent --zone=public--add-service=http
  4. # firewall-cmd --permanent --zone=public--add-service=https

然后,取消 internal 區域的 mdnssamba-client 和 dhcpv6-client 服務(僅保留 ssh),並增加你的組織為源:

  1. # firewall-cmd --permanent --zone=internal --remove-service=mdns
  2. # firewall-cmd --permanent --zone=internal --remove-service=samba-client
  3. # firewall-cmd --permanent --zone=internal --remove-service=dhcpv6-client
  4. # firewall-cmd --permanent --zone=internal --add-source=1.1.0.0/16

為容納你提升的 samba 的權限,增加一個富規則:

  1. # firewall-cmd --permanent --zone=internal --add-rich-rule='rule family=ipv4 source address="1.1.1.0/8" service name="samba" accept'

最后,重新加載,把這些變化拉取到會話中:

  1. # firewall-cmd --reload

僅剩下少數的細節了。從一個 internal 區域以外的 IP 去嘗試通過 ssh 到你的服務器,結果是回復一個拒絕的消息。它是 firewalld 默認的。更為安全的作法是去顯示不活躍的 IP 行為並丟棄該連接。改變 public 區域的目標為 DROP,而不是 default 來實現它:

  1. # firewall-cmd --permanent --zone=public--set-target=DROP
  2. # firewall-cmd --reload

但是,等等,你不再可以 ping 了,甚至是從內部區域!並且 icmp (ping 使用的協議)並不在 firewalld 可以列入白名單的服務列表中。那是因為,icmp 是第 3 層的 IP 協議,它沒有端口的概念,不像那些捆綁了端口的服務。在設置公共區域為 DROP 之前,ping 能夠通過防火牆是因為你的 default 目標通過它到達防火牆的默認動作(default),即允許它通過。但現在它已經被刪除了。

為恢復內部網絡的 ping,使用一個富規則:

  1. # firewall-cmd --permanent --zone=internal --add-rich-rule='rule protocol value="icmp" accept'
  2. # firewall-cmd --reload

結果如下,這里是兩個活動區域的配置:

  1. # firewall-cmd --zone=public--list-all
  2. public(default, active)
  3. interfaces: eno1 eno2
  4. sources:
  5. services: http https
  6. ports:
  7. masquerade:no
  8. forward-ports:
  9. icmp-blocks:
  10. rich rules:
  11. # firewall-cmd --permanent --zone=public--get-target
  12. DROP
  13. # firewall-cmd --zone=internal --list-all
  14. internal (active)
  15. interfaces:
  16. sources:1.1.0.0/16
  17. services:ssh
  18. ports:
  19. masquerade:no
  20. forward-ports:
  21. icmp-blocks:
  22. rich rules:
  23. rule family=ipv4 source address="1.1.1.0/8" service name="samba" accept
  24. rule protocol value="icmp" accept
  25. # firewall-cmd --permanent --zone=internal --get-target
  26. default

這個設置演示了一個三層嵌套的防火牆。最外層,public,是一個接口區域,包含全世界的訪問。緊接着的一層,internal,是一個源區域,包含你的組織,它是 public 的一個子集。最后,一個富規則增加到最內層,包含了你的工作組,它是 internal 的一個子集。

這里的關鍵信息是,當在一個場景中可以突破到嵌套層,最外層將使用接口區域,接下來的將使用一個源區域,並且在源區域中額外使用富規則。

 

調試

firewalld 采用直觀范式來設計防火牆,但比它的前任 iptables 更容易產生歧義。如果產生無法預料的行為,或者為了更好地理解 firewalld 是怎么工作的,則可以使用 iptables 描述 netfilter 是如何配置操作的。前一個示例的輸出如下,為了簡單起見,將輸出和日志進行了修剪:

  1. # iptables -S
  2. -P INPUT ACCEPT
  3. ...(forward and output lines)...
  4. -N INPUT_ZONES
  5. -N INPUT_ZONES_SOURCE
  6. -N INPUT_direct
  7. -N IN_internal
  8. -N IN_internal_allow
  9. -N IN_internal_deny
  10. -N IN_public
  11. -N IN_public_allow
  12. -N IN_public_deny
  13. -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
  14. -A INPUT -i lo -j ACCEPT
  15. -A INPUT -j INPUT_ZONES_SOURCE
  16. -A INPUT -j INPUT_ZONES
  17. -A INPUT -p icmp -j ACCEPT
  18. -A INPUT -m conntrack --ctstate INVALID -j DROP
  19. -A INPUT -j REJECT --reject-with icmp-host-prohibited
  20. ...(forward and output lines)...
  21. -A INPUT_ZONES -i eno1 -j IN_public
  22. -A INPUT_ZONES -i eno2 -j IN_public
  23. -A INPUT_ZONES -j IN_public
  24. -A INPUT_ZONES_SOURCE -1.1.0.0/16-g IN_internal
  25. -A IN_internal -j IN_internal_deny
  26. -A IN_internal -j IN_internal_allow
  27. -A IN_internal_allow -p tcp -m tcp --dport 22-m conntrack --ctstate NEW -j ACCEPT
  28. -A IN_internal_allow -1.1.1.0/8-p udp -m udp --dport 137-m conntrack --ctstate NEW -j ACCEPT
  29. -A IN_internal_allow -1.1.1.0/8-p udp -m udp --dport 138-m conntrack --ctstate NEW -j ACCEPT
  30. -A IN_internal_allow -1.1.1.0/8-p tcp -m tcp --dport 139-m conntrack --ctstate NEW -j ACCEPT
  31. -A IN_internal_allow -1.1.1.0/8-p tcp -m tcp --dport 445-m conntrack --ctstate NEW -j ACCEPT
  32. -A IN_internal_allow -p icmp -m conntrack --ctstate NEW -j ACCEPT
  33. -A IN_public -j IN_public_deny
  34. -A IN_public -j IN_public_allow
  35. -A IN_public -j DROP
  36. -A IN_public_allow -p tcp -m tcp --dport 80-m conntrack --ctstate NEW -j ACCEPT
  37. -A IN_public_allow -p tcp -m tcp --dport 443-m conntrack --ctstate NEW -j ACCEPT

在上面的 iptables 輸出中,新的鏈(以 -N 開始的行)是被首先聲明的。剩下的規則是附加到(以 -A 開始的行) iptables 中的。已建立的連接和本地流量是允許通過的,並且入站包被轉到 INPUT_ZONES_SOURCE 鏈,在那里如果存在相應的區域,IP 將被發送到那個區域。從那之后,流量被轉到 INPUT_ZONES 鏈,從那里它被路由到一個接口區域。如果在那里它沒有被處理,icmp 是允許通過的,無效的被丟棄,並且其余的都被拒絕。

 

結論

firewalld 是一個文檔不足的防火牆配置工具,它的功能遠比大多數人認識到的更為強大。以創新的區域范式,firewalld 允許系統管理員去分解流量到每個唯一處理它的分類中,簡化了配置過程。因為它直觀的設計和語法,它在實踐中不但被用於簡單的單一區域中也被用於復雜的多區域配置中。


via: https://www.linuxjournal.com/content/understanding-firewalld-multi-zone-configurations

作者:Nathan Vance 譯者:qhwdw 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出

本文永久更新鏈接地址http://www.linuxidc.com/Linux/2017-11/148795.htm


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM