OpenStack Neutron淺析(三)

1. 基礎知識

1.1 防火牆(firewall)

防火牆是依照特定的規則來控制進出它的網絡流量的網絡安全系統。一個典型的場景是在一個受信任的內網和不受信任的外網比如 Internet 之間建立一個屏障。防火牆可以是電腦上運行的軟件,也可以是獨立的硬件設備。
請添加圖片描述
與負載均衡器類似,按照其工作的網絡層次,防火牆可以分爲:

  • 網絡層防火牆(四層):網絡層防火牆可視爲一種 IP封包過濾器,運作在底層的TCP/IP協議堆棧上。我們可以以枚舉的方式,只允許符合特定規則的封包通過,其餘的一概禁止穿越防火牆(病毒除外,防火牆不能防止病毒侵入)。這些規則通常可以經由管理員定義或修改,不過某些防火牆設備可能只能套用內置的規則。我們也能以另一種較寬鬆的角度來制定防火牆規則,只要封包不符合任何一項“否定規則”就予以放行。操作系統及網絡設備大多已內置防火牆功能。較新的防火牆能利用封包的多樣屬性來進行過濾,例如:來源IP地址、來源端口號、目的 IP 地址或端口號、服務類型(如 HTTP 或是 FTP)。也能經由通信協議、TTL值、來源的網域名稱或網段…等屬性來進行過濾。
    請添加圖片描述

  • 應用層防火牆(七層):應用層防火牆是在 TCP/IP 堆棧的“應用層”上運作,您使用瀏覽器時所產生的數據流或是使用 FTP時的數據流都是屬於這一層。應用層防火牆可以攔截進出某應用程序的所有封包,並且封鎖其他的封包(通常是直接將封包丟棄)。理論上,這一類的防火牆可以完全阻絕外部的數據流進到受保護的機器裏。

按照防火牆的位置,可以分爲:

  • 主防火牆:如上面圖1所示,主防火牆位於網絡邊界,控制進出網絡的網絡包。Neutron FWaas 是一種主防火牆,安裝在網絡節點上。

  • 分佈式防火牆:分佈式防火牆位於內部網絡節點上,比如終端計算機上,控制進出該計算機的網絡包。Neutron 安全組(Security
    Group)是一種分佈式防火牆,安裝在計算節點上。

主防火牆的特點:

  • 內部網絡和外部網絡之間的所有網絡數據流都必須經過防火牆。防火牆適用於用戶網絡系統的邊界,屬於用戶網絡邊界的安全保護設備。

  • 只有符合安全策略的數據流才能通過防火牆。防火牆是一個類似於橋接或路由器的、多端口的(網絡接口>=2)轉發設備,它跨接於多個分離的物理網段之間,並在報文轉發過程之中完成對報文的審查工作。

  • 應用層防火牆具備更細緻的防護能力。下一代防火牆具備應用層分析的能力,能夠基於不同的應用特徵,實現應用層的攻擊過濾,在具備傳統防火牆、IPS、防毒等功能的同時,還能夠對用戶和內容進行識別管理,兼具了應用層的高性能和智能聯動兩大特性,能夠更好的針對應用層攻擊進行防護。

防火牆的主要概念:

  • 規則:只有符合所制定的規則的網絡包才能通過防火牆。
  • 策略:規則的邏輯集合。

1.2 IP 地址欺騙 (IP Spoofing)

正常情況下,二層數據幀的源IP 地址就是發出數據的機器的 IP 地址,對方計算機接收到以後,向該 IP 地址發出回覆數據幀:
在這裏插入圖片描述
(該例子中,node1 發往 node2 的幀的 IP 地址就是 node1 的地址,因此 node2 能夠通過 ARP 獲取 node1 的 MAC,並將回覆將發回到它)

如果源計算機的數據幀的源 IP 地址不是它自己的IP地址而是一個不存在的地址或者另外一臺機器的地址,目的計算機接受到數據幀後,它就會一直不停的發出 ARP 廣播,最終也無法獲取到MAC地址,或者發送返回幀到另一臺的計算機。這就是所謂的(源) IP 地址欺騙。
在這裏插入圖片描述
(該例子中,node1將它發往 node2 的數據幀的源IP設置爲 node3 的IP,導致 node2 的回覆發到了node3)

如果大量的計算機使用另外一臺計算機的 IP 作爲源 IP 向很多的計算機發出 ping 命令,那麼那一臺計算機將會收到很多的 ping 回覆。這將導致它的網絡帶寬被塞滿而不能對外提供網絡服務。

以上資料來源

常見的防止IP地址欺騙的方法:

  • 任何進入網絡的數據包不能把網絡內部的地址作爲源地址。
  • 任何進入網絡的數據包必須把網絡內部的地址作爲目的地址。
  • 任何離開網絡的數據包必須把網絡內部的地址作爲源地址。
  • 任何離開網絡的數據包不能把網絡內部的地址作爲目的地址。
  • 任何進入或離開網絡的數據包不能把一個私有地址(Private Address)或在RFC1918中列出的屬於保留空間(包括10.x.x.x/8、172.16.x.x/12 或192.168.x.x/16 和網絡回送地址127.0.0.0/8.)的地址作爲源或目的地址。阻塞任意源路由包或任何設置了IP選項的包。

Neutron 安全組針對 IP 地址欺騙,特別設置了相應的防火牆規則。

1.3 iptables bridge (在 linux 橋上做防火牆)

首先說說 bridge。這篇文章 詳細解釋了 bridge 的工作原理。簡單地說,brige 是 linux 上的一個虛擬(邏輯)設備,它依賴於從設備,並將從設備虛擬化爲端口(port),從設備的 IP 及 MAC 都不再可用,且被設置爲接收任何包,最終由 bridge 設備來決定數據包的去向:接收到本機、轉發、丟棄。

上一篇文章介紹了 iptables 是如何處理三層網絡包的。顯然,普通的 Linux 內核 IP 協議棧代碼和 netfilter 無法處理經過網橋的數據包,因爲網橋是屬於網絡二層,對於 IP 棧來說是透明的。因此,Linux 內核和 iptables 增加了處理經過二層網橋的數據包的功能。下面是增加了網橋處理能力的 netfilter 的數據包處理過程:
請添加圖片描述
(引用自 https://upload.wikimedia.org/wikipedia/commons/3/37/Netfilter-packet-flow.svg

linux-bridge/netfilter 在內核(代碼模塊成爲 br-nf)被啓用後,iptables 鏈的 Hook 函數也被註冊到橋處理代碼(bridging code)中。然而,這並不意味着它們不再被註冊到標準的 IP協議棧代碼中。對於被橋代碼處理的網絡包來說,br-nf 會判斷 iptables 哪些鏈會在網絡棧的什麼位置被遍歷。顯然,它會保證同一個包不會被鏈處理兩次,因此所有沒有被橋代碼處理的包會被標準的IP包處理方式來處理。但是,如果一個計算機既有 bridge 也有 router,那麼進入該計算機的網絡包,有些會被 bridge code 中 netfiler Hook 方法處理,有些會被 IP code 中的 netfilter hook 方法處理,這點需要在定義 iptables rules 時加以注意。

再來談談關鍵的 ”Bridging Decision“ 部分,其代碼在(rx_handler_result_t br_handle_frame(struct sk_buff **pskb))。它會基於目的MAC地址做出如下判斷:

  1. bridge 網絡幀,如果幀的目的 MAC 地址是在橋的另一側的某個網絡設備上。
  2. 泛洪該網絡幀,如果幀的目的 MAC 對網橋是不認識的。
  3. 轉到更高一層的三層IP協議棧代碼處理,如果幀的目的地址是橋本身的或者它的某個端口的。
  4. 忽略它,如果幀的目的地址是位於它來自的橋的方向的同一側。

對1和2來說,接下來該數據幀被 filter 的 FORWARD 鏈處理。對(3)來說,它會被 filter 的 INPUT 鏈處理。發生這種情況時,該 bridge 其實是被用作一個路由器(一個對比例子是現實世界中的帶路由的交換機設備)。包含 IP 包的以太幀的目的 MAC 地址是橋的MAC地址,但是目的 IP 地址不是橋的IP地址。 這篇文章 ebtables/iptables interaction on a Linux-based bridge 詳細分析了其處理過程。

要在 Linux bridge 上做防火牆(firewall packets as they are being bridged,或者說在 linux bridge 上應用 iptables 規則),必須滿足以下條件:

  • Linux 內核支持 bridge (CONFIG_BRIDGE=m or CONFIG_BRIDGE=y).
  • Linux 內核支持 bridge/netfilter (CONFIG_BRIDGE_NETFILTER=y).
  • Linux 內核需要包含 Netfilter physdev match 支持 (CONFIG_IP_NF_MATCH_PHYSDEV=m or CONFIG_IP_NF_MATCH_PHYSDEV=y). 它在 2.6 版本的內核中開始作爲標準模塊。
  • 你的 iptables 工具需要支持 physdev match,以及支持在一條規則中使用多個 ‘-m physdev’.iptables 從 1.3.6 版本開始支持。
  • 你需要安裝 bridge-utils 包。

需要注意的,各個 Linux 發行版並不是都默認啓用了 netfilter for bridge,比如 Ubuntu 默認啓用了, 而 RedHat 默認沒啓用。Neutron 會執行下面的命令來啓用它:

sysctl -w net.bridge.bridge-nf-call-arptables=1
sysctl -w net.bridge.bridge-nf-call-iptables=1

從Linux 2.6 內核版本上,iptables 1.3.6 版本以後就能夠過濾 Linux bridge 上的網絡包了。它使用如下參數:
在這裏插入圖片描述
舉例(來源):

在一臺 linux 機器上創建 linux bridge br0,連接 eth0 和 eth1.其中 eth0 是內網端口,eth1和 eth2是外網端口。

# brctl addbr br0
# brctl addif br0 eth0
# brctl addif br0 eth1
# ifconfig br0 netmask 255.255.255.0 192.168.32.1 up 

請添加圖片描述
實際上,在將 eth1 的 IP 設置給 br0 以後,該機器可以通過 br0/eth1 訪問外網(這篇文章 詳細地闡述了該原理),這樣,該 linux 機器是同時作爲一臺路由器和一臺終端機:

  • 作爲內網和外網之間的路由器,這些數據包經過 br0 時會被 iptables 的 filter 表的 FORWARD 鏈處理;
  • 作爲可以訪問外網的終端機,外網的數據包通過 eth1 直接進出該計算機,進來的包會被 iptables 的 filter 表的 INPUT鏈過濾,出去的包被 OUTPUT 鏈過濾。

可以創建如下的 iptables 規則來實現經過 br0 的網絡包:

#允許本機通過訪問外網,但是將進來的 udp,tcp 和 icmp 的網絡包寫日誌(INPUT 規則的 physdev-in 肯定是 eth1 了)
iptables -A INPUT -p udp -m physdev --physdev-in eth1 -j LOG
iptables -A INPUT -p tcp -m physdev --physdev-in eth1 -j LOG
iptables -A INPUT -p icmp -m physdev --physdev-in eth1 -j LOG

# 允許 ssh, smtp and http 到 br0(INPUT!)
iptables -A INPUT -p tcp --dport 22 -m physdev --physdev-in eth1 -j ACCEPT
iptables -A INPUT -p tcp --dport 25 -m physdev --physdev-in eth1 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -m physdev --physdev-in eth1 -j ACCEPT

# 拒絕到 br0 的別的網絡包
iptables -A INPUT -p tcp --syn -m physdev --physdev-in eth1 -J REJECT

# 允許通過 tcp 端口 22(ssh),25 (smtp),80(http)到內網
iptables -A FORWARD -p tcp --dport 22 -m physdev --physdev-in eth1 --physdev-out eth0 -j ACCEPT
iptables -A FORWARD -p tcp --dport 25 -m physdev --physdev-in eth1 --physdev-out eth0 -j ACCEPT
iptables -A FORWARD -p tcp --dport 80 -m physdev --physdev-in eth1 --physdev-out eth0 -j ACCEPT

# 禁止 tcp 端口 6667 (IRC)
iptables -A FORWARD -p tcp --dport 6667 -m physdev --physdev-in eth1 -j REJECT

# 禁止其它連接到內網
iptables -A FORWARD -p tcp --syn -m physdev --physdev-in eth1 --physdev-out eth0 -j REJECT

1.4 ipset 和在 iptables 規則中使用 ipset

在 iptables 中,如果去匹配多個 IP 地址的話,就會寫入多條 iptables 的規則(這些 IP 都是無規律性的),當如果需要匹配幾百甚至上千個 IP 地址的話,那麼性能就會受到嚴重的影響。使用 ipset 的話,這種情況可以有很大的改善,其最主要是的在結構和規則的查找上面做了很大的改善。當出現上面的情況的時候,ipset 對性能就始終穩定在一個相對值上。根據提供的測試結果表明,當規則在300-1500之間的時候其對性能的影響基本是水平線。所以當你的防火牆規則過多的時候不妨試試看。

使用:

  1. 首先 ipset 裏面好多的命令是和 iptables 一樣的,比如 -F ,-X, -A, -nL等等。

  2. 用戶如果什麼都沒有添加的話,這個時候 ipset list 就會發現都是空的。

  3. 這個時候我們試着添加一個 set,如:ipset -N test_policy ipmap --network 192.168.100.1/24。該命令:

    1. test_policy:自定義set;
    2. ipmap:自定義set的類型,表示是 IP 地址; bitmap:ip,mac 表示是 IP 或者 MAC 地址。
    3. network 192.168.100.1/24:代表一個網段
  4. 自定義 set 創建好了後就需要在上面添加一些IP了,如:

    1. ipset -A test_policy 192.168.100.1
    2. ipset -A test_policy 192.168.100.2
    3. ipset -A test_policy 192.168.100.3
    4. ipset -A test_policy 192.168.100.4
  5. 這個時候你ipset -nL就會看到該 set 以及它的 members:

    root@compute1:/home/s1# ipset list
    Name: test_policy
    Type: bitmap:ip
    Revision: 2
    Header: range 192.168.100.0-192.168.100.255
    Size in memory: 160
    References: 0
    Members:
    192.168.100.1
    192.168.100.2
    192.168.100.3
    192.168.100.4
    
  6. 把它加到 iptables 鏈裏面,比如說加到 FORWARD 鏈裏面。比如要拒絕該 ipset 中計算機的訪問,則添加規則 iptables -A FORWARD -m set --match-set test_policy src -j DROP。其中:

    1. src:也就是隻是匹配的源地址,如果你需要匹配目的地址的話那麼就寫成 dst

以上部分資料來自 來源。更詳細的信息,請 man ipset。

2. Neutron 防火牆和安全組概述

爲了虛機和網絡安全,Neutron 提供安全組和 FWaas(firewall-as-a-service)。兩者的概念非常類似。一個安全組定義了哪些進入的網絡流量能被轉發給虛機。安全組包含一組防火牆策略,稱爲安全組規則(Security Group Rule)。可以定義n個安全組,每個安全組可以有n個規則,可以給每個實例綁定n個安全組。FWaas 則作用於虛擬路由器上,對進出租戶網絡的網絡流量進行過濾。OpenStack 的相關的組件爲:

  1. Nova Security Group:Nova 項目提供給虛機的安全組。
  2. Neutron Security Group:Neutorn 項目提供給虛機的安全組。
  3. Neutron FWaas:基於 Neutron L3 Agent 實現的虛機防火牆的一個參考實現。

這三個組件底層都通過控制 Linux iptables 來控制進出虛機或者租戶網絡的網絡包,但是在不同的位置使用不同的方法來實現不同的目的。三者之間的比較如下:
在這裏插入圖片描述

3. Neutron 安全組

我們知道,每個網橋(bridge)都有若干個端口(port)連接到它。從一個 port 進來的數據包都根據其目的 MAC 地址會被轉發到其他端口,或者被丟棄。同樣地,nova-compute 節點(計算節點)也充當兩個角色:數據網絡的轉發器(bridge)(它使用 qbr bridge 將外部訪問虛機的流量轉發到虛機。當然了,在進入 qbr 橋之前,OVS 需要對 traffic 做一些操作)和 終端機(這個節點往往會配置多塊網卡,一塊用於數據網絡,一塊用於管理網絡,這樣,別的計算機通過管理網絡來訪問該計算機,比如配置 nova-compute 等)。跟上面例子區別的是,qbr 網橋並沒有設置 IP 地址,因此需要別的網卡。而 qbr 橋是一個簡單的網橋,它一頭連接的是虛機網卡 eth0 的 tap 設備(比如 tap59cfa0b8-2f),另一頭連接 veth pari 的一端(比如qvb59cfa0b8-2f),該 veth 設備的另一端是 OVS 上的端口 qvo59cfa0b8-2f。可見,qbr bridge 連接了虛機的網卡和 OVS 橋。使用 qbr 後,進入 qvo 的網絡包都將被 qbr 轉發到 tap 設備,而離開 tap 設備的網絡包都將被轉發到 qvo 上。 Neutron 安全組就是作用在 qbr 橋上。
在這裏插入圖片描述
至於爲什麼不將虛機的網卡直接連接到 OVS 橋 br-int,官方說法是:“理想地,TAP 設備最好能直接掛在 br-int 上。不幸的是,因爲 OpenStack Security Group 的實現方式,這種掛載是不可能實現的。OpenStack 使用 TAP 設備上的 iptables 規則來實現 Security Group,而 open vswitch 不支持在直接連到其網橋上的 TAP 設備上使用 iptables。因此,不得不增加 Linux bridge qbr 來將 TAP 設備連到 OVS bridge 上。”。簡單地說,OpenStack 需要在 qbr 橋上使用 iptables 過濾進出虛機的數據包,而 br-int 上無法做到這一點。

3.1 配置

在這裏插入圖片描述
neutron 也提供兩種安全組的實現:IptablesFirewallDriver 和 OVSHybridIptablesFirewallDriver

  • neutron.agent.linux.iptables_firewall.IptablesFirewallDriver :iptables-based FirewallDriver implementation
  • neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver:subclass of IptablesFirewallDriver with additional bridge

默認值是 neutron.agent.firewall.NoopFirewallDriver,表示不使用 neutron security group。

3.2 CLI 示例

列表 安全組:

s1@controller:~$ neutron security-group-list
+--------------------------------------+------------+-------------+
| id                                   | name       | description |
+--------------------------------------+------------+-------------+
| 0aff643b-7b34-4384-b482-f37eccef5b90 | sg-all-ssh | allow ssh   |
| c98a2a3f-1b06-429d-b419-aa862662f116 | default    | default     |
| f5377a66-803d-481b-b4c3-a6631e8ab456 | default    | default     |
+--------------------------------------+------------+-------------+
 
列表配置了某安全組的所有 port:
s1@controller:~$ neutron port-list -c security_groups -c id -c mac_address -c fixed_ips -c device_id | grep c98a2a3f-1b06-429d-b419-aa862662f116
| [u'c98a2a3f-1b06-429d-b419-aa862662f116'] | 29eaea66-6614-47e3-b251-0104ff9f12e2 | fa:16:3e:bc:52:eb | {"subnet_id": "d803eaa3-63c9-4c2b-834a-9780db31df70", "ip_address": "100.1.250.1"}   | 1214b1b4-7c3a-41ad-ad8e-1e520b9c2830                                          |
| [u'c98a2a3f-1b06-429d-b419-aa862662f116'] | a7e26c3e-c1ae-4c65-a0e4-2d81266a11b3 | fa:16:3e:b8:f9:ad | {"subnet_id": "4ac56c61-84f3-4d00-b87a-1ab2441e8437", "ip_address": "100.1.150.1"}   | 1214b1b4-7c3a-41ad-ad8e-1e520b9c2830
 
s1@controller:~$ neutron port-list -c security_groups -c id -c mac_address -c fixed_ips -c device_id | grep 29eaea66-6614-47e3-b251-0104ff9f12e2
| [u'0aff643b-7b34-4384-b482-f37eccef5b90'] | 29eaea66-6614-47e3-b251-0104ff9f12e2 | fa:16:3e:bc:52:eb | {"subnet_id": "d803eaa3-63c9-4c2b-834a-9780db31df70", "ip_address": "100.1.250.1"}   | 1214b1b4-7c3a-41ad-ad8e-1e520b9c2830                                          |

刪除指定 port 的安全組:
s1@controller:~$ neutron port-update --no-security-groups 29eaea66-6614-47e3-b251-0104ff9f12e2
Updated port: 29eaea66-6614-47e3-b251-0104ff9f12e2
 
刪除後查看:
s1@controller:~$ neutron port-list -c security_groups -c id -c mac_address -c fixed_ips -c device_id | grep 29eaea66-6614-47e3-b251-0104ff9f12e2
| []                                        | 29eaea66-6614-47e3-b251-0104ff9f12e2 | fa:16:3e:bc:52:eb | {"subnet_id": "d803eaa3-63c9-4c2b-834a-9780db31df70", "ip_address": "100.1.250.1"}   | 1214b1b4-7c3a-41ad-ad8e-1e520b9c2830                                          |

設置指定 port 的安全組:
s1@controller:~$ neutron port-update --security-group 0aff643b-7b34-4384-b482-f37eccef5b90 29eaea66-6614-47e3-b251-0104ff9f12e2               
Updated port: 29eaea66-6614-47e3-b251-0104ff9f12e2

設置後查看
s1@controller:~$ neutron port-list -c security_groups -c id -c mac_address -c fixed_ips -c device_id | grep 29eaea66-6614-47e3-b251-0104ff9f12e2
| [u'0aff643b-7b34-4384-b482-f37eccef5b90'] | 29eaea66-6614-47e3-b251-0104ff9f12e2 | fa:16:3e:bc:52:eb | {"subnet_id": "d803eaa3-63c9-4c2b-834a-9780db31df70", "ip_address": "100.1.250.1"}   | 1214b1b4-7c3a-41ad-ad8e-1e520b9c2830

3.3 Neutron 安全組驅動

如上所述,Neutron 安全組提供兩種驅動,OVSHybridIptablesFirewallDriver 和 IptablesFirewallDriver。不幸的是,在 Juno 版本上使用 IptablesFirewallDriver 遇到下面的 bug 而無法使用:

Command: ['sudo', '/usr/bin/neutron-rootwrap', '/etc/neutron/rootwrap.conf', 'iptables-restore', '-c']
Exit code: 2
Stdout: ''
Stderr: "iptables-restore v1.4.21: interface name `406e066f-5d2a-4df9-b763-2bff230738cb' must be shorter than IFNAMSIZ (15)\nError occurred at line: 96\nTry `iptables-restore -h' or 'iptables-restore --help' for more information.\n"
2015-07-13 23:30:54.312 9389 ERROR neutron.agent.linux.iptables_manager [req-63695db6-6bdf-4ec0-8186-55218a076ab5 None] IPTablesManager.apply failed to apply the following set of iptables rules。

下面的分析是基於 OVSHybridIptablesFirewallDriver 的。

3.3.1 Neuron 安全組使用的 iptables 鏈和規則

理論上,qbr 橋只負責在虛機和 br-int 之間轉發網絡幀,因此 bridge 代碼應該是用 filter 表的 FORWARD 鏈來處理這些網絡幀。但是,基於還沒有被找到的原因,Neutron 還是對 filter 表的 INPUT 鏈進行了處理。根據上面基礎知識部分的描述,只有當 qbr 承擔路由器功能時(達到的網絡幀的目的 MAC 是它自己但是目的 IP 地址不是它自己時)纔會調用 LOCAL_IN hook,從而走到 filter 的 INPUT 鏈。但是很明顯,目前的 Neutron 中 qbr 只是 bridge,不承擔 router 任務。這篇文章 也認爲大多數經過 qbr 進出虛機的網絡包會被 FORWARD 鏈處理,還是有網絡包會被 INPUT 或者 OUTPUT 鏈處理。幸運的是,INPUT 和 OUTPUT 鏈的規則和 FORWARD 鏈的規則完全相同。這一塊還會繼續摸索,有大牛知曉還請不吝告知。

Neutron L2 Agent 承擔使用 iptables 維護鏈和規則的任務。它爲虛機的每塊網卡的 tap 設備建立 i(進)、o(出) 和 s(防IP欺騙)鏈和規則,來實現:

  • prepares, updates, removes firewall filters (準備、更新和刪除防火牆過濾器)
  • drops all packets by default (默認丟棄所有包)
  • prevents IP spoofing based on port’s mac address (compatible with allowed_address_pairs extension)(防 IP欺騙)
  • allows incoming DHCP and ICMPv6 RA (允許進入虛機的 DHCP 包和 ICMPV6 RA)
  • blocks outgoing DHCP (禁止出虛機的 DHCP 包) drops INVALID packets (丟棄無效狀態的包)
  • allows stateful, established connections (允許有狀態的並且已建立的連接,比如允許進來的 ICMP的時候,從外面 ping 虛機時虛機的響應包是可以返回的)
  • converts security group rules to iptables rules (IPv4, IPv6, TCP, UDP, ICMP, ICMPv6) (將用戶配置的規則轉化爲iptables 規則)
  • multiple TCP/UDP ports per iptables rule using multiport module
  • 支持 IPV4 和 IPV6

來看看 Neutron 爲了實現這些功能添加的 iptables 鏈:

-N neutron-filter-top
-N neutron-openvswi-FORWARD #neutorn 定義的 FORWARD 鏈
-N neutron-openvswi-INPUT   #Neutron 定義的 INPUT 鏈
-N neutron-openvswi-OUTPUT  #Neutron 定義的 OUTPUT 鏈 
-N neutron-openvswi-i6e3f2eda-3 #處理進入該虛機的網絡包
-N neutron-openvswi-local
-N neutron-openvswi-o6e3f2eda-3 #處理出該虛機的網絡包
-N neutron-openvswi-s6e3f2eda-3 #處理出該虛機的網絡包的防IP欺騙
-N neutron-openvswi-sg-chain    
-N neutron-openvswi-sg-fallback
-A INPUT -j neutron-openvswi-INPUT #將 INPUT 鏈轉到 neutron 的 INPUT 鏈
-A FORWARD -j neutron-filter-top
-A FORWARD -j neutron-openvswi-FORWARD #將 FORWARD 鏈轉到 neutorn 的 forward 鏈
-A OUTPUT -j neutron-filter-top
-A OUTPUT -j neutron-openvswi-OUTPUT   #將 OUTPUT 鏈轉到 neutron 的 output 鏈
-A neutron-filter-top -j neutron-openvswi-local

這些鏈之間的關係:
請添加圖片描述

3.3.2 當在 port 上不應用安全組時:只允許虛機訪問 DHCP 服務器和 DHCP 服務器給虛機的返回包,禁止其餘所有的網絡訪問。

先補充兩個iptabels 的知識點:

  • -j RETURN:退出當前CHIAN,如果當前CHIAN是別的CHAIN調用的子CHIAN,那麼返回到調用點下一條規則處開始執行,如果當前CHIAN不是子CHAIN,那麼就以默認策略執行。
  • -m state:匹配連接的狀態。Linux 網絡連接的狀態包括:
    在這裏插入圖片描述
-A neutron-openvswi-FORWARD -m physdev --physdev-out tap6e3f2eda-32 --physdev-is-bridged -j neutron-openvswi-sg-chain #處理進入虛機的數據包
-A neutron-openvswi-FORWARD -m physdev --physdev-in tap6e3f2eda-32 --physdev-is-bridged -j neutron-openvswi-sg-chain  #處理出虛機的數據包
-A neutron-openvswi-INPUT -m physdev --physdev-in tap6e3f2eda-32 --physdev-is-bridged -j neutron-openvswi-o6e3f2eda-3 #處理出虛機的數據包#處理進虛機的包
-A neutron-openvswi-i6e3f2eda-3 -m state --state INVALID -j DROP                               #丟棄無效連接
-A neutron-openvswi-i6e3f2eda-3 -m state --state RELATED,ESTABLISHED -j RETURN                 #允許已建立的連接  
-A neutron-openvswi-i6e3f2eda-3 -s 90.1.180.3/32 -p udp -m udp --sport 67 --dport 68 -j RETURN #允許 DHCP 服務器 91.1.180.3 的返回包
-A neutron-openvswi-i6e3f2eda-3 -s 91.1.180.2/32 -p udp -m udp --sport 67 --dport 68 -j RETURN #允許 DHCP 服務器 91.1.180.2 的返回包
-A neutron-openvswi-i6e3f2eda-3 -j neutron-openvswi-sg-fallback                                #其餘包交給 fallback 鏈處理     #處理出虛機的包
-A neutron-openvswi-o6e3f2eda-3 -p udp -m udp --sport 68 --dport 67 -j RETURN   #允許 DHCP 訪問
-A neutron-openvswi-o6e3f2eda-3 -j neutron-openvswi-s6e3f2eda-3                 #防止 IP 欺騙
-A neutron-openvswi-o6e3f2eda-3 -p udp -m udp --sport 67 --dport 68 -j DROP     #不允許對外提供 DHCP 服務
-A neutron-openvswi-o6e3f2eda-3 -m state --state INVALID -j DROP                #禁止無效連接
-A neutron-openvswi-o6e3f2eda-3 -m state --state RELATED,ESTABLISHED -j RETURN  #允許已建立的連接
-A neutron-openvswi-o6e3f2eda-3 -j neutron-openvswi-sg-fallback                 #其餘交給 fallback 鏈處理#防 IP 欺騙規則:防止該虛機被利用來做 IP 欺騙攻擊。
-A neutron-openvswi-s6e3f2eda-3 -s 91.1.180.14/32 -m mac --mac-source FA:16:3E:F3:1E:C0 -j RETURN #允許從虛機發出的MAC 和IP 同虛機的 MAC 和 IP 的包
-A neutron-openvswi-s6e3f2eda-3 -j DROP                                                           #禁止其餘包
-A neutron-openvswi-sg-chain -m physdev --physdev-out tap6e3f2eda-32 --physdev-is-bridged -j neutron-openvswi-i6e3f2eda-3 #處理進入虛機的包
-A neutron-openvswi-sg-chain -m physdev --physdev-in tap6e3f2eda-32 --physdev-is-bridged -j neutron-openvswi-o6e3f2eda-3  #處理出虛機的包
-A neutron-openvswi-sg-chain -j ACCEPT
-A neutron-openvswi-sg-fallback -j DROP #丟棄其它包

可見,此時,虛機的網絡訪問能力 = 基本網絡能力(DHCP訪問、允許已建立的連接、防 IP 欺騙)。也就是說虛機此時是無法網絡訪問和被網絡訪問,比如 ping,ssh 都無法連接。

3.3.3 當在 port 上應用安全組時:只允許用戶規則制定的網絡訪問。

(1)創建如下的安全組規則
請添加圖片描述
各條規則:

  • 允許 ping 別的機器
  • 允許別的機器 ping 它
  • 允許訪問別的機器 22 端口上的 tcp 服務 (ssh)
  • 允許別的機器訪問它的80 端口上的 tcp 服務 (http)
  • 允許訪問別的機器的 80 端口上的 tcp 服務 (http)
  • 允許15.5.0.0/16 網段的機器訪問它 110 端口上的 TCP 服務(pop3)
  • 允許 100.1.100.0/24 網段上的機器訪問它的 53 端口上的 UDP 服務 (DNS 服務器)

(2)將安全組綁定到 port

s1@controller:~$ neutron port-update --security-group  0aff643b-7b34-4384-b482-f37eccef5b90 6e3f2eda-3230-45e8-9be5-f382af5b83ea
Updated port: 6e3f2eda-3230-45e8-9be5-f382af5b83ea

(3)看看此時的 iptables filter 表的規則

-A neutron-openvswi-FORWARD -m physdev --physdev-out tap6e3f2eda-32 --physdev-is-bridged -j neutron-openvswi-sg-chain
-A neutron-openvswi-FORWARD -m physdev --physdev-in tap6e3f2eda-32 --physdev-is-bridged -j neutron-openvswi-sg-chain
-A neutron-openvswi-INPUT -m physdev --physdev-in tap6e3f2eda-32 --physdev-is-bridged -j neutron-openvswi-o6e3f2eda-3#適用於進入虛機的網絡包
-A neutron-openvswi-i6e3f2eda-3 -m state --state INVALID -j DROP
-A neutron-openvswi-i6e3f2eda-3 -m state --state RELATED,ESTABLISHED -j RETURN
-A neutron-openvswi-i6e3f2eda-3 -s 90.1.180.3/32 -p udp -m udp --sport 67 --dport 68 -j RETURN #DHCP server 1
-A neutron-openvswi-i6e3f2eda-3 -s 91.1.180.2/32 -p udp -m udp --sport 67 --dport 68 -j RETURN #DHCP Server 2
-A neutron-openvswi-i6e3f2eda-3 -s 15.5.0.0/16 -p tcp -m tcp --dport 110 -j RETURN             #第 6 條自定義rule
-A neutron-openvswi-i6e3f2eda-3 -p tcp -m tcp --dport 80 -j RETURN                             #第 4 條自定義 rule
-A neutron-openvswi-i6e3f2eda-3 -s 100.1.100.0/24 -p udp -m udp --dport 53 -j RETURN           #第 7 條自定義 rule
-A neutron-openvswi-i6e3f2eda-3 -p icmp -j RETURN                                              #第 2 條自定義 rule 
-A neutron-openvswi-i6e3f2eda-3 -j neutron-openvswi-sg-fallback                                #處理不滿足以上 rule 的包,默認是丟棄#處理出虛機的網絡包
-A neutron-openvswi-o6e3f2eda-3 -p udp -m udp --sport 68 --dport 67 -j RETURN                 #允許訪問 DHCP server
-A neutron-openvswi-o6e3f2eda-3 -j neutron-openvswi-s6e3f2eda-3                               #轉防 IP 欺騙鏈
-A neutron-openvswi-o6e3f2eda-3 -p udp -m udp --sport 67 --dport 68 -j DROP                   #禁止提供 DHCP 服務
-A neutron-openvswi-o6e3f2eda-3 -m state --state INVALID -j DROP                              #禁止無效連接
-A neutron-openvswi-o6e3f2eda-3 -m state --state RELATED,ESTABLISHED -j RETURN                #允許已建立連接
-A neutron-openvswi-o6e3f2eda-3 -p tcp -m tcp --dport 22 -j RETURN                            #自定義第 3 條規則
-A neutron-openvswi-o6e3f2eda-3 -p icmp -j RETURN                                             #自定義第 1 條規則 
-A neutron-openvswi-o6e3f2eda-3 -p tcp -m tcp --dport 80 -j RETURN                            #自定義第 5 條規則
-A neutron-openvswi-o6e3f2eda-3 -j neutron-openvswi-sg-fallback                               #處理不滿足以上規則的數據包#防 IP 欺騙規則
-A neutron-openvswi-s6e3f2eda-3 -s 91.1.180.14/32 -m mac --mac-source FA:16:3E:F3:1E:C0 -j RETURN
-A neutron-openvswi-s6e3f2eda-3 -j DROP#繼續鏈轉發
-A neutron-openvswi-sg-chain -m physdev --physdev-out tap6e3f2eda-32 --physdev-is-bridged -j neutron-openvswi-i6e3f2eda-3 #處理經過 qbr 進入虛機的網絡包
-A neutron-openvswi-sg-chain -m physdev --physdev-in tap6e3f2eda-32 --physdev-is-bridged -j neutron-openvswi-o6e3f2eda-3  #處理經過 qbr 橋出虛機的包
-A neutron-openvswi-sg-chain -j ACCEPT #接受不經過 qbr 橋的網絡包
-A neutron-openvswi-sg-fallback -j DROP #丟棄

結論:

此時,虛機的網絡訪問能力 = 基本網絡能力(DHCP訪問、允許已建立的連接、防 IP 欺騙)+ 用戶自定義的規則允許的網絡能力。

3.3.4 ipset

根據 官方文檔 描述,每當有新的port被創建後,L2 Agent 會增加新的 ipset set 到 iptable 鏈之中(在我的測試中,如果沒有後面的條件,ipset 是不會被創建的);如果該 port 所屬的安全組有與別的組共享的規則,那麼別的安全組的成員就會被加入到該組中。

neutron 的 security-group-rule-create CLI 支持以兩種形式指定允許(被)訪問的對象:

  • CIDR:待被匹配的網段,使用 remote-ip-prefix 參數指定
  • Remote security group id 或者 name:表示允許所有使用該 security group 的 port 的 IP,使用 remote-group-id 參數。
--remote-ip-prefix REMOTE_IP_PREFIX          CIDR to match on.
--remote-group-id REMOTE_GROUP               Remote security group name or ID to apply rule.

比如下面的命令指定 remote security group 爲 “default” security group:

s1@controller:~$ neutron security-group-rule-create  --direction ingress --ethertype IPv4 --protocol tcp --port-range-min 22 --port-range-max 22 --remote-group-id f5377a66-803d-481b-b4c3-a6631e8ab456 0aff643b-7b34-4384-b482-f37eccef5b90
Created a new security_group_rule:
+-------------------+--------------------------------------+
| Field             | Value                                |
+-------------------+--------------------------------------+
| direction         | ingress                              |
| ethertype         | IPv4                                 |
| id                | 3340b429-22dc-4176-b5c0-01a4f449e812 |
| port_range_max    | 22                                   |
| port_range_min    | 22                                   |
| protocol          | tcp                                  |
| remote_group_id   | f5377a66-803d-481b-b4c3-a6631e8ab456 |
| remote_ip_prefix  |                                      |
| security_group_id | 0aff643b-7b34-4384-b482-f37eccef5b90 |
| tenant_id         | 74c8ada23a3449f888d9e19b76d13aab     |
+-------------------+--------------------------------------+

這時候在 port 所在的計算節點上,有個新的 ipset set 被創建了。其命名規則爲 protocol + remote-group-id 的一部分:

root@compute1:/home/s1# ipset list
Name: IPv4f5377a66-803d-481b-b
Type: hash:ip
Revision: 2
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 16536
References: 1
Members:
91.1.180.5
81.1.180.13

其 members 是應用了該規則的所有 port 的 IP:

s1@controller:~$ neutron port-list -c security_groups -c id -c mac_address -c fixed_ips -c device_id | grep f5377a66-803d-481b-b4c3-a6631e8ab456
| [u'f5377a66-803d-481b-b4c3-a6631e8ab456'] | 402fe6b1-7670-4b6b-84a3-097beed64015 | fa:16:3e:45:6b:8b | {"subnet_id": "13888749-12b3-462e-9afe-c527bd0a297e", "ip_address": "91.1.180.5"}    |                                                                               |
| [u'f5377a66-803d-481b-b4c3-a6631e8ab456'] | 617d20fb-a635-4a03-95b1-bc15093fe32f | fa:16:3e:d8:29:9e | {"subnet_id": "4ec65731-35a5-4637-a59b-a9f2932099f1", "ip_address": "81.1.180.13"}   |

然後該 port 所在的計算節點上的 iptables 中增加了一項:

-A neutron-openvswi-i6e3f2eda-3 -p tcp -m tcp --dport 22 -m set --match-set IPv4f5377a66-803d-481b-b src -j RETURN

這意味着該虛機允許上述 ipset chain 的members 訪問。使用 “src” 是因爲那條 rule 的方向是 “ingress”。

如果不使用 ipset 的話(設置 enable_ipset = False),iptables 規則爲:

-A neutron-openvswi-i6e3f2eda-3 -s 91.1.180.5/32 -p tcp -m tcp --dport 22 -j RETURN
-A neutron-openvswi-i6e3f2eda-3 -s 81.1.180.13/32 -p tcp -m tcp --dport 22 -j RETURN

這就可以看出使用 ipset 的價值:

  • 提高 neutron 操作 iptables 的性能
  • 提高 linux 內核管理 iptables 規則的性能

3.4 Kilo 版本允許 port 不使用安全組 <更新於 2015/11/27>

出發點:Kilo 版本之前,安全組是必須應用於整個network的,包括防欺騙規則,而這個在保證安全的同時也限制了在虛機上運行某些網絡服務。

變化:增加 ML2PortSecurityExtensionDriver,應有該externsion dirver 後,可以指定某個 port 不使用安全組

neutron port-update  c080dbeb-491e-46e2-ab7e-192e7627d050 ---port-security-enabled=False

效果圖:(在作爲 router 的虛機 R1 和 R1 的端口上禁止安全組)
請添加圖片描述請添加圖片描述
詳情可參考 https://wiki.openstack.org/wiki/Neutron/ML2PortSecurityExtensionDriver

4. 示例分析

4.1 計算機 192.168.1.15 ping 虛機 91.1.180.14

root@compute1:/home/s1# ping 192.168.1.104
PING 192.168.1.104 (192.168.1.104) 56(84) bytes of data.
64 bytes from 192.168.1.104: icmp_seq=1 ttl=63 time=8.76 ms
64 bytes from 192.168.1.104: icmp_seq=2 ttl=63 time=2.41 ms
64 bytes from 192.168.1.104: icmp_seq=3 ttl=63 time=2.07 ms
64 bytes from 192.168.1.104: icmp_seq=4 ttl=63 time=1.23 ms

4.1.1 經過 qbr bridge 的網絡包

這種數據包來回共 4 次,seq 1 ~ 4。可以看到,達到 qbr 的網絡包已經經過了 DNAT。

09:29:28.718256 fa:16:3e:90:e5:50 > fa:16:3e:f3:1e:c0, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 63, id 49778, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.1.15 > 91.1.180.14: ICMP echo request, id 15849, seq 3, length 64
09:29:28.718670 fa:16:3e:f3:1e:c0 > fa:16:3e:90:e5:50, ethertype IPv4 (0x0800), length 98: (tos 0x0, ttl 64, id 53018, offset 0, flags [none], proto ICMP (1), length 84)
    91.1.180.14 > 192.168.1.15: ICMP echo reply, id 15849, seq 3, length 64

4.2.2 被 iptables filter 表各鏈處理的數據包的數目

(1)被 Forward 鏈處理的包進出各4個
請添加圖片描述
(2)被 neutron-openvswi-i6e3f2eda-3 處理的進入虛機的 4 個包:第一各包被匹配到符合要求的 icmp 協議類型,以後三個是匹配到連接狀態是 ESTABLISHED。
請添加圖片描述
(3)被 neutron-openvswi-o6e3f2eda-3 處理出虛機的 4 各網絡包:4 各皆通過 IP Spoofing 鏈的處理,然後被匹配到連接狀態是 ESTABLISHED (連接應該是第一次有 icmp 包進來時被建立好的)
在這裏插入圖片描述
(4)沒有經過 qbr 的網絡包被 INPUT 鏈處理
在這裏插入圖片描述

4.2 虛機 91.1.180.14 ping 192.168.1.115

4.2.1 同樣是有 8 個網絡包被 FORWARD 鏈處理

在這裏插入圖片描述

4.2.2 網絡包順序是出、 進、出、進、出、進、出、進,因此第一個包被匹配到 icmp,後面的包就是被匹配到 ESTABLISHED。

(1)4個從虛機出去的包
在這裏插入圖片描述
(2)4個進入到虛機的包
在這裏插入圖片描述

5. 代碼分析

注:以下材料引用自 這裏,與最新的實現可能有些出入,僅供參考。

(1)neutron server 和 ML2 Agent
在這裏插入圖片描述
(2)neutron server 在 DB 操作後通過 RPC 調用 ML2 Agent
在這裏插入圖片描述
(3)當 ML2 Agent 檢測到有新的虛機的 port 被 plug 到 OVS 後,它增加該 tap 設備的 iptables 鏈和規則
在這裏插入圖片描述
(4)當 ML2 Agent 監測到有虛機的 port 已經被從 OVS plug out 時,它刪除對應的 tap 設備的 iptables 鏈和規則
在這裏插入圖片描述
(5)當安全組有更新的時候,Neutron Server 通過 RPC 通知 ML2 Agent 去更新 iptables rules
在這裏插入圖片描述
(6)當有安全組成員(policy)變更的時候,Neutron Server 通過 RPC 通知 ML2 Agent 去更新 iptables rules
在這裏插入圖片描述

原文鏈接:https://www.cnblogs.com/sammyliu/p/4658746.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章