本文闡述了 OpenStack 用 iptables、鏈和規則處理聯網的,這跟其他系統非常類似。但是首先,讓 我們先來看看 iptables 的結構,作為本文內使用技術的前奏。
iptable 的結構
iptable 是一個用戶空間應用程序,允許系統管理員配置由 Linux 內核防火牆提供的表;iptable 專指 IPv4 網 絡。
要設置一個 Linux 防火牆,就要使用規則,每個規則指定在包中與什麼匹配,以及對包執 行什麼操作。鏈 是一個規則列表。
Iptable 的前身 ipchains 增加規則鏈的概念;iptable 則 將概念擴展為表。所以 iptable 的結構是:iptables > tables > chains > rules。
iptable 具有四個內置表:
Filter 表:默認表,具有如下鏈:
INPUT 用於傳到本地服務器的包。
OUTPUT 用於本地生成以及傳出本地服務器的包。
FORWARD 用於通過本地服務器路由的包。
NAT 表(網絡地址轉換):
PREROUTING:用於目的 NAT,它在路由前更改包 IP 地址。
POSTROUTING:用於源 NAT,它在路由前更改包 IP 地址。
OUTPUT:用於防火牆上本地生成包的 NAT。
Mangle 表:用於特定包的更改:
PREROUTING
OUTPUT
FORWARD
INPUT
POSTROUTING
Raw 表:用於配置免除:
PREROUTING
OUTPUT
OpenStack 內的 iptable
在 OpenStack 內,您會在 Compute-Nova 模塊中發現 iptable 鏈和規則占主導作用,該模塊是使用 Python 編寫並使用在多數外部庫的雲計算結構控制器(IaaS 系統 的主要部分)。本文詳細介紹了 nova-network FlatDHCPManager 組件以及其他聯網任務所需的 OpenStack 組件。
在開始時,OpenStack 定義了一些 OpenStack 鏈。這些鏈與 Linux 內置鏈形 成了一個鏈結構。啟動時的另一個任務是為固定的網絡范圍和元數據服務定義一些規則。創建並使用網 絡後,nova-network 就會設置一些規則。當創建一個實例(也稱為一個服務器和 VM)後,nova- compute 就會創建一個特定於實例的鏈並設置此鏈下的規則以確保實例的連接性。就浮動 IP 而言, OpenStack 也可使用一些規則以正常運行起來。此外,OpenStack 的安全性組及其規則是由 iptables 規則體現。
初識 OpenStack
OpenStack 是一個由開發者和雲計算技術人員的全球 協作開發的面向公共和私有雲的標准雲操作系統,是在 Apache 許可條款下發布的免費開源軟件。雲服 務提供者、企業和政府組織均可使用這個免費的 Apache 許可的軟件來構建可大規模伸縮的雲環境。
OpenStack 目前包含六個核心軟件項目:
Cloud Compute-Nova
Cloud Storage-Swift
Image Service-Glance(交付和注冊)
Identity Service-Keystone
Dashboard-Horizon
Network Connectivity-Quantum
這些項目以及充滿活力的技術提供者和未來項目組成的生態系統帶來了一個面向公共和私有雲的可 插入式的框架和操作系統。
Nova 項目內擁有 10 多個命令,其中的 3 個與 VM 連接性有關:
nova-api 為 VM 提供元數據服務。
nova-compute 為 VM 設置網絡環境。
nova-network 為整個雲生態系統設置網絡環境,如 IP 配置和 DHCP 設置等任務。
雖然 Nova 要求並與很多本機系統組件集成,用於數據庫、消息接送功能和虛擬化功能,但它的模 塊主要由一組 Python 守護進程組成。它使用了一個特殊的元數據服務來使虛擬機實例檢索特定於實例 的數據。實例訪問 http://169.254.169.254 處的元數據服務。
元數據包括公共 SSH 密鑰(當 用戶請求一個新的實例時,由密鑰/對標識),用戶數據(作為 API 調用中的 user_data 參數進行傳遞 ,或是由 Nova 啟動命令中的 --user_data 標記傳遞)。二進制的 nova-api 命令實現元數據服務。
OpenStack 是一套復雜組件集。
在開始探討 Nova 內的規則和鏈之前,讓我們先來看看 IP 尋址的模式。
Nova 中的 IP 尋址
每個 VM 都會從可用的 nova-network 自動分配一 個私有 IP 地址。這些 IP 地址稱為固定 IP。您可以選擇性地將公共 IP 地址分配給實例。OpenStack 使用術語浮動 IP 來指代可被動態添加到一個運行中虛擬實例的 IP 地址(通常都是公共的)。
有多個策略可用來實現固定 IP:
Flat 模式
Flat DHCP 模式
VLAN DHCP 模式
具有定額(quantum)模式的 nova-network
Flat 模式
Flat 模式是最簡單的一種聯網模式。每個實例接收一個來自池的固定 IP。所有 實例均默認附加到相同的橋 (br100)。橋必須進行手動配置。聯網配置在實例引導前插入到實例中。在 這種模式中,沒有浮動 IP 特性。
Flat DHCP 模式
與 flat 模式類似,所有實例也是都 附加到同一個橋。在這種模式下,Nova 會進行更多的一些配置;它會試圖橋接到一個 Ethernet 設備( 默認為 eth0)。它還會運行 dnsmasq 作為 dhcpserver 來偵聽橋。實例通過執行 dhcpdiscover 接收 它們的固定 IP。並且,還會提供浮動 IP 特性。
VLAN DHCP 模式
這是一種默認的聯網模 式,並且支持大多數特性。對於安裝了多個機器的情況,它需要一個能支持主機托管的 VLAN 標簽的開 關。在這種模式下,Nova 將會創建一個 VLAN 並會為每個項目進行橋接(與一個租戶一樣)。項目會獲 得只能從 VLAN 內訪問到的私有 IP 的范圍。對於在其項目內訪問實例的用戶,需要創建一個特殊的 VPN 實例(代碼命名為 “cloudpipe”)。Nova 會生成一個證書和密鑰以供用戶訪問此 VPN,並自動啟 動此 VPN。
具有定額模式的 nova-network
在這個模式下,DHCP 服務器還可以自動啟動 ,但不支持浮動 IP。在每個計算主機上運行一個定額代理以將虛擬實例連接到定額網絡。網絡拓撲可以 是非常復雜的。
在 Nova 內,一個安全組就是網絡訪問規則的組合,比如防火牆策略。這些訪問 規則指定了哪些傳入網絡流量應該被發送到組內所有的 VM 實例;所有其他流量則被丟棄。用戶可以隨 時修改組的規則。所有運行中的實例以及從那時起啟動的實例將強制使用這些新的規則。可將安全組想 象為安全配置文件或安全角色,比如 “webappserver”。
iptable 的規則和鏈
正如之 前所討論的,iptable 是一個用戶空間應用程序,允許系統管理員配置由 Linux 內核防火牆提供的表以 及它所存儲的鏈和規則。
正如之前所提到的,可以定義幾個不同的表;OpenStack 內使用表中有 filter 和 NAT。每個表都包含一些內置的鏈,也可能包含用戶定義的鏈。每個鏈均是一個能與一組包相 匹配的規則列表。每個規則指定對匹配的包執行什麼操作,稱之為一個目標,可以是跳到同一個表內的 一個用戶定義的鏈。
接下來,將討論各種密鑰鏈和規則。
nova-network 啟動時創建的鏈
圖 1. NetworkManager 類連接其他類
如圖 1 所示, NetworkManager 是一個連接到很多其他類或模塊的大類。linux_net 就是這些類或模塊中的一個。 linux_net 包含了一個 IptablesManager 對象,其 __init__() 方法則初始化 OpenStack 系統內定義 的鏈。
圖 2. 初始化鏈
如之前所述,Linux 內核中的 IPv4 包過濾器規則表擁有一些內置的鏈:PREROUTING、INPUT、FORWARD、OUTPUT 和 POSTROUTING。總 體上,抵達 Linux 主機的包會轉向 PREROUTING 鏈。在傳遞之後,內核就會做出一個路由決定。如果包 的目標是本 Linux 主機,它就會轉向INPUT 鏈,如果被接受,則會轉向目標進程。如果包不是用於本 Linux 主機的,則會轉向 FORWARD 鏈,接著再轉向 POSTROUTING鏈,然後離開主機。由本地進程生成的 包首先會轉向 OUTPUT 鏈,如果被接受,就會轉向 POSTROUTING 鏈。
除了這些內置鏈外, OpenStack 系統會創建其他一些可鉤掛到鏈系統的鏈。OpenStack 鏈包含兩種類型:未包裝(unwrapped )鏈和已包裝(wrapped)鏈。
nova-filter-top 和 nova-postrouting-bottom 是兩種未包裝鏈 。nova-filter-top 被添加到 FORWARD 和 OUTPUT 鏈頂部。由於起未包裝,所以它可在各種 Nova 工作 進程間進行共享。它針對的是 FORWARD 和 OUTPUT 鏈頂部存在的規則。在表中的 IPv4 和 IPv6 集合均 均存在 nova-filter-top。
已包裝鏈的例子則包括綠色鏈(green colored chains)。這些鏈 的名稱會有進程名作為後綴。比如,nova-network 會創建 nova-network-PREROUTING 鏈。
對 於 IPv4 和 IPv6,內置的 INPUT、OUTPUT 和 FORWARD 過濾器鏈都是已包裝的,這意味著這個“真正” 的 INPUT 鏈具有一個規則,可跳至已包裝的 INPUT 鏈等。此外,還有一種已包裝鏈,名為 local,它 從 nova-filter-top 開始跳轉。
對於 IPv4,內置的 PREROUTING、OUTPUT 和 POSTROUTING NAT 鏈的包裝方式與內置的過濾器鏈一樣。此外,在 POSTROUTING 鏈之後,還會應用一個 sNAT 鏈和一個 float-sNAT 鏈。
nova-network 啟動時的規則
圖 3 顯示了 FlatDHCPManager 的部分啟 動進程。之前介紹過的 __init__() 方法,它可構成 IptableManager 對象來創建很多 OpenStack 鏈。 所以,我們將著重介紹 init_host()。init_host() 方法調用 LinuxNet3 的 initialize() 方法,它調 用 linux_net 的方法來設置 NAT 表內的一些 iptables 規則。
圖 3. FlatDHCPManager 的啟動 進程
讓我們來看看這些規則。
元數據主機的規則
在由 linux_net 的 init_host() 創建的這些規則之中,其中的一個 規則就是允許 FLAGS.fixed_range 下的 IP 訪問 metadata_host(在本例中為 192.168.1.90)。
-A nova-network-POSTROUTING -s 10.0.0.0/8 -d 192.168.1.90/32 -j ACCEPT
ensure_metadata_ip() 將 169.254.169.254/32 添加到 lo 設備,使用命令如下:
# ip addr add 169.254.169.254/32 scope link dev lo
然後,metadata_forward() 將 一個 dNAT 規則添加到 route 包,從 169.254.169.254/32 到 metadata_host:
-A nova- network-PREROUTING -d 169.254.169.254/32 -p tcp -m tcp --dport 80 -j DNAT
--to- destination 192.168.1.90:8775
如果此 nova-network 和 nova-api 並未在相同的主機上運行 ,那麼您必須定義 nova-network 上的 metadata_host 來指向此 nova-api 主機。
訪問 dmz 的 規則
FLAGS.dmz_cidr 定義了一個 dmz 列表(邊界聯網)CIDRs(無類別域間路由)。在默認的 情況下,它是一個空列表。在本例中為 10.128.0.0/24。所以,此規則為:
-A nova-network- POSTROUTING -s 10.0.0.0/8 -d 10.128.0.0/24 -j ACCEPT
VM 之間互相連接的規則
另一 個規則是確保具有兩個規定 IP 的 VM 能夠互相會話:
-A nova-network-POSTROUTING -s 10.0.0.0/8 -d 10.0.0.0/8 -m conntrack ! --ctstate DNAT
-j ACCEPT
固定子集之外的訪 問所需規則
add_snat_rule() 方法將一個 sNAT 規則添加到此 NAT 表的已包裝鏈 sNAT 內。在 圖 3 中可以看到 ip_range 和 FLAGS.routing_source_ip。ip_range 的值是由 FLAGS.fixed_range 定 義。在本例中為 10.0.0.0/8。FLAGS.routing_source_ip 默認為 FLAGS.my_ip,由函數 flags._get_my_ip() 默認。在本例中,FLAGS.my_ip 為 192.168.1.90。在這之後,您會獲得一個規則 ,類似於:
-A nova-network-snat -s 10.0.0.0/8 -j SNAT --to-source 192.168.1.90
為了固定 IP 能夠訪問外部,必須創建一個是 FLAGS.fixed_range 子集的網絡。這樣一來,隨著默認網 關指向 nova-network 機器上的 br100 的一個 IP ,具有此子集 IP 的 VM 就將能夠訪問一個外部網絡 。
每個網絡的規則
要設置一個網絡,nova-network 會在此 filter 表內創建一些規則。 要觸發此 nova-network 在給定網絡上的操作,可運行如下命令:
創建一個網絡並設置主機:
# ./bin/nova-manage network create mynet 10.10.10.0/24
引導一個服務器:
nova boot --image a3fb743d-42df-49ba-b9c4-8042ebbd344e --flavor 1 myserver
執 行這些命令後,如下規則適用:
支持轉發流量傳遞橋,這樣 br100 上的 IP 就可以充當一個網 關:
-A nova-network-FORWARD -i br100 -j ACCEPT
-A nova-network-FORWARD -o br100 -j ACCEPT
支持 DHCP 和 DNS 流量進入到本地 dnsmasq 過程:
-A nova-network-INPUT -i br100 -p udp -m udp --dport 67 -j ACCEPT
-A nova-network-INPUT -i br100 -p tcp -m tcp - -dport 67 -j ACCEPT
-A nova-network-INPUT -i br100 -p udp -m udp --dport 53 -j ACCEPT
-A nova-network-INPUT -i br100 -p tcp -m tcp --dport 53 -j ACCEPT
備注:67 為 DHCP 端 口,而 53 為 DNS 端口。
nova-compute 主機上的規則
nova-compute 模塊還會創建已包 裝的鏈。在這些鏈上,它會在此 filter 表內創建一些規則。讓我們一起來看看。
支持轉發流量 傳遞橋的規則
nova-compute 主機上的這些規則允許 VM 與 nova-network 主機以及其他計算主 機上的 VM 相連接。
-A nova-compute-FORWARD -i br100 -j ACCEPT
-A nova-compute- FORWARD -o br100 -j ACCEPT
每個實例的鏈和規則
對於每個實例,它都會在此 filter 表內 創建一個鏈及一些規則(參見圖 4)。
圖 4. 每個實例的鏈和規則
 
可以看到:
nova-compute 為每個實例創建一個鏈。在圖 4 中,此鏈的名稱是 nova-compute-inst-1。
所有針對此實例的流量,無論是轉發而來的還是從本地過程生成的,都會進入此實例的特定鏈。
所有來自該實例所在的子集的 IP 的流量都是允許的。
所有來自特定 DHCP 服務器的 DHCP 流量都是允許的。
所有其他流量均放棄。
nova-api
一開始,nova-api 會在 filter 表內創建一個規則以允許他人能夠訪問 nova- api 服務。
-A nova-api-INPUT -d 192.168.1.90/32 -p tcp -m tcp --dport 8775 -j ACCEPT
浮動 IP
要了解浮動 IP 是如何實現的,首先將一個浮動 IP 關聯到此實例的固定 IP。之前所創建的這個實例的固定 IP 是 10.10.10.2。
在默認池內創建一個浮動 IP
要 在默認池內創建一個浮動 IP,請運行一下代碼:
# nova-manage floating create -- ip_range=192.168.1.232/30
要從這個池分派一個浮動 IP,請運行一下代碼:
# Nova floating-ip-create
這樣,就擁有一個 IP 192.168.1.233。現在將它分配給 ID 為 8f773639- c04f-4885-9349-ac7d6a799843 的實例:
# nova add-floating-ip 8f773639-c04f-4885-9349- ac7d6a799843 192.168.1.233
將浮動 IP 綁定到公共接口
FLAGS.public_interface 被用 來綁定浮動 IP。在運行了 nova add-floating-ip 命令後,可以看到 public_interface 下就具有了如 下的浮動 IP:
# ip addr list dev wlan0
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
link/ether 08:11:96:75:91:54 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.90/16 brd 192.168.255.255 scope global wlan0
inet 192.168.1.233/32 scope global wlan0
inet6 fe80::a11:96ff:fe75:9154/64 scope link
valid_lft forever preferred_lft forever
NAT 表內針對浮動 IP 的 規則
在此實例獲得了 nova-network 主機上的一個浮動 IP 後,這些規則適用:
-A nova-network-OUTPUT -d 192.168.1.233/32 -j DNAT --to-destination 10.10.10.2
-A nova- network-PREROUTING -d 192.168.1.233/32 -j DNAT --to-destination 10.10.10.2
-A nova- network-float-snat -s 10.10.10.2/32 -j SNAT --to-source 192.168.1.233
您會看到該 dNAT 規則被用來將此浮動 IP 轉換成此實例的固定 IP。如果一個包到達 nova-network 主機並以浮動 IP 為 目標 IP,則此目標 IP 就會被轉換。然後,就會有另一項 sNAT 規則會將來自此實例的固定 IP 的流量 轉換到此浮動 IP。由於所有從 VM 到固定網絡之外的流量均被指向網關(是由 nova-network 的 dnsmasq 進行設置),有了 sNAT 規則,出 VM 的流量就可以成功標志成來自此浮動 IP。此外,已包裝 的 OUTPUT 鏈內還有一個 dNAT 規則,允許 nova-network 上的本地過程訪問具有浮動 IP 的 VM。
使用浮動 IP 的 Ping VM
要將 VM 與浮動 IP Ping 在一起,也需要一些規則。請記住, 在此 nova-compute 主機上,針對每個實例必須有一個特定鏈;其內的規則只允許來自固定子集內的 IP 的流量。如果想要 ping 一個浮動 IP,流量就會被這些規則丟棄,因為 ping 包的源 IP 並不在此固定 子集內。顯然,需要一個規則以允許 icmp 流量。
為了添加一個允許 ping 的規則,可以使用 OpenStack 的安全組規則的概念:
# nova secgroup-add-rule default icmp -1 -1 0.0.0.0/0
之後,就可以看到在此實例的特定鏈下多創建了一個規則:
-A nova-compute- inst-1 -p icmp -j ACCEPT
同樣的方式,可以對具有浮動 IP 的 VM 啟用 SSH。
結束語
來自 iptable 的規則被 OpenStack 網絡廣泛使用。其安全組以及浮動 IP 的概念只是使用 iptable 規則的開始。