1. 程式人生 > >Neutron 理解 (8): Neutron 是如何實現虛機防火牆的 [How Neutron Implements Security Group]

Neutron 理解 (8): Neutron 是如何實現虛機防火牆的 [How Neutron Implements Security Group]

學習 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 地址發出回覆資料幀:

Ping Exchange: Normal Case(該例子中,node1 發往 node2 的幀的 IP 地址就是 node1 的地址,因此 node2 能夠通過  ARP 獲取 node1 的 MAC,並將回覆將發回到它)

如果源計算機的資料幀的源 IP 地址不是它自己的IP地址而是一個不存在的地址或者另外一臺機器的地址,目的計算機接受到資料幀後,它就會一直不停的發出 ARP 廣播,最終也無法獲取到MAC地址,或者傳送返回幀到另一臺的計算機。這就是所謂的(源) IP 地址欺騙。

Ping Exchange: Fake source of 192.168.1.66(該例子中,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“ 部分,其程式碼在(http://lxr.free-electrons.com/source/net/bridge/br_input.c#L226 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 上的網路包了。它使用如下引數:

引數 說明
-m physdev 匹配橋埠的進入和出去的裝置。這隻在核心版本 2.5.44 以上有效 (This module matches on the bridge port input and output devices enslaved to a bridge device. This module is a part of the infrastructure that enables a transparent bridging IP firewall and is only useful for kernel versions above version 2.5.44.)
--physdev-in [!] name Name of a bridge port via which a packet is received。(收到資料包的 bridge port 的名字,只對 INPUT, FORWARD and PREROUTING 鏈有效)。可以新增 ”+“ 來做頭部部分匹配。如果資料包不是從橋裝置接收到的,則匹配不成功。
--physdev-out [!] name                                                                       Name of a bridge port via which a packet is going to be sent.(資料包要發到的 bridge port name,只對 FORWARD, OUTPUT and POSTROUTING 有效)
[!] --physdev-is-in Matches if the packet has entered through a bridge interface (在資料包是通過一個橋interface進入的時候會匹配成功)
[!] --physdev-is-out Matches if the packet will leave through a bridge interface. (在資料包將要通過一個橋的interface出去時匹配成功)
[!] --physdev-is-bridged Matches if the packet is being bridged and therefore is not being routed (在資料包是正被橋接的而不是正被路由時匹配成功。它只對 FORWARD and POSTROUTING 有效。)

舉例(來源):

在一臺 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。該命令:

  • test_policy:自定義set;
  • ipmap:自定義set的型別,表示是 IP 地址; bitmap:ip,mac 表示是 IP 或者 MAC 地址。
  • network 192.168.100.1/24:代表一個網段

(4) 自定義 set 建立好了後就需要在上面新增一些IP了,如:

  • ipset -A test_policy 192.168.100.1
  • ipset -A test_policy 192.168.100.2
  • ipset -A test_policy 192.168.100.3
  • ipset -A test_policy 192.168.100.4

(5)這個時候你ipset -nL就會看到該 set 以及它的 members:

[email protected]:/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。其中:

  • 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 來控制進出虛機或者租戶網路的網路包,但是在不同的位置使用不同的方法來實現不同的目的。三者之間的比較如下:
Nova Security Group Neutron Security Group Neutron FWaas 
作用 控制進入虛機的網路包 控制進出虛機的網路包 控制進出租戶網路的網路包。對不經過 Virutal Router 的網路包不起作用。
防火牆節點 Nova 計算節點 Nova 計算節點(L2 Agent 節點) L3 Agent 節點上該 firewall 所在的租戶的所有 router 的 namespace 中
IPV6 支援 支援。通過配置項 use_ipv6 來指定是否使用 IPV6,預設值為 false。 判斷 /proc/sys/net/ipv6/conf/default/disable_ipv6 檔案的內容。如果是 ”0“,表示支援 ipv6,否則不支援。如果支援的話,則同時往 iptables 和 ip6tables 中新增鏈和規則。 支援,同時往 iptables 和 ip6tables 中新增鏈和規則,但是似乎沒有判斷系統是否支援 IPV6.
控制粒度 虛機 Neutron port 租戶的所有 virtual router 的所有 Interface
控制實施者 Nova 計算節點的 IP 棧 Nova 計算節點的 qbr 橋 router 的 namespace 的 IP 棧
控制的網路流量方向 ingress only (進入虛機的網路包) ingress 和 egress (進出虛機的網路包) ingress 和 egress (進出租戶網路的網路包)
匹配的資料項 協議、源 IP 網段、目的埠號 協議、埠、網段、方向 協議、源埠、目的埠、源 IP 網段、目的 IP、方向
匹配的結果行為 允許(allow) 允許(allow) 允許(allow)和拒絕(deny)
使用 啟動虛機時指定安全組,不指定的話使用預設安全組。虛機啟動後,對所使用的安全組的變更會實時應用到虛機。可以向虛機新增和刪除安全組。 動態(隨時,啟動虛機時和啟動後)使用 neutron port-update 命令更新指定 port 的安全組。 動態(隨時)應用到租戶的所有虛擬路由器。
沒有顯式配置安全組時的預設行為 使用預設安全組(Default Security Group  ),它允許使用同一個安全組的虛機訪問該虛機  禁止該機器的網路訪問,除了允許它訪問 DHCP 服務  沒有預設防火牆,防火牆沒有預設規則。配置了 firewall 但是沒新增規則的話,禁止所有網路進出資料網路。
允許的數目 多個,Security Group 數目(預設10)和 Security Group Rules 數目(預設100)受租戶的 quota 限制 最多一個,不允許多個。
CLI

#列表,增加,刪除 虛機的安全組

add-secgroup: Add a Security Group to a server              
list-secgroup: List Security Group(s) of a server.             
remove-secgroup: Remove a Security Group from a server.          

#操作安全組 
secgroup-add-group-rule   
secgroup-add-rule         
secgroup-create           
secgroup-delete           
secgroup-delete-group-rule
secgroup-delete-rule      
secgroup-list             
secgroup-list-rules       
secgroup-update           

#啟動虛機時指定安全組

nova boot --flavor FLAVOR_ID --image IMAGE_ID --security-groups SEC_GROUP

#操作安全組

neutron security-group-create 
neutron security-group-list
neutron security-group-rule-create 
neutron security-group-rule-list
neutron security-group-rule-delete 
neutron security-group-delete

#建立 port 時指定安全組:
neutron port-create --security-group SECURITY_GROUP_ID1 --security-group SECURITY_GROUP_ID2 NETWORK_ID

#顯示 port 的安全組
neutron port-list -c security_groups -c id -c mac_address -c fixed_ips -c device_id

#刪除 port 的安全組
neutron port-update --no-security-groups PORT_ID

#使用帶安全組的 port 啟動虛機
nova boot vm1 --flavor 6 --nic port-id=

#防火牆操作

firewall-create
firewall-delete
firewall-list
firewall-show
firewall-update


#防火牆策略操作
firewall-policy-create
firewall-policy-delete
firewall-policy-insert-rule
firewall-policy-list
firewall-policy-remove-rule
firewall-policy-show
firewall-policy-update


#防火牆規則操作
firewall-rule-create
firewall-rule-delete
firewall-rule-list
firewall-rule-show
firewall-rule-update

配置 見下文  
底層實現 見下文

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 配置

節點 配置檔案 配置項 說明
controller  /etc/nova/nova.conf security_group_api = neutron  使得 nova secgroup* 命令使用的是 neutron 安全組的 API
/etc/neutron/plugins/ml2/ml2_conf.ini enable_security_group = True
firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver
啟用 Neutron 安全組並指定驅動
nova-compute  /etc/nova/nova.conf firewall_driver = nova.virt.firewall.NoopFirewallDriver 禁用 nova 安全組
/etc/neutron/plugins/ml2/ml2_conf.ini enable_security_group = True
enable_ipset = True
firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver
啟用 Neutron 安全組並指定驅動
network /etc/neutron/plugins/ml2/ml2_conf.ini enable_security_group = True
enable_ipset = True
firewall_driver = neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver
啟用 Neutron 安全組並指定驅動

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 示例

列表 安全組:

[email protected]:~$ 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: [email protected]:~$ 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  [email protected]:~$ 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 的安全組: [email protected]:~$ neutron port-update --no-security-groups 29eaea66-6614-47e3-b251-0104ff9f12e2
Updated port: 29eaea66-6614-47e3-b251-0104ff9f12e2 刪除後檢視: [email protected]:~$ 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 的安全組: [email protected]:~$ neutron port-update --security-group 0aff643b-7b34-4384-b482-f37eccef5b90 29eaea66-6614-47e3-b251-0104ff9f12e2                Updated port: 29eaea66-6614-47e3-b251-0104ff9f12e2

設定後檢視 [email protected]:~$ 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 網路連線的狀態包括:
狀態 說明
NEW NEW 說明這個包是我們看到的第一個包。意思就是,這是 conntrack 模組看到的某個連線第一個包,它即將被匹配了。比如,我們看到一個SYN 包,是我們所留意的連線的第一個包,就要匹配它。第一個包也可能不是SYN包,但它仍會被認為是NEW狀態。這樣做有時會導致一些問題,但對某些情況是有非常大的幫助的。例如,在我們想恢復某條從其他的防火牆丟失的連線時,或者某個連線已經超時,但實際上並未關閉時。
ESTABLISHED                                                 ESTABLISHED 已經注意到兩個方向上的資料傳輸,而且會繼續匹配這個連線的包。處於 ESTABLISHED 狀態的連線是非常容易理解的。只要傳送並接到應答,連線就是ESTABLISHED的了。一個連線要從NEW變為ESTABLISHED,只需要接到應答包即可,不管這個包是發往防火牆的,還是要由防火牆轉發的。ICMP的錯誤和重定向等資訊包也被看作是ESTABLISHED,只要它們是我們所發出的資訊的應答。
RELATED RELATED 是個比較麻煩的狀態。當一個連線和某個已處於 ESTABLISHED 狀態的連線有關係時,就被認為是 RELATED 的了。換句話說,一個連線要想是 RELATED的,首先要有一個ESTABLISHED的連線。這個ESTABLISHED連線再產生一個主連線之外的連線,這個新的連線就是 RELATED的了,當然前提是conntrack模組要能理解RELATED。ftp是個很好的例子,FTP-data 連線就是和 FTP-control 有 RELATED 的。還有其他的例子,比如,通過IRC的DCC連線。有了這個狀態,ICMP應答、FTP傳輸、DCC 等才能穿過防火牆正常工作。注意,大部分還有一些UDP協議都依賴這個機制。這些協議是很複雜的,它們把連線資訊放在資料包裡,並且要求這些資訊能被正確 理解。
INVALID INVALID說明資料包不能被識別屬於哪個連線或沒有任何狀態。有幾個原因可以產生這種情況,比如,記憶體溢位,收到不知屬於哪個連線的ICMP 錯誤資訊。一般地,我們DROP這個狀態的任何東西。
-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)建立如下的安全組規則

各條規則:
  1. 允許 ping 別的機器
  2. 允許別的機器 ping 它
  3. 允許訪問別的機器 22 埠上的 tcp 服務 (ssh)
  4. 允許 別的機器訪問它的80 埠上的 tcp 服務 (http)
  5. 允許訪問別的機器的 80 埠上的 tcp 服務 (http)
  6. 允許 15.5.0.0/16 網段的機器訪問它 110 埠上的 TCP 服務(pop3)
  7. 允許 100.1.100.0/24 網段上的機器訪問它的 53 埠上的 UDP 服務 (DNS 伺服器)
(2)將安全組繫結到 port
[email protected]:~$ 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:

[email protected]:~$ 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 的一部分:

[email protected]:/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:

[email protected]:~$ neutron port-list -c security_groups -c id -c mac_address -c fixed_ips -c device_id | grep f5377a66-803d-481b-b4c3-