nftables 日志解決方案實踐

nftables 重要規(guī)則進(jìn)行日志記錄,并配置日志切割、nftables 規(guī)則固定到文件,保證重啟不丟失。
最后更新時間:2021/7/13
根據(jù)官方 wiki 中Logging traffic[1]這篇文章的說明:從 Linux 內(nèi)核 3.17 開始提供完整的日志支持。如果您運(yùn)行較舊的內(nèi)核,則必須 modprobe ipt_LOG 以啟用日志記錄。從 nftables v0.7 開始,支持 log 標(biāo)志。
那么我們的內(nèi)核是5.13.0-1.el7.elrepo.x86_64,nftables 版本是nftables v0.8 (Joe Btfsplk),應(yīng)該不需要手動加載內(nèi)核模塊。
前置條件:
openvpn 網(wǎng)卡 tun0、openvpn 用戶虛擬 IP 網(wǎng)段為 10.121.0.0/16;
wireguard 網(wǎng)卡 wg0、wireguard 虛擬 IP 網(wǎng)段 10.122.0.0/16;
1. nftables 規(guī)則創(chuàng)建及測試
我這邊需要在這臺 VPN 中樞服務(wù)器進(jìn)行路由轉(zhuǎn)發(fā)和控制,并且需要監(jiān)控哪個 VPN 用戶訪問了哪些服務(wù)的日志;
1.1. 簡單測試-權(quán)限粒度從 ip 到目的 ip.端口
首先測試確定的用戶虛擬 IP 到確定的服務(wù)器的控制轉(zhuǎn)發(fā)規(guī)則:
## 添加單條規(guī)則如下:
nft add rule ip nat POSTROUTING oifname eth0 ip saddr 10.121.6.6 ip daddr 192.168.5.71 counter log masquerade
nft add rule ip nat POSTROUTING oifname eth0 ip saddr 10.121.6.6 ip daddr 10.10.210.9 counter log masquerade
## 查詢到的規(guī)則如下
table ip filter {
chain INPUT {
type filter hook input priority 0; policy accept;
counter packets 248456 bytes 62354809 ## handle 4
}
chain FORWARD {
type filter hook forward priority 0; policy accept;
iifname "wg0" counter packets 97 bytes 6924 accept ## handle 5
oifname "wg0" counter packets 121 bytes 7776 accept ## handle 6
}
chain OUTPUT {
type filter hook output priority 0; policy accept;
}
}
table ip nat {
chain PREROUTING {
type nat hook prerouting priority 0; policy accept;
}
chain INPUT {
type nat hook input priority 0; policy accept;
}
chain OUTPUT {
type nat hook output priority 0; policy accept;
}
chain POSTROUTING {
type nat hook postrouting priority 0; policy accept;
counter packets 76584 bytes 5488498 ## handle 7
oifname "eth0" ip saddr 10.121.6.6 ip daddr 192.168.5.71 counter packets 1 bytes 60 log masquerade ## handle 27
oifname "eth0" ip saddr 10.121.6.6 ip daddr 10.10.210.9 counter packets 0 bytes 0 log masquerade ## handle 28
}
}
openvpn 客戶端 ping 10.10.210.9 和 192.168.5.71 測試,查看日志 tail -100f /var/log/nftables.log,需要先做第二步驟的日志設(shè)置
值得注意的是,短時間內(nèi)再次 ping 同一個 IP 的話,不會出現(xiàn)新的記錄,conntrack -E看也是一樣的,有網(wǎng)友說可能是按照比例輸出的日志,后面根據(jù)生產(chǎn)經(jīng)驗看其實日志是有的,只不過 tail 沒全部展現(xiàn)。
Jul 9 17:32:12 test-openvpn kernel: IN=tun0 OUT=eth0 MAC= SRC=10.121.6.6 DST=10.10.210.9 LEN=60 TOS=0x00 PREC=0x00 TTL=127 ID=59753 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=716
Jul 9 17:32:17 test-openvpn kernel: IN=tun0 OUT=eth0 MAC= SRC=10.121.6.6 DST=192.168.5.71 LEN=60 TOS=0x00 PREC=0x00 TTL=127 ID=36231 PROTO=ICMP TYPE=8 CODE=0 ID=1 SEQ=720
1.2. 權(quán)限粒度控制到網(wǎng)段
若要對用戶以及目的地址進(jìn)行批量配置和控制用戶可以目的地址的粒度
需要新增VPN 用戶虛擬 IP 集合、目的服務(wù)集合(粒度到端口)、目的服務(wù)器(粒度服務(wù)器或網(wǎng)段);
然后用三條規(guī)則控制這樣的處理流程。以下是三個集合的創(chuàng)建和新增規(guī)則過程【只需要關(guān)注 nat 表的 POSTROUTING 鏈即可】:
我們需要將剛才的表刪掉nft delete table filter、nft delete table nat,并從頭創(chuàng)建覆蓋范圍更廣的通用規(guī)則:
## -i參數(shù)進(jìn)入交互模式 從頭開始創(chuàng)建表filter、nat以及鏈和新增規(guī)則
nft -i
add table ip filter
add chain ip filter INPUT { type filter hook input priority 0; policy accept; }
add chain ip filter FORWARD { type filter hook forward priority 0; policy accept; }
add chain ip filter OUTPUT { type filter hook output priority 0; policy accept; }
add table ip nat
add chain ip nat PREROUTING { type nat hook prerouting priority 0; policy accept; }
add chain ip nat INPUT { type nat hook input priority 0; policy accept; }
add chain ip nat OUTPUT { type nat hook output priority 0; policy accept; }
add chain ip nat POSTROUTING { type nat hook postrouting priority 0; policy accept; }
## 測量流量
add rule filter INPUT counter
add rule nat POSTROUTING counter
## 決定是否增加的測試規(guī)則
add rule ip nat POSTROUTING oifname eth0 ip saddr 10.11.6.6 ip daddr 192.168.5.71 counter masquerade
add rule ip nat POSTROUTING oifname eth0 ip saddr 10.11.6.6 ip daddr 10.10.210.18 counter masquerade
## 允許wg0網(wǎng)卡轉(zhuǎn)發(fā)流量
add rule filter FORWARD iifname wg0 counter accept
add rule filter FORWARD oifname wg0 counter accept
## user_vips 用戶虛擬IP
add set nat user_vips { type ipv4_addr \; flags interval\; }
## dest_addrs 目標(biāo)地址/網(wǎng)段
add set nat dest_addrs { type ipv4_addr \; flags interval\; }
## 查看 退出i交互模式操作
nft list ruleset
## 【核心地址】
## 添加用戶虛擬地址 若想直接給所有虛擬用戶添加,則需要刪除單個ip,添加成10.121.0.0/16
nft add element nat user_vips { 10.121.6.6, 10.121.6.7 }
##查看結(jié)果
nft list set nat user_vips
## 添加目標(biāo)服務(wù)【粒度到端口協(xié)議】 【這里此階段沒有測試!】
nft add element nat dest_svcs { 192.168.5.15 . tcp . 80, 192.168.5.15 . tcp . 22 }
## 添加目標(biāo)網(wǎng)段【粒度粗一些】【此階段測試了】
nft add element nat dest_addrs { 10.10.210.99, 192.168.5.77 }
##查看結(jié)果
nft list set nat dest_addrs
## 【核心規(guī)則】
## tun0 進(jìn) 精確到端口 tcp協(xié)議
nft insert rule ip nat POSTROUTING oifname eth0 counter log ip saddr @user_vips ip daddr . meta l4proto . tcp dport @dest_svcs masquerade
## tun0 進(jìn) 精確到端口 udp協(xié)議
nft insert rule ip nat POSTROUTING oifname eth0 counter log ip saddr @user_vips ip daddr . meta l4proto . udp dport @dest_svcs masquerade
## tun0 進(jìn) eth0 出
nft insert rule ip nat POSTROUTING oifname eth0 counter log ip saddr @user_vips ip daddr @dest_addrs masquerade
## tun0 進(jìn) wg0 出
nft insert rule ip nat POSTROUTING oifname wg0 counter log ip saddr @user_vips ip daddr @dest_addrs masquerade
##查看結(jié)果
nft list ruleset -a -nn
table ip filter {
chain INPUT {
type filter hook input priority 0; policy accept;
counter packets 1245244 bytes 478473640 ## handle 4
}
chain FORWARD {
type filter hook forward priority 0; policy accept;
iifname "wg0" counter packets 429596 bytes 254444866 accept ## handle 5
oifname "wg0" counter packets 566722 bytes 80498891 accept ## handle 6
}
chain OUTPUT {
type filter hook output priority 0; policy accept;
}
}
table ip nat {
set user_vips {
type ipv4_addr
flags interval
elements = { 10.121.6.6, 10.121.6.7 }
}
set dest_svcs {
type ipv4_addr . inet_proto . inet_service
}
set dest_addrs {
type ipv4_addr
flags interval
elements = { 10.10.210.99, 192.168.5.77 }
}
chain PREROUTING {
type nat hook prerouting priority 0; policy accept;
}
chain INPUT {
type nat hook input priority 0; policy accept;
}
chain OUTPUT {
type nat hook output priority 0; policy accept;
}
chain POSTROUTING {
type nat hook postrouting priority 0; policy accept;
oifname "eth0" counter packets 2010 bytes 128703 log ip saddr @user_vips ip daddr @dest_addrs masquerade ## handle 14
oifname "wg0" counter packets 24631 bytes 1400846 log ip saddr @user_vips ip daddr @dest_addrs masquerade ## handle 13
counter packets 26604 bytes 1536440 ## handle 5
}
}
## 若以后nat表POSTROUTING鏈的規(guī)則粒度改成了更細(xì)的粒度,規(guī)則數(shù)目會變成人數(shù)*服務(wù)端口數(shù) 查詢可以這么曬選
nft list table ip nat -a | grep "10.121.0.3"
2. 日志設(shè)置
簡單配置并重啟rsyslog服務(wù),則 nftables 規(guī)則中寫了 log 標(biāo)志及符合正則的事件流將會出現(xiàn)在日志文件中。
vim /etc/rsyslog.d/nftables.conf
## 寫入以下內(nèi)容 此處的配置將匹配conntrack中符合正則的日志
:msg,regex,"IN=.*OUT=.*SRC=.*DST=.*" -/var/log/nftables.log
## 重啟日志服務(wù)
systemctl restart rsyslog
## 查看日志
tail -100f /var/log/nftables.log
如何對日志文件進(jìn)行管理呢?這就用到了日志切割:參考博客https://zhuanlan.zhihu.com/p/90507023
## 為nftables和openvpn設(shè)置切割規(guī)則,無需重啟logrotate服務(wù) 因為nftables生產(chǎn)上有測試機(jī)器瘋狂訪問數(shù)據(jù)庫,這里清理日志改成每3月
vim /etc/logrotate.d/nftables
/var/log/nftables.log {
monthly
rotate 3
dateext
compress
delaycompress
missingok
notifempty
create 644 root root
postrotate
/usr/bin/killall -HUP rsyslogd
endscript
}
## openvpn日志也類似
vim /etc/logrotate.d/openvpn
/var/log/openvpn.log {
monthly
rotate 5
dateext
compress
delaycompress
missingok
notifempty
create 644 root root
postrotate
/usr/bin/killall -HUP rsyslogd
endscript
}
## 手動測試
logrotate -vf /etc/logrotate.d/nftables
logrotate -vf /etc/logrotate.d/openvpn
## 測試結(jié)果
-rw-r--r-- 1 root root 69619 Jul 12 15:06 nftables.log
-rw------- 1 root root 5959277 Jul 12 14:55 nftables.log-20210712
-rw-r--r-- 1 root root 0 Jul 12 14:57 openvpn.log
-rw------- 1 root root 118663677 Jul 12 15:10 openvpn.log-20210712
## 規(guī)則說明
rotate 5 保留五個備份;dateext每次切割結(jié)果后面加上日期
考慮到nftables流量會很大的話,可以只存三個月、或者改成每周切割一次
3. nft 規(guī)則的備份恢復(fù)
若要臨時備份規(guī)則,請如下操作:
## 備份
nft list ruleset >> backup.nft
## 恢復(fù)(原子性)
nft -f backup.nft
若想達(dá)成 nft 規(guī)則開機(jī)自動恢復(fù)的效果,需要將上面文件中的規(guī)則保存到/etc/sysconfig/nftables.conf
這樣重啟后無需做任何操作(wireguard、openvpn、nftables 都自動恢復(fù));
缺點(diǎn):需要每次服務(wù)器重啟前盡量將最新的規(guī)則覆蓋更新到此文件中,這點(diǎn)暫時未考慮方案~
目前的全部規(guī)則如下,ICMP 和 22 端口咱們用云服務(wù)器的安全組作了限制,不允許外部訪問!
table ip filter {
chain INPUT {
type filter hook input priority 0; policy accept;
counter packets 22510792 bytes 7510722663 ## handle 4
}
chain FORWARD {
type filter hook forward priority 0; policy accept;
iifname "wg0" counter packets 10352763 bytes 4340019433 accept ## handle 5
oifname "wg0" counter packets 10642518 bytes 1781990328 accept ## handle 6
oifname "eth0" log counter packets 26348 bytes 1381110 accept ## handle 8
iifname "eth0" log counter packets 23762 bytes 57192818 accept ## handle 9
}
chain OUTPUT {
type filter hook output priority 0; policy accept;
}
}
table ip nat {
set user_vips {
type ipv4_addr
flags interval
elements = { 10.111.0.0/16, 10.122.0.0/16 }
}
set dest_svcs {
type ipv4_addr . inet_proto . inet_service
}
set dest_addrs {
type ipv4_addr
flags interval
elements = { 10.1.0.0-10.3.255.255, 10.10.0.0/16,
192.168.0.0/16 }
}
chain PREROUTING {
type nat hook prerouting priority 0; policy accept;
}
chain INPUT {
type nat hook input priority 0; policy accept;
}
chain OUTPUT {
type nat hook output priority 0; policy accept;
}
chain POSTROUTING {
type nat hook postrouting priority 0; policy accept;
oifname "eth0" counter packets 10674 bytes 669286 log ip saddr @user_vips ip daddr @dest_addrs masquerade ## handle 14
oifname "wg0" counter packets 272649 bytes 14720638 log ip saddr @user_vips ip daddr @dest_addrs masquerade ## handle 13
counter packets 35014 bytes 2061579 ## handle 5
}
}
4.未成功的方案(ulogd & ulogd2)
因為系統(tǒng)環(huán)境是 centos7,不是 debian,所以 yum 源沒有匹配ulogd的軟件;于是需求 netfilter 官網(wǎng)下載包,編譯安裝的方式:
## 下載ulogd包并編譯安裝
cd /opt
curl -O https://www.netfilter.org/projects/ulogd/files/ulogd-2.0.7.tar.bz2
tar xvf ulogd-2.0.7.tar.bz2
cd ulogd-2.0.7
./configure
## 編譯報錯 沒有l(wèi)ibnetfilter_acct包
configure: error: Package requirements (libnetfilter_acct >= 1.0.1) were not met:
No package 'libnetfilter_acct' found
## 于是又去官網(wǎng)找libnetfilter_acct
https://www.netfilter.org/projects/libnetfilter_acct/downloads.html
## 下載源碼包 編譯安裝 沒有任何報錯
curl -O https://www.netfilter.org/projects/libnetfilter_acct/files/libnetfilter_acct-1.0.3.tar.bz2
tar xvf libnetfilter_acct-1.0.3.tar.bz2
cd libnetfilter_acct-1.0.3
./configure
make && make install
## 但是此時再回去編譯ulogd2還是報一樣的錯誤找不到libnetfilter_acct包
## 這里并不了解是不是因為源碼編譯安裝包后需要讓系統(tǒng)知道安裝完的包有哪些,我理解make & install后系統(tǒng)會識別出來的;
如果有任何想法的前輩請告訴我!感激無比~
5. 設(shè)置 nf_log 內(nèi)核參數(shù)【未用到】
未修改過內(nèi)核日志模塊的機(jī)器
sudo sysctl -a | grep nf_log
sysctl: reading key "net.ipv6.conf.all.stable_secret"
sysctl: reading key "net.ipv6.conf.default.stable_secret"
sysctl: reading key "net.ipv6.conf.eth0.stable_secret"
sysctl: reading key "net.ipv6.conf.lo.stable_secret"
sysctl: reading key "net.ipv6.conf.wg0.stable_secret"
net.netfilter.nf_log.0 = NONE
net.netfilter.nf_log.1 = NONE
net.netfilter.nf_log.10 = NONE
net.netfilter.nf_log.11 = NONE
net.netfilter.nf_log.12 = NONE
net.netfilter.nf_log.2 = NONE
net.netfilter.nf_log.3 = NONE
net.netfilter.nf_log.4 = NONE
net.netfilter.nf_log.5 = NONE
net.netfilter.nf_log.6 = NONE
net.netfilter.nf_log.7 = NONE
net.netfilter.nf_log.8 = NONE
net.netfilter.nf_log.9 = NONE
net.netfilter.nf_log_all_netns = 0
測試機(jī)器(自己折騰過日志內(nèi)核,發(fā)現(xiàn)不需要折騰)
sysctl -a | grep nf_log
sysctl: reading key "net.ipv6.conf.all.stable_secret"
sysctl: reading key "net.ipv6.conf.default.stable_secret"
sysctl: reading key "net.ipv6.conf.eth0.stable_secret"
sysctl: reading key "net.ipv6.conf.lo.stable_secret"
sysctl: reading key "net.ipv6.conf.wg0.stable_secret"
net.netfilter.nf_log.0 = NONE
net.netfilter.nf_log.1 = NONE
net.netfilter.nf_log.10 = nf_log_ipv6
net.netfilter.nf_log.11 = NONE
net.netfilter.nf_log.12 = NONE
net.netfilter.nf_log.2 = nf_log_ipv4
net.netfilter.nf_log.3 = nf_log_arp
net.netfilter.nf_log.4 = NONE
net.netfilter.nf_log.5 = nf_log_netdev
net.netfilter.nf_log.6 = NONE
net.netfilter.nf_log.7 = nf_log_bridge
net.netfilter.nf_log.8 = NONE
net.netfilter.nf_log.9 = NONE
net.netfilter.nf_log_all_netns = 0
6. 參考資料
Steve Suehring 的《Linux Firewalls_ Enhancing Security with nftables and Beyond-Addison-Wesley Professional》這本書中對防火墻有充分的介紹,很多方面都有可借鑒之處 設(shè)置 nf_log 內(nèi)核參數(shù)[2] (最終沒用到) 連接跟蹤(conntrack):原理、應(yīng)用及 Linux 內(nèi)核實現(xiàn)[3]
腳注
Logging traffic: https://wiki.nftables.org/wiki-nftables/index.php/Logging_traffic
[2]設(shè)置 nf_log 內(nèi)核參數(shù): https://forums.centos.org/viewtopic.php?t=54411#p230026
[3]連接跟蹤(conntrack):原理、應(yīng)用及 Linux 內(nèi)核實現(xiàn): https://cloud.tencent.com/developer/article/1761367


你可能還喜歡
點(diǎn)擊下方圖片即可閱讀

云原生是一種信仰 ??
關(guān)注公眾號
后臺回復(fù)?k8s?獲取史上最方便快捷的 Kubernetes 高可用部署工具,只需一條命令,連 ssh 都不需要!


點(diǎn)擊 "閱讀原文" 獲取更好的閱讀體驗!
發(fā)現(xiàn)朋友圈變“安靜”了嗎?


