rss logo

Managing nftables Logs with Rsyslog and Logrotate

Rsyslog Logo

Intro

For legal obligations on an open public network, I had to work on connection log management. The architecture was based on a Debian 12 bookworm, which served as an Internet gateway for the clients, with nftables for the firewall. The aim was to log all packets passing through the router, retrieving the following informations: mac addresses, destination IPs and protocols used.

  • My requirements were quite simple:
    • Separate the nftables logs and save them in a specific file.
    • To have a yearly rotation of collected nftables logs.

The problem is that now, with the implementation of systemd, all system messages are handled by it. Unfortunately, this isn't very configurable (or maybe I'm juste a big dummy 😅). Indeed, I haven't found a way to do what I've outlined above with systemd. To meet my needs, I used Rsyslog to sort log messages and logrotate to manage the history. To be quite precise, Rsyslog doesn't replace systemd/journal, in fact it will just retrieve the logs from the latter and enable us to meet the needs set out above.

Control systemd/journal size

Depending on the number of clients and their usage, the size of the systemd/journal file can be very large in a short space of time. By default, its size is limited to 10% of the size of the underlying file system and capped at 4 GiB. See here for more information: https://wiki.archlinux.org/. In any case, I'll first set the maximum size of the systemd/journal to 1 GiB maximum. As explained, we don't really need it anymore, as Rsyslog will write the same events to /var/logs/syslog and (this is what we'll set) to /var/logs/nftables/ for nftables logs.

  • To limit the size of systemd/journal to 1 GiB, edit /etc/systemd/journald.conf:
SystemMaxUse=1G
  • And restart the systemd/journal service:
root@host:~# systemctl restart systemd-journald.service

Configuring Rsyslog

  • Install the Rsyslog package:
root@host:~# apt install rsyslog
  • Create an nftables directory for logs:
root@host:~# mkdir /var/log/nftables/
  • And edit the /etc/rsyslog.conf file:
# /etc/rsyslog.conf configuration file for rsyslog # # For more information install rsyslog-doc and see # /usr/share/doc/rsyslog-doc/html/configuration/index.html ################# #### MODULES #### ################# module(load="imuxsock") # provides support for local system logging module(load="imklog") # provides kernel logging support #module(load="immark") # provides --MARK-- message capability # provides UDP syslog reception #module(load="imudp") #input(type="imudp" port="514") # provides TCP syslog reception #module(load="imtcp") #input(type="imtcp" port="514") ########################### #### GLOBAL DIRECTIVES #### ########################### # # Set the default permissions for all log files. # $FileOwner root $FileGroup adm $FileCreateMode 0640 $DirCreateMode 0755 $Umask 0022 # # Where to place spool and state files # $WorkDirectory /var/spool/rsyslog # # Include all config files in /etc/rsyslog.d/ # $IncludeConfig /etc/rsyslog.d/*.conf ############### #### RULES #### ############### # the regex rule below corresponds to traditional nftables logs, which take the following form: IN=interface1 OUT=interface2. # Each “match” will be written to /var/log/nftables/nftables.log :msg, regex, "IN=[A-Za-z0-9_]* OUT=" -/var/log/nftables/nftables.log # & stop means that the match will not write to another file & stop # # Log anything besides private authentication messages to a single log file # *.*;auth,authpriv.none -/var/log/syslog # # Log commonly used facilities to their own log file # auth,authpriv.* /var/log/auth.log cron.* -/var/log/cron.log kern.* -/var/log/kern.log mail.* -/var/log/mail.log user.* -/var/log/user.log # # Emergencies are sent to everybody logged in. # *.emerg :omusrmsg:*
  • Restart the Rsyslog service so that the new configuration is taken into account:
root@host:~# systemctl restart rsyslog

Configuring logrotate

  • Edit the /etc/logrotate.d/rsyslog file:
/etc/logrotate.d/rsyslog /var/log/syslog /var/log/mail.log /var/log/kern.log /var/log/auth.log /var/log/user.log /var/log/cron.log { rotate 4 weekly missingok notifempty compress delaycompress sharedscripts postrotate /usr/lib/rsyslog/rsyslog-rotate endscript } /var/log/nftables/nftables.log { rotate 365 size 100M daily missingok notifempty compress delaycompress postrotate /usr/lib/rsyslog/rsyslog-rotate endscript dateext dateformat .%Y.%m.%d dateyesterday }
  • Explanation of the different options:
    • rotate 365: Keeps up to 365 rotated log files. Older logs beyond this number will be deleted.
    • size 100M: Rotates the log file when it reaches 100 MB in size.
    • daily: Specifies daily rotation of the log file.
    • missingok: Skips errors and warnings if the log file is missing.
    • notifempty: Does not rotate the log file if it is empty.
    • compress: Compresses rotated log files to save space.
    • delaycompress: Delays compression of the most recent rotated log until the next rotation cycle.
    • postrotate: Reloads rsyslog to ensure it uses the newly rotated log file.
    • dateext: Adds a date-based extension to the rotated log files.
    • dateformat .%Y.%m.%d: Specifies the date format for the log file extension as Year.Month.Day.
    • dateyesterday: Uses yesterday's date for the date extension on the rotated logs.
  • Restart the logrotate service:
root@host:~# systemctl restart logrotate.service

Configure nftables to create logs on specific rules

As explained, I needed to record the mac addresses, the protocols and the IP addresses. To do so, we juste need to add the mention log flags ether on our nftables rules. Use all to enable all flags. See official page to see others flags here: https://wiki.nftables.org/wiki-nftables/.

  • For example in a full nftables configuration:
#!/usr/sbin/nft -f flush ruleset table inet filter { chain input { type filter hook input priority 0; policy accept; } chain forward { type filter hook forward priority 0; policy drop; #by default, we drop traffic ct state invalid drop ip saddr 192.168.1.0/24 tcp dport { http, https } ct state { new, related, established } counter log flags ether accept comment "accept WEB" ip saddr 192.168.1.0/24 udp dport { domain, ntp } ct state { new, related, established } counter log flags ether accept comment "DNS" ip saddr 192.168.1.0/24 icmp type { echo-reply, echo-request} counter log flags ether accept comment "allow icmp" ip daddr 192.168.1.0/24 ct state { established, related } counter accept } chain output { type filter hook output priority 0; policy accept; } } table ip my_nat { chain my_masquerade { type nat hook postrouting priority 100; policy accept; ip daddr != { 192.168.1.0/24 } oifname "wan" masquerade comment "outgoing NAT" } }
  • Reload nftables rules:
root@host:~# nft -f /etc/nftables.conf
  • You should see a file appear in your /var/log/nftables folder:
root@host:~# ls /var/log/nftbles/ total 1,9G -rw-r----- 1 root adm 457M 6 déc. 20:14 nftables.log

Note the size of the log file, which is larger than the size defined in the /etc/logrotate.d/rsyslog configuration file. This is because logrotate is run once a day. It is not triggered once a condition is met, but only if it is met when it is run at 00:00.

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Contact :

contact mail address