iptables詳解及docker的iptables規則

百里miles發表於2020-10-31

iptables

處理流程

iptables是Linux中網路鉤子,有四表五鏈。

  • filter表即防火牆規則,允許、阻止或丟棄進出的資料包,使用是最多的
  • nat表,網路地址轉換,內網的資料包收發室,有多種型別,常見的有SNAT,PNAT,DNAT,是第二常用的
  • mangle表,修改資料包的TTL,給資料包做不同的標記,策略路由等
  • raw表,一般用於跟蹤狀態,除錯,用的較少

優先順序:raw,mangle,nat,filter

五鏈:

  • PREROUTING,到達本機前的路由規則
  • INPUT,進入本機的規則
  • FORWARD,轉發的規則
  • OUTPUT,本機發出的規則
  • POSTROUTING,發出後的路由規則

在這裡插入圖片描述

命令與擴充套件

清空表上的所有規則,預設為filter表:
iptables -F

鏈上操作規則,A追加,I前面插入,D刪除,R替換,N新建一個自定義鏈,例如:
在第5條規則前插入禁止非192.168.1.0/24訪問80埠
iptables -I INPUT 5 -p tcp --dport 80 ! -s 192.168.1.0/24 -j DROP

檢視某個表的所有鏈上的規則:
iptables -t nat -L -n -v --line-numbers

filter表,常將lo網路卡和已建立連線的規則放在最前面,降低系統負擔:
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

允許ping:
iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT

允許連續範圍埠:
iptables -A INPUT -p udp --sport 1000:2000 -j ACCEPT

每個鏈都有預設規則,禁止時可以設定白名單,允許時可以設定黑名單
INPUT鏈預設禁止連線:
iptables -P INPUT DROP

iptables有很多擴充套件,不同的擴充套件有不同的功能,檢視文件,man iptables-extensions常用的:

  • 多埠擴充套件,-m multiport --dports 80,443
  • recent擴充套件,每30秒最多10個連線:
    iptables -I INPUT -p tcp --dport 80 -m state --state NEW -m recent --set
    iptables -I INPUT -p tcp --dport 80 -m state --state NEW -m recent --update --seconds 30 --hitcount 10 -j DROP
  • connlimit擴充套件,限制併發連線數:
    iptables -I INPUT -p tcp --syn --dport 80 -m connlimit --connlimit-above 100 -j REJECT
  • string擴充套件,字串匹配禁止:
    iptables -I INPUT -p tcp --sport 443 -m string --string "xunlei" --algo kmp -j DROP

iptables規則都是儲存在記憶體中的,重啟規則會丟失,可以使用iptables-saveiptables-restore儲存,還可以使用iptables-services

# 禁用firewalld
#systemctl stop firewalld
#systemctl disable firewalld
yum -y install iptables-services
service iptables save
service iptables reload

系統預設規則

安裝iptables-services後,/etc/sysconfig/iptables檔案中有預設規則:

iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -p icmp -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
iptables -A INPUT -j REJECT --reject-with icmp-host-prohibited
iptables -A FORWARD -j REJECT --reject-with icmp-host-prohibited

第四個是允許ssh登入
第五個是禁止其他連線通過INPUT,並返回icmp-host-prohibited錯誤
第六個是禁止FORWARD

ipset的使用

可與iptables結合,實現動態的白名單,並且可以設定過期時間
ipset create ssh-allow hash:ip timeout 0
ipset add ssh-allow 192.168.47.1 timeout 86400
ipset list ssh-allow
iptables -A INPUT -p tcp --dport 22 -m set --match-set ssh-allow src -j ACCEPT

SNAT與DNAT

SNAT常用於內部無法上網的機器通過閘道器上網,需要調整安全組和解除閘道器MAC與IP繫結。

# 閘道器開啟核心轉發
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
sysctl -p

# 資料包離開前將源地址改為閘道器地址,動態上網時,常用-j MASQUERADE
iptables -t nat -A POSTROUTING -o eth0 -s 192.168.1.0/24 -j SNAT --to 172.16.8.1

# 不能上網的機器,修改閘道器
route add default gw 192.168.1.1

DNAT常用於將內部機器暴漏給外部使用者使用。
iptables -t nat -A PREROUTING -d 172.16.8.1 -p tcp --dport 80 -j DNAT --to-destination 192.168.1.20:8080

ftp規則

ftp分為主動模式和被動模式。

主動模式資料流是server主動連線client的隨機埠,一般客戶端都工作在NAT網路中,客戶端埠須層層路由開放,所以這種模式很少使用。

被動模式,server告知client資料連線埠,客戶端連線server的資料連線埠,這個埠一般是隨機的,需要服務端開放,使用iptables的連線追蹤功能,可以很好的解決這個問題

載入ftp專用的追蹤模組,modprobe nf_conntrack_ftp

開啟ftp追蹤模組後,僅需開放21埠即可(INPUT預設DROP,OUTPUT預設ACCEPT)
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
RELATED指明ftp關聯的資料埠允許連線

firewall-cmd命令

iptables分為ipv4和ipv6,兩者是獨立的,firewalld是iptables的python指令碼,已經整合了ipv4和ipv6

與iptables不同的是,firewalld使用zone來管理防火牆
zone可以根據source,mac,ipset,interface等匹配,匹配不上的進入預設的public

查詢預設zone:
firewall-cmd --get-default-zone
修改了規則需要重新載入才能生效:
firewall-cmd --reload
列出zone的所有規則:
firewall-cmd --list-all --zone=public
開放80埠:
firewall-cmd --zone=public --add-port=80/tcp --permanent

進行復雜的控制,需要rich規則,命令比較複雜,不推薦使用

docker的iptables規則

docker網路型別

  • none:顧名思義,不使用網路,只使用lo
  • host:使用主機的網路
  • bridge:橋接,相當於nat,通過docker0分配一個172.17.0.x的地址使用
  • container:使用指定容器的網路

資料包處理流程

為便於測試,啟動兩個容器:
docker run -d --rm --name nginx -p 80:80 nginx:1.16.1
docker run -it --name busybox --rm busybox sh

filter表規則

iptables -N DOCKER
iptables -N DOCKER-ISOLATION-STAGE-1
iptables -N DOCKER-ISOLATION-STAGE-2
iptables -N DOCKER-USER
iptables -A FORWARD -j DOCKER-USER
iptables -A FORWARD -j DOCKER-ISOLATION-STAGE-1
iptables -A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -o docker0 -j DOCKER
iptables -A FORWARD -i docker0 ! -o docker0 -j ACCEPT
iptables -A FORWARD -i docker0 -o docker0 -j ACCEPT
iptables -A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
iptables -A DOCKER-ISOLATION-STAGE-1 -j RETURN
iptables -A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
iptables -A DOCKER-ISOLATION-STAGE-2 -j RETURN
iptables -A DOCKER-USER -j RETURN

主要是轉發規則,預設FORWARD為DROP,DOCKER鏈處理到docker0的IP資料包,即容器對外的規則,例如:

iptables -A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 80 -j ACCEPT
允許非docker0訪問80埠

為了搞清楚DOCKER-ISOLATION-STAGE-2,需要建立一個bridge,開啟一個nginx,並安裝telnet

docker network create docker1
docker run -d --rm --name nginx1 -p 8080:80 --net docker1 nginx:1.16.1
docker exec -it nginx /bin/bash
# 在nginx中安裝telnet
#apt update
#apt install telnet
#telnet 172.18.0.2 80

可以看到telnet 172.18.0.2 80並不通,怎麼實現的呢?
DOCKER-ISOLATION-STAGE-1規則是源網路卡是docker0,而目的地不是docker0就進入DOCKER-ISOLATION-STAGE-2

而DOCKER-ISOLATION-STAGE-2中,有一條規則,iptables -A DOCKER-ISOLATION-STAGE-2 -o br-afba712bfb32 -j DROP,即不允許不同的網路卡互相訪問,這對於docker-compose非常有用,設計非常精妙

DOCKER-USER鏈用於自定義轉發規則,優先順序最高,可以限制進入容器的源IP地址:
iptables -I DOCKER-USER ! -s 192.168.47.1 -p tcp --dport 80 -j DROP
以上規則禁止非192.168.47.1的IP地址訪問容器的80埠

nat表規則

iptables -t nat -N DOCKER
iptables -t nat -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
iptables -t nat -A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
iptables -t nat -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
iptables -t nat -A DOCKER -i docker0 -j RETURN

DOCKER鏈方便container自定義規則
POSTROUTING規則,使得container使用宿主機docker0的IP作為閘道器,便於接收外部返回的資料

有如下規則:
iptables -t nat -A DOCKER ! -i docker0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.17.0.2:80
通過PREROUTING鏈和DOCKER鏈將主機的80埠流量轉發給172.17.0.2,並通過filter表的FORWARD鏈返回給客戶端

宿主機通過nat表的OUTPUT鏈是可以訪問container的80埠的

nat表的POSTROUTING規則使得container可以訪問外網

很奇怪的一條規則:
iptables -t nat -A POSTROUTING -s 172.17.0.2/32 -d 172.17.0.2/32 -p tcp -m tcp --dport 80 -j MASQUERADE
使得容器通過自己的IP172.17.0.2也可以訪問80埠

最後網上的一張流程圖:
在這裡插入圖片描述

相關文章