Advanced ruleset for dynamic environments: Difference between revisions

From nftables wiki
Jump to navigation Jump to search
(Started working on a more advanced config that supports service discovery)
 
m (Figured out and documented kernel versions for table creation implicit vs explicit)
 
(5 intermediate revisions by the same user not shown)
Line 3: Line 3:
Today's modern computing environments require features like Service Discovery and the environments themselves can be quite dynamic and rapidly changing. One of the ways nftables can help is by breaking firewall config into small pieces which can by dynamically generated by the likes of [https://www.consul.io/ Consul] and [https://www.hashicorp.com/blog/introducing-consul-template Consul Template], [https://www.vaultproject.io/ Vault], or config management like [https://www.chef.io/solutions/infrastructure-automation/ Chef] [https://puppet.com/ Puppet] or [https://www.ansible.com/ Ansible].
Today's modern computing environments require features like Service Discovery and the environments themselves can be quite dynamic and rapidly changing. One of the ways nftables can help is by breaking firewall config into small pieces which can by dynamically generated by the likes of [https://www.consul.io/ Consul] and [https://www.hashicorp.com/blog/introducing-consul-template Consul Template], [https://www.vaultproject.io/ Vault], or config management like [https://www.chef.io/solutions/infrastructure-automation/ Chef] [https://puppet.com/ Puppet] or [https://www.ansible.com/ Ansible].


An example use case would be if you had a number of servers, and you detected traffic on one host that you'd like to block across your entire fleet. You could add the IP to block into Consul, which will propagate it out and then Consul Template on each hosts updates nftables blacklist set definition with the new blacklisted IP and reloads nftables. Alternatively if you don't trust Consul due to the lack of an execution guarantee, you could put the blocked IP in an Ansible var and deploy it everywhere through your configuration management system.
By default your Systemd service file likely lives in ''/lib/systemd/system/'', the values suggested on this page are not default so you may wish to change those values. If you do, it's [https://unix.stackexchange.com/questions/206315/what-is-difference-between-usr-lib-and-etc-systemd best practice] to copy the nftables.service file to ''/etc/systemd/system'' where it will override the system-provided version without the need to modify files provided by the package.
There's nothing wrong with using a different layout, or even having everything in one file. This author prefers to split out rules and sets into individual files so that grouping them together by application or purpose is easier, you can use any configuration structure you wish.
'''''TODO:''''' Is ''/etc/nftables.start.conf'' really necessary? In a Debian test system on Linux 4.9.0, Debian Stretch, Nftables version v0.7, this file is not necessary - table creation is implicit from the table definition, for both 'inet' and 'ip' table types. This differs from my tests on the system I've lost access to at the moment, this needs to be explored once the host is reset. Note version numbers if the behaviour changed.




'''/etc/nftables.start.conf'''
'''/etc/nftables.start.conf'''
Creates tables
Creates tables
Loads /etc/nftables.conf
 
Loads ''/etc/nftables.conf''
 
Called from Systemd service file for nftables in ''ExecStart=''
 
The table creation statements are kept intentionally separate in this example so that its compatible with both config file formats. With the nftables-output config format, table creation statements cannot be used after the table is already created or an error is thrown, aborting the config reload.
 
'''Note:''' If you use Debian Stretch or a newer kernel (Linux Kernel >=4.9.0), this isn't necessary - the table creation will be handled implicitly so you can just add a 'flush ruleset' to ''/etc/nftables.conf'', update ''/etc/systemd/system/nftables.service'' so ''ExecStart='' points to ''/etc/nftables.conf'', and delete ''/etc/nftables.start.conf''.
 
Example contents of ''/etc/nft.conf.d/nftables.start.conf'':
 
<source lang="bash">
create table ip filter
create table ip nat
include "/etc/nftables.conf"
</source>
 


'''/etc/nftables.conf'''
'''/etc/nftables.conf'''
Loads table-specific entries like /etc/nft.conf.d/nftables.ip.filter.conf and /etc/nft.conf.d/nftables.ip.nat.conf
Loads Sets main file /etc/nft.conf.d/main.conf


'''/etc/nft.conf.d/main.conf'''
Loads table-specific entries like ''/etc/nft.conf.d/nftables.ip.filter.conf'' and ''/etc/nft.conf.d/nftables.ip.nat.conf''
Loads each individual Set, because nftables doesn't support wildcards in ''include'' statements (/etc/nft.conf.d/sets.d/trusted_ips.conf)
 
Loads Sets main file ''/etc/nft.conf.d/sets.d/main.conf''
 
Called from Systemd service file for nftables in ''ExecReload=''
 
Example content of ''/etc/nftables.conf'':
 
<source lang="bash">
include "/etc/nft.conf.d/sets.d/main.conf"
include "/etc/nft.conf.d/nftables.ip.filter.conf"
include "/etc/nft.conf.d/nftables.ip.nat.conf"
include "/etc/nft.conf.d/nftables.test1.conf"
include "/etc/nft.conf.d/nftables.test2.conf"
</source>
 
 
'''/etc/nft.conf.d/sets.d/main.conf'''
 
Loads each individual Set, because nftables doesn't support wildcards in ''include'' statements (yet?)
 
Called only from the include in ''/etc/nftables.conf''
 
Example content of ''/etc/nft.conf.d/sets.d/main.conf'':
 
<source lang="bash">
include "/etc/nft.conf.d/sets.d/trusted_ips1.conf"
include "/etc/nft.conf.d/sets.d/trusted_ips2.conf"
include "/etc/nft.conf.d/sets.d/family_ips.conf"
</source>
 
Example of an included set ''/etc/nft.conf.d/sets.d/trusted_ips1.conf'':
 
<source lang="bash">
table ip filter {
set trusted_ips {
type ipv4_addr
elements = { 192.168.1.1}
}
}
</source>
 
Example of included set ''/etc/nft.conf.d/sets.d/trusted_ips2.conf'':
 
<source lang="bash">
table ip filter {
set trusted_ips {
type ipv4_addr
elements = { 192.168.2.2}
}
}
</source>
 
Example of included set ''/etc/nft.conf.d/sets.d/family_ips.conf'':
 
<source lang="bash">
table ip filter {
set family_ips {
type ipv4_addr
elements = { 192.168.3.3}
}
}
</source>
 
Example of how the configuration is combined:
 
<source lang="bash">
% nft list table ip filter
table ip filter {
set trusted_ips {
type ipv4_addr
elements = { 192.168.2.2, 192.168.1.1}
}
set family_ips {
type ipv4_addr
elements = { 192.168.3.3}
}
}
</source>
 


'''/etc/nft.conf.d/nftables.ip.filter.conf'''
'''/etc/nft.conf.d/nftables.ip.filter.conf'''
Configures the 'ip filter' table
Configures the 'ip filter' table
Called from ''/etc/nftables.conf''
Example content:
<source lang="bash">
flush table ip filter
table ip filter {
set trusted_ips {
type ipv4_addr
elements = { 192.168.2.2, 192.168.1.1}
}
chain input {
#This is required to get input traffic to process this chain
type filter hook input priority 0; policy drop;
#Accept all traffic from the LAN, and any traffic related to already-active connections
ip saddr 192.168.1.0/24 counter packets 0 bytes 0 accept
ct state established,related counter packets 6471 bytes 337740 accept
#Accept SSH connections from everywhere, not just the LAN
tcp dport ssh counter packets 0 bytes 0 accept
#We want logs of the drops. If you don't, remove this line.
log prefix "nft-input-drop " level debug counter packets 112 bytes 8404 drop
}
chain output {
#This is required to get output traffic to process this chain
type filter hook output priority 0; policy drop;
#Accept all outbound traffic
oif "eth1" counter packets 0 bytes 0 accept
#We want logs of the drops. If you don't, remove this line.
log prefix "nft-output-drop " level debug counter packets 0 bytes 0 drop
}
chain forward {
#This is required to get forward traffic to process this chain
type filter hook forward priority 0; policy drop;
#We want logs of the drops. If you don't, remove this line.
log prefix "nft-forward-drop " level debug counter packets 104 bytes 4910 drop
}
}
</source>


'''/etc/nft.conf.d/nftables.ip.nat.conf'''
'''/etc/nft.conf.d/nftables.ip.nat.conf'''
Configures the 'ip nat' table
Configures the 'ip nat' table
Called from ''/etc/nftables.conf''
Example contents of ''/etc/nft.conf.d/nftables.ip.nat.conf'':
<source lang="bash">
flush table nat
table ip nat {
  chain prerouting {
    type filter hook prerouting priority 0
  }
  chain postrouting {
    type filter hook postrouting priority 100
  }
}
</source>

Latest revision as of 01:32, 27 January 2018

This page is an unvetted draft

Today's modern computing environments require features like Service Discovery and the environments themselves can be quite dynamic and rapidly changing. One of the ways nftables can help is by breaking firewall config into small pieces which can by dynamically generated by the likes of Consul and Consul Template, Vault, or config management like Chef Puppet or Ansible.

An example use case would be if you had a number of servers, and you detected traffic on one host that you'd like to block across your entire fleet. You could add the IP to block into Consul, which will propagate it out and then Consul Template on each hosts updates nftables blacklist set definition with the new blacklisted IP and reloads nftables. Alternatively if you don't trust Consul due to the lack of an execution guarantee, you could put the blocked IP in an Ansible var and deploy it everywhere through your configuration management system.

By default your Systemd service file likely lives in /lib/systemd/system/, the values suggested on this page are not default so you may wish to change those values. If you do, it's best practice to copy the nftables.service file to /etc/systemd/system where it will override the system-provided version without the need to modify files provided by the package.

There's nothing wrong with using a different layout, or even having everything in one file. This author prefers to split out rules and sets into individual files so that grouping them together by application or purpose is easier, you can use any configuration structure you wish.

TODO: Is /etc/nftables.start.conf really necessary? In a Debian test system on Linux 4.9.0, Debian Stretch, Nftables version v0.7, this file is not necessary - table creation is implicit from the table definition, for both 'inet' and 'ip' table types. This differs from my tests on the system I've lost access to at the moment, this needs to be explored once the host is reset. Note version numbers if the behaviour changed.


/etc/nftables.start.conf

Creates tables

Loads /etc/nftables.conf

Called from Systemd service file for nftables in ExecStart=

The table creation statements are kept intentionally separate in this example so that its compatible with both config file formats. With the nftables-output config format, table creation statements cannot be used after the table is already created or an error is thrown, aborting the config reload.

Note: If you use Debian Stretch or a newer kernel (Linux Kernel >=4.9.0), this isn't necessary - the table creation will be handled implicitly so you can just add a 'flush ruleset' to /etc/nftables.conf, update /etc/systemd/system/nftables.service so ExecStart= points to /etc/nftables.conf, and delete /etc/nftables.start.conf.

Example contents of /etc/nft.conf.d/nftables.start.conf:

create table ip filter
create table ip nat
include "/etc/nftables.conf"


/etc/nftables.conf

Loads table-specific entries like /etc/nft.conf.d/nftables.ip.filter.conf and /etc/nft.conf.d/nftables.ip.nat.conf

Loads Sets main file /etc/nft.conf.d/sets.d/main.conf

Called from Systemd service file for nftables in ExecReload=

Example content of /etc/nftables.conf:

include "/etc/nft.conf.d/sets.d/main.conf"
include "/etc/nft.conf.d/nftables.ip.filter.conf"
include "/etc/nft.conf.d/nftables.ip.nat.conf"
include "/etc/nft.conf.d/nftables.test1.conf"
include "/etc/nft.conf.d/nftables.test2.conf"


/etc/nft.conf.d/sets.d/main.conf

Loads each individual Set, because nftables doesn't support wildcards in include statements (yet?)

Called only from the include in /etc/nftables.conf

Example content of /etc/nft.conf.d/sets.d/main.conf:

include "/etc/nft.conf.d/sets.d/trusted_ips1.conf"
include "/etc/nft.conf.d/sets.d/trusted_ips2.conf"
include "/etc/nft.conf.d/sets.d/family_ips.conf"

Example of an included set /etc/nft.conf.d/sets.d/trusted_ips1.conf:

table ip filter {
	set trusted_ips {
		type ipv4_addr
		elements = { 192.168.1.1}
	}
}

Example of included set /etc/nft.conf.d/sets.d/trusted_ips2.conf:

table ip filter {
	set trusted_ips {
		type ipv4_addr
		elements = { 192.168.2.2}
	}
}

Example of included set /etc/nft.conf.d/sets.d/family_ips.conf:

table ip filter {
	set family_ips {
		type ipv4_addr
		elements = { 192.168.3.3}
	}
}

Example of how the configuration is combined:

% nft list table ip filter
table ip filter {
	set trusted_ips {
		type ipv4_addr
		elements = { 192.168.2.2, 192.168.1.1}
	}
	set family_ips {
		type ipv4_addr
		elements = { 192.168.3.3}
	}
}


/etc/nft.conf.d/nftables.ip.filter.conf

Configures the 'ip filter' table

Called from /etc/nftables.conf

Example content:

flush table ip filter
table ip filter {
	set trusted_ips {
		type ipv4_addr
		elements = { 192.168.2.2, 192.168.1.1}
	}

	chain input {
		#This is required to get input traffic to process this chain
		type filter hook input priority 0; policy drop;

		#Accept all traffic from the LAN, and any traffic related to already-active connections
		ip saddr 192.168.1.0/24 counter packets 0 bytes 0 accept
		ct state established,related counter packets 6471 bytes 337740 accept

		#Accept SSH connections from everywhere, not just the LAN
		tcp dport ssh counter packets 0 bytes 0 accept

		#We want logs of the drops. If you don't, remove this line.
		log prefix "nft-input-drop " level debug counter packets 112 bytes 8404 drop
	}

	chain output {
		#This is required to get output traffic to process this chain
		type filter hook output priority 0; policy drop;

		#Accept all outbound traffic 
		oif "eth1" counter packets 0 bytes 0 accept

		#We want logs of the drops. If you don't, remove this line.
		log prefix "nft-output-drop " level debug counter packets 0 bytes 0 drop
	}

	chain forward {
		#This is required to get forward traffic to process this chain
		type filter hook forward priority 0; policy drop;

		#We want logs of the drops. If you don't, remove this line.
		log prefix "nft-forward-drop " level debug counter packets 104 bytes 4910 drop
	}
}


/etc/nft.conf.d/nftables.ip.nat.conf

Configures the 'ip nat' table

Called from /etc/nftables.conf

Example contents of /etc/nft.conf.d/nftables.ip.nat.conf:

flush table nat
table ip nat {
  chain prerouting {
    type filter hook prerouting priority 0
  }
  chain postrouting {
    type filter hook postrouting priority 100
  }
}