基於我之前的文章中的相關內容,本文通過使用OVN訪問控制列表(ACL)來實現基本的網絡安全功能。
OVN中的ACL規則存儲於北向數據庫的ACL表中,並且可以使用ovn-nbctl的acl命令進行配置。目前,ACL只能應用於邏輯交換機,但是未來將支持應用到邏輯路由器。
在出站和入站方向都支持使用ACL:
入站:從工作負載(from-lport)進入邏輯端口
出站:從邏輯端口出去到工作負載(to-lport)。
此外,爲每個ACL分配一個優先級,以確定它們的匹配順序,最高優先級首先被匹配。另外ACL可以被賦予相同的優先級。 然而,在兩個具有相同優先級並且都匹配同一個分組的ACL的情況下,將僅匹配一個ACL。確切地說,哪一個ACL最終將被匹配是不確定的,你不能真正地確定哪個規則將應用於給定的情況。所以我建議:在大多數情況下儘量使用不同的優先級。
ACL中的匹配規則基於OVS中的流語法,對於具有編程背景的人都會覺得很熟悉。該語法在ovn-sb手冊頁的「Logical_Flow表」部分中進行了說明。它值得一讀,特別是介紹「!=」匹配規則的那部分內容。
另外值得強調的一點是,您不能在具有type = router的端口上創建ACL匹配規則。爲了減少ACL表中的條目數量,可以使用定義相同類型地址組的地址集。例如,一組IPv4地址/網絡,一組MAC地址或一組IPv6地址可以放置在一個可命名的地址集內。爲了減少ACL表中的條目數,可以使用定義相同類型地址組的地址集。 例如,一組IPv4地址/網絡,一組MAC地址或一組IPv6地址可以放置在命名地址集內。 然後地址集可以被ACL的match子句內的「name」引用(以$ name的形式)。
下面舉個例子:
|
#允許來自交換機「ls1」上端口「ls1-vm1」的所有ip流量,同時允許相關回包通過 ovn-nbctl acl-add ls1 from-lport 1000 "inport == \"ls1-vm1\" && ip" allow-related
# 允許 ssh 到 ls1-vm1 ovn-nbctl acl-add ls1 to-lport 999 "outport == \"ls1-vm1\" && tcp.dst == 22" allow-related
# 阻止所有到ls1-vm1的IPv4/IPv6流量 ovn-nbctl acl-add ls1 to-lport 998 "outport == \"ls1-vm1\" && ip" drop |
注意「allow-related」的使用。 它的作用是這樣:它允許反向相關的流量(例如,響應,fragements等)通過。 在第二條規則中,爲了允許從服務器回來的SSH響應流量通過,我就使用了 allow-related 。
我們再來看看地址集。 如前文所述,地址集是相同類型的地址組。 使用ovn-nbctl北向數據庫命令創建地址集,然後在ACL中調用地址集。 這裏有幾個創建地址集的例子:
|
ovn-nbctl create Address_Set name=wwwServers addresses=172.16.1.2,172.16.1.3 ovn-nbctl create Address_Set name=www6Servers addresses=\"fd00::1\",\"fd00::2\" ovn-nbctl create Address_Set name=macs addresses=\"02:00:00:00:00:01\",\"02:00:00:00:00:02\" |
注意使用帶有包含‘:’字符的地址集的雙引號。 如果你在命令中不使用雙引號,將會報錯。
我們在實驗室環境中使用ACL進行實驗。詳細的環境介紹和搭建,請參考我之前的文章。
物理網絡環境:
OVN邏輯網絡環境:
第一步,我們將通過爲每個服務器創建一個靜態NAT規則來允許從外部訪問DMZ中的服務器。
在ubuntu1上執行:
|
#爲vm1創建snat-dnat規則並應用於edge1 ovn-nbctl -- --id=@nat create nat type="dnat_and_snat" logical_ip=172.16.255.130 \ external_ip=10.127.0.250 -- add logical_router edge1 nat @nat
#爲vm2創建snat-dnat規則並應用於edge1 ovn-nbctl -- --id=@nat create nat type="dnat_and_snat" logical_ip=172.16.255.131 \ external_ip=10.127.0.251 -- add logical_router edge1 nat @nat |
從 ubuntu1 ping snat-dnat 的外部IP:
|
root@ubuntu1:~# ping 10.127.0.250 PING 10.127.0.250 (10.127.0.250) 56(84) bytes of data. 64 bytes from 10.127.0.250: icmp_seq=1 ttl=62 time=2.57 ms 64 bytes from 10.127.0.250: icmp_seq=2 ttl=62 time=1.23 ms 64 bytes from 10.127.0.250: icmp_seq=3 ttl=62 time=0.388 ms
root@ubuntu1:~# ping 10.127.0.251 PING 10.127.0.251 (10.127.0.251) 56(84) bytes of data. 64 bytes from 10.127.0.251: icmp_seq=1 ttl=62 time=3.15 ms 64 bytes from 10.127.0.251: icmp_seq=2 ttl=62 time=1.52 ms 64 bytes from 10.127.0.251: icmp_seq=3 ttl=62 time=0.475 ms |
第二步:檢查虛擬機可以使用正確的IP連接到外部世界
|
root@ubuntu2:~# ip netns exec vm1 ping 10.127.0.130 PING 10.127.0.130 (10.127.0.130) 56(84) bytes of data. 64 bytes from 10.127.0.130: icmp_seq=1 ttl=62 time=3.05 ms
root@ubuntu3:~# ip netns exec vm2 ping 10.127.0.130 PING 10.127.0.130 (10.127.0.130) 56(84) bytes of data. 64 bytes from 10.127.0.130: icmp_seq=1 ttl=62 time=1.87 ms
root@ubuntu1:~# tcpdump -i br-eth1 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on br-eth1, link-type EN10MB (Ethernet), capture size 262144bytes 17:51:01.055258 IP 10.127.0.250 > 10.127.0.130: ICMP echo request, id4565, seq 12, length 64 17:51:01.055320 IP 10.127.0.130 > 10.127.0.250: ICMP echo reply, id 4565, seq 12, length 64
17:51:56.378089 IP 10.127.0.251 > 10.127.0.130: ICMP echo request, id4301, seq 6, length 64 17:51:56.378160 IP 10.127.0.130 > 10.127.0.251: ICMP echo reply, id 4301, seq 6, length 64 |
現在,我們可以從ubuntu1上的tcpdump的輸出結果看到虛擬機正在使用正確的NAT地址。
第三步:應用一些安全策略。 首先,我們將完全鎖定DMZ。
|
#添加默認ACL策略(對不匹配任何轉發規則的流量進行丟棄) ovn-nbctl acl-add dmz to-lport 900 "outport == \"dmz-vm1\" && ip" drop ovn-nbctl acl-add dmz to-lport 900 "outport == \"dmz-vm2\" && ip" drop |
在ubuntu1上驗證網絡已經不通:
|
root@ubuntu1:~# ping 10.127.0.250 PING 10.127.0.250 (10.127.0.250) 56(84) bytes of data. ^C --- 10.127.0.250 ping statistics --- 2 packets transmitted, 0 received, 100% packet loss, time 1007ms
root@ubuntu1:~# ping 10.127.0.251 PING 10.127.0.251 (10.127.0.251) 56(84) bytes of data. ^C --- 10.127.0.251 ping statistics --- 2 packets transmitted, 0 received, 100% packet loss, time 1007ms |
DMZ服務器現在無法從外部訪問,但這時候從DMZ內部ping 外界網絡也不通了:
|
root@ubuntu2:~# ip netns exec vm1 ping 10.127.0.130 PING 10.127.0.130 (10.127.0.130) 56(84) bytes of data. ^C --- 10.127.0.130 ping statistics --- 2 packets transmitted, 0 received, 100% packet loss, time 1008ms
root@ubuntu3:~# ip netns exec vm2 ping 10.127.0.130 PING 10.127.0.130 (10.127.0.130) 56(84) bytes of data. ^C --- 10.127.0.130 ping statistics --- 2 packets transmitted, 0 received, 100% packet loss, time 1008ms |
我們來解決這個問題:
|
#允許所有ip流量和相關連接回包通過 ovn-nbctl acl-add dmz from-lport 1000 "inport == \"dmz-vm1\" && ip" allow-related ovn-nbctl acl-add dmz from-lport 1000 "inport == \"dmz-vm2\" && ip" allow-related |
驗證:
|
root@ubuntu2:~# ip netns exec vm1 ping 10.127.0.130 PING 10.127.0.130 (10.127.0.130) 56(84) bytes of data. 64 bytes from 10.127.0.130: icmp_seq=1 ttl=62 time=4.16 ms 64 bytes from 10.127.0.130: icmp_seq=2 ttl=62 time=3.07 ms
root@ubuntu3:~# ip netns exec vm2 ping 10.127.0.130 PING 10.127.0.130 (10.127.0.130) 56(84) bytes of data. 64 bytes from 10.127.0.130: icmp_seq=1 ttl=62 time=3.59 ms 64 bytes from 10.127.0.130: icmp_seq=2 ttl=62 time=2.30 ms |
允許到DMZ服務器的入站HTTPS (tcp 443端口)流量:
|
#允許到DMZ服務器的入站HTTPS (tcp 443端口)和回包流量: ovn-nbctl acl-add dmz to-lport 1000 "outport == \"dmz-vm1\" && tcp.dst == 443" allow-related ovn-nbctl acl-add dmz to-lport 1000 "outport == \"dmz-vm2\" && tcp.dst == 443" allow-related |
驗證: 首先需要監聽tcp 443 端口。我喜歡使用ncat。 它實際上是nmap軟件包的一部分。所以第一步是在所有3個Ubuntu主機上安裝它:
|
apt-get -y install nmap |
現在我們可以在443端口運行一個監聽進程。進程將在連接結束時終止,但是你可以使用-k參數來持續運行它。
在ubuntu2:
|
ip netns exec vm1 ncat -l -p 443 |
在 ubuntu3:
|
ip netns exec vm2 ncat -l -p 443 |
並在ubuntu1的檢查連通性。 如果連接成功,它將保持打開狀態,直到您終止它。 如果沒有,那麼它應該在1秒後超時
|
root@ubuntu1:~# ncat -w 1 10.127.0.250 443 ^C
root@ubuntu1:~# ncat -w 1 10.127.0.251 443 ^C |
策略生效了! 我們加固了「inside」服務器的安全性。
接下來的操作會使它更加安全:阻止所有出站訪問,並且只允許從dmz訪問tcp 3306。 我們將配置一個地址集來表示DMZ內的一些地址。 注意在「acl-add」命令中使用了單引號。 我們實際上是通過地址集名稱來引用它,前綴是一個'$'字符。 因爲我們不希望bash將其解釋爲一個變量,所以我們使用了單引號。
|
# 爲dmz服務器創建一個地址集。 使用/31掩碼 ovn-nbctl create Address_Set name=dmz addresses=\"172.16.255.130/31\"
# 允許源IP爲dmz地址集內的IP地址,且目標端口爲3306 ovn-nbctl acl-add inside to-lport 1000 'outport == "inside-vm3" && ip4.src == $dmz && tcp.dst == 3306' allow-related ovn-nbctl acl-add inside to-lport 1000 'outport == "inside-vm4" && ip4.src == $dmz && tcp.dst == 3306' allow-related
# 添加默認ACL策略(對不匹配任何轉發規則的流量進行丟棄) ovn-nbctl acl-add inside to-lport 900 "outport == \"inside-vm3\" && ip" drop ovn-nbctl acl-add inside to-lport 900 "outport == \"inside-vm4\" && ip" drop |
我們將再次使用ncat監聽我們的VM,但這次是在vm3 /vm4上進行
在 ubuntu2:
|
ip netns exec vm3 ncat -l -p 3306 |
在 ubuntu3:
|
ip netns exec vm4 ncat -l -p 3306 |
驗證 dmz到 inside的網絡連通性:
|
root@ubuntu2:~# ip netns exec vm1 ncat -w 1 172.16.255.195 3306 ^C
root@ubuntu3::~# ip netns exec vm1 ncat -w 1 172.16.255.195 3306 ^C
root@ubuntu3:~# ip netns exec vm2 ncat |