深入淺出解析 OpenStack 安全組實現(xiàn)原理
1、iptables簡介
1.1 iptables概述
在介紹OpenStack安全組前先簡單介紹下iptables,其實iptables只是一個用戶空間的程序,真正干活的其實是Linux內(nèi)核netfilter,通過iptables創(chuàng)建新規(guī)則,其實就是在netfilter中插入一個hook,從而實現(xiàn)修改數(shù)據(jù)包、控制數(shù)據(jù)包流向等,對iptables使用方法不熟悉的可以參考圖文并茂理解iptables[1].
簡單地說,iptables就是通過一系列規(guī)則條件匹配執(zhí)行指定的動作,因此一條規(guī)則就是由條件+動作構(gòu)成,條件比如源IP地址、四層協(xié)議、端口等,動作如拒絕、通過、丟棄、修改包等,動作通常通過-j參數(shù)指定。
比如拒絕192.168.1.2訪問目標(biāo)22端口,只需要添加如下iptables規(guī)則:
如上:
- -t指定表(table),如果把所有的規(guī)則混放在一起肯定會特別亂,因此iptables根據(jù)功能劃分為不同的表,過濾包的放在filter表,做NAT的放nat表等,還有raw表、mangle表、security表,共5個表。如果不指定該參數(shù),默認(rèn)會選中filter表。
- -I表示insert操作,在最前面插入這條規(guī)則,相對應(yīng)的還有-A參數(shù),表示從末尾追加規(guī)則,-I、-A還可以在后面指定索引位置,將規(guī)則插入到指定的位置。
- INPUT表示鏈名稱,鏈可以看做是一個鏈表,鏈表元素為規(guī)則。iptables一共可操縱5條鏈,分別為PREROUTING、INPUT、FORWARD、OUTPUT、POSTROUTING。需要注意的是,所有的表都是共享這5條鏈的,當(dāng)然并不是所有的表都同時需要這5條鏈,比如filter表就沒有PREROUTING、POSTROUTING。如果多個table都在如上鏈上插入了規(guī)則,則根據(jù)raw -> mangle -> nat -> filter的順序執(zhí)行。
- -s、-p、--dport都是條件,多個條件是與的關(guān)系,即只有滿足指定的所有條件才能匹配該規(guī)則,如上-s指定了源地址IP為192.168.1.2,-p指定了協(xié)議為TCP,--dport指定了端口22,即只有源地址訪問目標(biāo)的22 TCP端口才能匹配這條規(guī)則。
- -j指定了行為,當(dāng)然官方的叫法是目標(biāo)(target),這里DROP表示丟棄包。
1.2 iptables匹配條件
除了以上的-s、-p、--dport等參數(shù)作為匹配條件外,iptables還支持如-d匹配目標(biāo)IP地址,-i、-o分別指定從哪個網(wǎng)卡進入的以及從哪個網(wǎng)卡出去的。當(dāng)然這些匹配條件還不夠,甚至都不支持匹配MAC地址。iptables為了滿足不同的需求,通過擴展模塊支持更多的匹配條件,主要分為如下兩類:
- 功能加強型:比如前面的--dport參數(shù)只能匹配單個port或者連續(xù)的port,如果需要匹配多個不連續(xù)的port,則不得不通過添加多條規(guī)則實現(xiàn)。mulport擴展模塊允許同時指定多個port,通過逗號分隔。再比如ip-range模塊,支持指定ip地址段。
- 新功能:比如mac模塊支持匹配源MAC地址。time模塊支持通過時間段作為匹配條件,比如實現(xiàn)每天0點到8點不允許外部SSH。
不同的擴展模塊支持不同的參數(shù),比如mac模塊,支持--mac-source參數(shù)。
使用擴展模塊必須通過-m參數(shù)加載,之前我一直以為-m是--module的縮寫,看iptables的man手冊才發(fā)現(xiàn)其實是--match的縮寫,不過我們只需要知道是加載擴展模塊的功能就可以了。
比如我們不允許MAC地址為FA:16:3E:A0:59:BA通過,通過如下規(guī)則配置:
iptables的擴展模塊非常多,具體可以通過man iptables-extensions命令查看,不過OpenStack安全組用到的并不多:
- comment:給規(guī)則添加注釋。
- tcp/udp/icmp:沒錯,這些也屬于擴展模塊,iptables基本模塊中甚至連指定端口的功能都沒有。
- set:匹配ipset,當(dāng)ip在ipset集合中即滿足條件。
- mac:前面說了,支持匹配MAC地址。
- state: 這個模塊非常有用,舉個簡單的例子,假設(shè)服務(wù)器A(192.168.0.1)配置的iptables規(guī)則為入訪全不通,即INPUT鏈全DROP,出訪全通,即OUTPUT鏈全ACCEPT。另外一臺服務(wù)器B(192.168.0.2)和A在同一個二層網(wǎng)絡(luò),則顯然B ping不通A,問題是A能ping通B嗎?有人肯定會說,A既然出訪全是通的,那肯定能ping通B了。事實上,A根本ping不通B,因為A的包有去無回,即A的ICMP包確實能到B,但B的回包卻被A的INPUT DROP了,因此A根本接收不到reply包。那怎么解決呢?把B加到A的白名單列表中顯然破壞了我們原有的初衷。通過state模塊可以完美解決這個問題,指定state為ESTABLISHED能夠匹配已經(jīng)建立連接的包,注意這里的已建立連接并不是說TCP連接,而是更廣泛的連接含義,比如udp、icmp,簡單理解就是匹配回包。因此解決如上問題只需要添加-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT規(guī)則即可。
- physdev: 這個模塊相對內(nèi)置的-i、-o參數(shù)功能更強大。假如我們創(chuàng)建了一個linux bridge br0,br0上掛了很多虛擬網(wǎng)卡tap設(shè)備。我們通過-i指定br0則不管從哪個虛擬網(wǎng)卡進來的都會匹配,做不了精確匹配到底是從哪個虛擬網(wǎng)卡進來的。而physdev模塊則非常強大,通過physdev-in參數(shù)指定從哪個接口進來的,通過--physdev-out參數(shù)指定從哪個接口出去的。
1.3 iptables執(zhí)行動作
前面提到iptables通過-j指定執(zhí)行的動作(target),iptables常見的target如下:
- ACCEPT:接收包,直接放行,不需要在匹配該鏈上的其他規(guī)則,注意是該鏈,其他鏈的還是需要匹配的,即只是說明通了一關(guān),后面幾關(guān)能不能通過還不好說。
- DROP:直接丟棄包,包都丟了,當(dāng)然也不需要在匹配其他任何規(guī)則了。
- REJECT:拒絕包。這個和DROP有什么區(qū)別呢?DROP是直接丟棄包,不做任何響應(yīng),客戶端會一直在傻傻地等直到超時。而REJECT會響應(yīng)拒絕消息,客戶端能收到拒絕包并作出反應(yīng),不需要一直盲等。
- LOG:僅僅記錄下日志。
當(dāng)然還有實現(xiàn)NAT的SNAT、MASQUERADE、DNAT,因為安全組實現(xiàn)涉及不到,因此不做詳細介紹,另外還有RETURN以及指向另一個鏈的動作,等后面介紹了子鏈再討論。
動作通常都是短路的,也就是說一旦匹配規(guī)則并執(zhí)行動作,就不會繼續(xù)往后去匹配該鏈的其他規(guī)則了,當(dāng)然這并不是絕對的,比如LOG動作就是例外,執(zhí)行該動作后會繼續(xù)匹配下一條規(guī)則。
1.4 iptables鏈
前面提到iptables一共有5條鏈,并且鏈可以認(rèn)為是一個單向鏈表,問題來了,當(dāng)接收到一個新包,到底是如何匹配規(guī)則的。這里我直接引用圖文并茂理解iptables的圖[1]:
(1) 數(shù)據(jù)包首先到達PREROUTING鏈,然后按照raw、mangle、nat的順序匹配執(zhí)行定義在PREROUTING的規(guī)則。
(2) 接下來經(jīng)過路由判斷,如果包是發(fā)給自己的則流向INPUT鏈,然后由INPUT鏈發(fā)給用戶空間進程處理。如果不是發(fā)給自己的包,則流向FORWARD表,同樣按照raw -> mangle -> nat -> filter表依次匹配執(zhí)行鏈上的規(guī)則。
(3) 同理,ONPUT鏈、POSTROUTING鏈,包流向方向,直接看圖,非常清晰,這里不再贅述。
前面提到每條鏈上都可以插入規(guī)則,需要注意的是這些規(guī)則是有順序的,iptables每次匹配時都是從第一條規(guī)則開始匹配,依次匹配下一條,一旦匹配其中一條規(guī)則,則執(zhí)行對應(yīng)的動作。
肯定有人會疑問,如果這條鏈上的規(guī)則都不匹配該怎么辦,答案是取決于該鏈的默認(rèn)策略(policy)。如果該策略是DROP,則最后沒有匹配的包都將丟棄,即該鏈時白名單列表。如果默認(rèn)策略是ACCEPT,則最后沒有匹配的包都會通過,即該鏈時黑名單列表。當(dāng)然通常policy都設(shè)置為ACCEPT,因為配置為DROP太危險了,比如清空規(guī)則立馬就相當(dāng)于全不通了,如果你通過SSH連接的服務(wù)器,則立即中斷連接了,不得不通過vnc或者帶外console連接重置,所以不建議修改policy。
通過如下命令查看filter表各個鏈的默認(rèn)策略:
如果一條鏈規(guī)則特別多且復(fù)雜,管理起來非常麻煩,因此很有必要對鏈根據(jù)功能分組。iptables通過自定義鏈實現(xiàn)。用戶可以通過iptables -N name創(chuàng)建一個新鏈,然后和內(nèi)置鏈一樣可以往新鏈中添加規(guī)則。但是需要注意的是,自定義鏈不能獨立存在,必須掛在內(nèi)置5條鏈下面,即必須是內(nèi)置鏈的子鏈。
前面1.3節(jié)提了下-j可以指定一條新鏈,這里的新鏈即子鏈,即iptables是通過-j把子鏈掛到某個規(guī)則下面。比如創(chuàng)建一個允許SSH訪問的白名單列表,可以創(chuàng)建一個新的子鏈,SSH相關(guān)的策略都放在這個新鏈中:
以上第二條命令表示將所有訪問本機端口22的包都放到SSH_Access_List這條子鏈上處理,然后這條子鏈上添加了許多白名單規(guī)則,由于進到這個子鏈的一定是目標(biāo)22端口的,因此規(guī)則無需要在指定--dport參數(shù),最后一個DROP表示不在白名單列表中的包直接丟掉。
需要注意的是白名單規(guī)則中的動作不是ACCEPT而是RETURN,這兩者有什么區(qū)別呢?ACCEPT表示允許包直接通過INPUT,不需要再匹配INPUT的其他規(guī)則。而RETURN則表示只是不需要再匹配該子鏈下的后面規(guī)則,但需要返回到該子鏈的母鏈的規(guī)則或者子鏈繼續(xù)匹配,能不能通過INPUT關(guān)卡取決于后面的規(guī)則。
另外需要注意的是,前面提到內(nèi)置的5條鏈可以配置policy,當(dāng)所有規(guī)則都不匹配時,使用policy對包進行處置。但是,自定義鏈?zhǔn)遣恢С謕olicy的,更確切的說,不支持設(shè)置policy,因為自定義鏈的policy只能是RETURN,即如果子鏈的規(guī)則都不匹配,則一定會返回到母鏈中繼續(xù)匹配。
1.5 iptables總結(jié)
本小節(jié)簡單介紹了iptables的功能和用法,總結(jié)如下:
1、iptables通過規(guī)則匹配決定包的去向,規(guī)則由匹配條件+動作構(gòu)成,規(guī)則通過-I、-A插入。
2、五鏈五表,五鏈為PREROUTING、INPUT、FORWARD、OUTPUT、POSTROUTING,五表為raw、mangle、nat、filter、security。鏈、表、規(guī)則都是有順序的。
3、當(dāng)鏈中的所有規(guī)則都不匹配時,iptables會根據(jù)鏈設(shè)置的默認(rèn)策略policy處理包,通過policy設(shè)置為ACCEPT,不建議配置為DROP。
4、可以創(chuàng)建子鏈掛在內(nèi)置鏈中,子鏈的policy為RETURN,不支持配置。
5、匹配條件包括基本匹配條件以及擴展模塊提供的擴展匹配條件,擴展匹配條件通過-m參數(shù)加載,需要記住的擴展模塊為comment、tcp、udp、icmp、mac、state、physdev、set。
6、常見的iptables動作(target)為ACCEPT、DROP、RETURN、LOG以及跳轉(zhuǎn)到子鏈。
2、OpenStack安全組簡介
2.1 Neutron安全組 VS Nova安全組
OpenStack安全組最開始是通過Nova管理及配置的,引入Neutron后,新OpenStack安全組則是通過Neutron管理,并且關(guān)聯(lián)的對象也不是虛擬機,而是port。我們在頁面上把虛擬機加到某個安全組,其實是把虛擬機的port關(guān)聯(lián)到安全組中。
由于歷史的原因,可能還有些版本的Nova依然保留著對安全組規(guī)則的操作API,不過不建議使用,建議通過Neutron進行安全組規(guī)則管理。
2.2 security group VS firewall
很多剛開始接觸OpenStack的用戶分不清楚安全組(security group)和防火墻(firewall)的區(qū)別,因為二者都是做網(wǎng)絡(luò)訪問控制的,并且社區(qū)都是基于iptables實現(xiàn)的。其實二者的區(qū)別還是比較大的:
- security group主要是做主機防護的,換句話說安全組是和虛擬機的port相關(guān)聯(lián),安全組是針對每一個port做網(wǎng)絡(luò)訪問控制,所以它更像是一個主機防火墻。而firewall是針對一個VPC網(wǎng)絡(luò)的,它針對的是整個VPC的網(wǎng)絡(luò)控制,通常是在路由做策略。因此security group在計算節(jié)點的tap設(shè)備上做,而firewall在網(wǎng)絡(luò)節(jié)點的router上做。
- 相對于傳統(tǒng)網(wǎng)絡(luò)模型,security group其實就是類似于操作系統(tǒng)內(nèi)部自己配置的防火墻,而firewall則是旁掛在路由器用于控制整個局域網(wǎng)網(wǎng)絡(luò)流量的防火墻。
- security group定義的是允許通過的規(guī)則集合,即規(guī)則的動作就是ACCEPT。換句話說定義的是白名單規(guī)則,因此如果虛擬機關(guān)聯(lián)的是一個空規(guī)則安全組,則虛擬機既出不去也進不來。并且由于都是白名單規(guī)則,因此安全組規(guī)則順序是無所謂的,而且一個虛擬機port可以同時關(guān)聯(lián)多個安全組,此時相當(dāng)于規(guī)則集合的并集。而firewall規(guī)則是有動作的(allow,deny,reject),由于規(guī)則既可以是ACCEPT,也可以是DROP,因此先后順序則非常重要,一個包的命運,不僅取決于規(guī)則,還取決于規(guī)則的優(yōu)先級順序。
- 前面說到security group針對的是虛擬機port,因為虛擬機的IP是已知條件,定義規(guī)則時不需要指定虛擬機IP,比如定義入訪規(guī)則時,只需要定義源IP、目標(biāo)端口、協(xié)議,不需要定義目標(biāo)IP。而防火墻針對的是整個二層網(wǎng)絡(luò),一個二層網(wǎng)絡(luò)肯定會有很多虛擬機,因此規(guī)則需要同時定義源IP、源端口、目標(biāo)IP、目標(biāo)端口、協(xié)議。之前有人問我一個問題,多個虛擬機關(guān)聯(lián)到了一個安全組,想針對這幾個虛擬機做網(wǎng)絡(luò)訪問控制,源IP是192.168.4.5,但我只想開通到兩個虛擬機的80端口訪問,問我怎么做?我說實現(xiàn)不了,因為關(guān)聯(lián)在同一個安全組的虛擬機網(wǎng)絡(luò)訪問策略是必須是一樣的,你沒法指定目標(biāo)IP,如果虛擬機有不同的訪問需求,只能通過關(guān)聯(lián)不同的安全組實現(xiàn)。
- security group通常用于實現(xiàn)東西向流量控制實現(xiàn)微分段策略,而firewall則通常用于實現(xiàn)南北向流量控制。
2.3 安全組用法介紹
前面介紹了安全組,安全組其實就是一個集合,需要把安全組規(guī)則放到這個集合才有意義。
Neutron通過security-group-create子命令創(chuàng)建安全組,參數(shù)只有一個name,即安全組名稱:
不過Neutron創(chuàng)建的新安全組并不是一個空規(guī)則安全組,而是會自動添加兩條默認(rèn)規(guī)則:
即禁止所有的流量訪問,允許所有的流量出去。
創(chuàng)建了安全組后,就可以往安全組里面加規(guī)則了。Neutron通過security-group-rule-create子命令創(chuàng)建,涉及的參數(shù)如下:
- --direction: 該規(guī)則是出訪(egress)還是入訪(ingress)。
- --ethertype: 以太網(wǎng)類型,ipv4或者ipv6。
- --protocol: 協(xié)議類型,tcp/udp/icmp等。不指定該參數(shù)則表示任意協(xié)議。
- --port-range-min、--port-range-max端口范圍,如果只有一個端口,則兩個參數(shù)填一樣即可,端口范圍為1~65535。
- --remote-ip-prefix,如果是入訪則指的是源IP地址段,如果是出訪則指的是目標(biāo)IP段,通過CIDR格式定義,如果只指定一個IP,通過x.x.x.x/32指定,如果是任意IP,則通過0.0.0.0/0指定。
- --remote-group-id: 除了通過ip段指定規(guī)則,OpenStack還支持通過安全組作為匹配條件,比如允許關(guān)聯(lián)了xyz安全組的所有虛擬機訪問22端口。
創(chuàng)建一條安全組規(guī)則,只允許192.168.4.5訪問虛擬機SSH 22端口:
需要注意的是創(chuàng)建安全組和安全組規(guī)則只是一個邏輯操作,并不會創(chuàng)建任何iptables規(guī)則,只有當(dāng)安全組被關(guān)聯(lián)到port時才會真正創(chuàng)建對應(yīng)的iptables規(guī)則。
關(guān)聯(lián)安全組通過Neutron的port-update命令,比如要把虛擬機uuid為38147993-08f3-4798-a9ab-380805776a40添加到該安全組:
安全組命令操作參數(shù)較多,相對復(fù)雜,可以通過Dashboard圖形界面操作,如圖:
具體操作這里不多介紹。
3、安全組實現(xiàn)原理分析
3.1 虛擬機網(wǎng)絡(luò)流向路徑
Linux網(wǎng)絡(luò)虛擬化支持linux bridge以及openvswitch(簡稱OVS),OpenStack Neutron ml2驅(qū)動二者都支持,目前大多數(shù)使用的是OVS。
不過早期的iptables不支持OVS bridge以及port,因此為了實現(xiàn)安全組,虛擬機的tap設(shè)備并不是直接連接到OVS bridge上,而是中間加了一個Linux bridge,通過veth pair連接Linux bridge以及OVS bridege,這樣就可以在Linux bridge上添加iptables規(guī)則實現(xiàn)安全組功能了。
目前大多數(shù)的OpenStack環(huán)境還遵循如上規(guī)則,簡化的虛擬機流量路徑如下:
其中X、Y、Z為虛擬機port UUID前11位。
3.2 安全組規(guī)則掛在iptables哪條鏈?
根據(jù)前面的基礎(chǔ),不難猜出安全組的iptables規(guī)則肯定是在filter表實現(xiàn)的,filter表只涉及INPUT、FORWARD、OUTPUT三條鏈,iptables規(guī)則流向圖可以簡化為:
做過主機防火墻的可能第一直覺會認(rèn)為安全組規(guī)則會掛在INPUT以及OUTPUT鏈上,但根據(jù)上面的流程圖,如果包不是發(fā)給自己的,根本到不了INPUT以及OUTPUT,因此顯然在INPUT、OUTPUT根本實現(xiàn)不了安全組規(guī)則,因此安全組的iptables規(guī)則肯定是在FORWARD鏈上實現(xiàn)的,也就是說計算節(jié)點不處理虛擬機的包(發(fā)給自己的包除外),只負(fù)責(zé)轉(zhuǎn)發(fā)包。
3.3 安全組規(guī)則定義
為了便于后面的測試,我提前創(chuàng)建了一臺虛擬機int32bit-server-1,IP為192.168.100.10/24,port UUID為3b90700f-1b33-4495-9d64-b41d7dceebd5,并添加到了之前創(chuàng)建的int32bit-test-secgroup-1安全組。
我們先導(dǎo)出本計算節(jié)點的所有tap設(shè)備對應(yīng)Neutron的port,該腳本在github int32bit/OpenStack_Scripts可以下載:
根據(jù)前面的分析,虛擬機安全組是定義在filter表的FORWARD鏈上的,我們查看該鏈的規(guī)則:
FORWARD鏈先跳到neutron-filter-top子鏈上,neutron-filter-top鏈會又跳到neutron-openvswi-local,而neutron-openvswi-local鏈?zhǔn)强真?,因此會返回到母鏈FORWARD上,因此這里第一條規(guī)則其實沒啥用。
返回到FORWARD鏈后繼續(xù)匹配第2條規(guī)則,跳轉(zhuǎn)到了neutron-openvswi-FORWARD,我們查看該鏈的規(guī)則:
該鏈上一共有4條規(guī)則,第1、2臺規(guī)則對應(yīng)的tap設(shè)備分別為dhcp以及router_interface端口,即允許DHCP以及網(wǎng)關(guān)的port通過。
而tap3b90700f-1b顯然是虛擬機port對應(yīng)的tap設(shè)備(名稱為tap+portUUID前11位),第3、4規(guī)則表明無論是從這個tap設(shè)備進的還是出的包都進入子鏈neutron-openvswi-sg-chain處理。
我們繼續(xù)查看neutron-openvswi-sg-chain查看鏈:
從規(guī)則我們可以看出:
- --physdev-out表示從tap3b90700f-1b出來發(fā)往虛擬機的包,通過子鏈neutron-openvswi-i3b90700f-1處理,即虛擬機入訪流量。
- --physdev-in表示從虛擬機出來進入tap3b90700f-1b的包,通過子鏈neutron-openvswi-o3b90700f-1處理,即虛擬機出訪流量。
顯然neutron-openvswi-i3b90700f-1和neutron-openvswi-o3b90700f-1分別對應(yīng)安全組的入訪規(guī)則和出訪規(guī)則,即虛擬機的入訪規(guī)則鏈為neutron-openvswi-i + port前綴,虛擬機的出訪規(guī)則鏈為neutron-openvswi-i + port前綴。
3.4 安全組入訪規(guī)則
由3.3我們了解到,安全組入訪規(guī)則鏈為neutron-openvswi-i3b90700f-1,我們查看該鏈規(guī)則:
一共有6條規(guī)則:
- 第1條規(guī)則我們在前面已經(jīng)介紹過,應(yīng)該很熟悉了,主要用于放行回包。
- 第2、3條規(guī)則主要用于放行dhcp廣播包。
- 第4條即我們前面添加的安全組規(guī)則。
- 第5條規(guī)則丟棄無用包。
- 第6條用來處理所有規(guī)則都不匹配的包,跳轉(zhuǎn)到neutron-openvswi-sg-fallback鏈,而該鏈其實只有一條規(guī)則,即DROP ALL。因此不匹配安全組規(guī)則的包都會直接丟棄。
安全組入訪規(guī)則中第1、2、3、5、6都是固定的,當(dāng)有新的安全組策略時就往第4條規(guī)則后面追加。
3.5 安全組出訪規(guī)則
由3.3我們了解到,安全組入訪規(guī)則鏈為neutron-openvswi-o3b90700f-1,我們查看該鏈規(guī)則:
一共有8條規(guī)則:
- 第1、3條規(guī)則用于放行虛擬機DHCP client廣播包。
- 第2條規(guī)則,放到第4章再介紹。
- 第4條規(guī)則用于阻止DHCP欺騙,避免用戶在虛擬機內(nèi)部自己啟一個DHCP Server影響Neutron的DHCP Server。
- 第5條規(guī)則不再解釋。
- 第6條規(guī)則是我們的安全組規(guī)則,因為我們的安全組出訪是ANY,因此所有包都放行。
- 第7條規(guī)則丟棄無用包。
- 第8條規(guī)則用來處理所有規(guī)則都不匹配的包,跳轉(zhuǎn)到neutron-openvswi-sg-fallback鏈,而該鏈其實只有一條規(guī)則,即DROP ALL。因此不匹配安全組規(guī)則的包都會直接丟棄。
3.6 安全組使用安全組作為匹配條件
前面2.3節(jié)提到,安全組不僅支持通過IP地址段作為源或者目標(biāo)的匹配條件,還支持通過指定另一個安全組,這種情況怎么處理呢。
為了測試我把創(chuàng)建了一個新的安全組int32bit-test-secgroup-2以及新的虛擬機int32bit-server-2(192.168.100.7),并且int32bit-server-2關(guān)聯(lián)了安全組int32bit-test-secgroup-2。
同時在int32bit-test-secgroup-1上增加一條入訪規(guī)則,允許關(guān)聯(lián)int32bit-test-secgroup-2的虛擬機訪問8080端口:
我們查看虛擬機入訪規(guī)則鏈neutron-openvswi-i3b90700f-1:
我們發(fā)現(xiàn)插入了一條新的規(guī)則,編號為4。該規(guī)則使用了set擴展模塊,前面介紹過set是用來匹配ipset的,后面的參數(shù)NIPv4fc83d82a-5b5d-4c90-80b0-為ipset名,顯然是由NIPv4+安全組UUID前綴組成。
我們查看該ipset:
可見192.168.100.7在ipset集合中。
因此OpenStack安全組使用安全組作為匹配條件時是通過ipset實現(xiàn)的,每個安全組會對應(yīng)創(chuàng)建一個ipset集合,關(guān)聯(lián)的虛擬機IP會放到這個集合中,iptables通過ipset匹配實現(xiàn)了安全組匹配功能。
4、安全組anti snoop功能
前面3.5節(jié)提到第2條規(guī)則,所有的包都會先進入neutron-openvswi-s3b90700f-1子鏈處理,這個鏈?zhǔn)歉墒裁吹哪?
我們首先查看下里面的規(guī)則:
這條鏈的處理邏輯很簡單,只放行IP是192.168.100.10并且MAC地址是FA:16:3E:A0:59:BA的包通過。這其實是Neutron默認(rèn)開啟的反欺騙anti snoop功能,只有IP和MAC地址匹配Neutron port分配的才能通過。換句話說,你起了個虛擬機IP為192.168.3.1,然后自己手動把網(wǎng)卡的IP篡改為192.168.3.2,肯定是不允許通過的。
但是呢,我們業(yè)務(wù)又往往有virtual ip的需求,最常見的如haproxy、pacemaker的vip。OpenStack考慮了這種需求,支持用戶添加白名單列表,通過port的allowed address pairs配置。
比如我有兩個虛擬機,IP分別為192.168.0.10、192.168.0.11,申請了一個port 192.168.0.100作為這個兩個虛擬機的vip,可以通過Neutron更新port信息實現(xiàn):
添加后我們再查看下neutron-openvswi-s3b90700f-1鏈規(guī)則:
可見在最前面添加了一條規(guī)則允許IP為192.168.0.100的包通過,此時在虛擬機192.168.0.10上把IP改為192.168.0.100也可以ping通了。
5、虛擬機訪問宿主機怎么辦?
我們已經(jīng)知道,安全組是在filter表的FORWARD鏈上實現(xiàn)的,但如果虛擬機的包是去往宿主機時,由于內(nèi)核判斷目標(biāo)地址就是自己,因此不會流到FORWARD鏈而是發(fā)往INPUT鏈,那這樣豈不就是繞過安全組規(guī)則了嗎?
解決辦法很簡單,只需要把neutron-openvswi-o3b90700f-1再掛到INPUT鏈就可以了。
我們查看INPUT鏈規(guī)則:
即:
有人可能會問,那宿主機發(fā)往虛擬機的包會出現(xiàn)問題嗎?需要在OUTPUT鏈上添加規(guī)則嗎?答案是不需要,因為從OUTPUT直接出去,當(dāng)作正常流程走就可以了。
6、總結(jié)
本文首先簡單介紹了下iptables,然后介紹OpenStack安全組,最后詳細分析了安全組的實現(xiàn)原理。
另外寫了一個腳本可以快速導(dǎo)出虛擬機的iptables規(guī)則,需要在計算節(jié)點上運行:
付廣平,任職某銀行云技術(shù)管理中心,負(fù)責(zé)云計算相關(guān)技術(shù)研究。畢業(yè)于北京郵電大學(xué),從2013開始從事OpenStack相關(guān)工作,參與了OpenStack Nova、Cinder、Oslo等項目社區(qū)開發(fā)。