{"id":70,"date":"2020-09-23T11:50:13","date_gmt":"2020-09-23T10:50:13","guid":{"rendered":"https:\/\/www.xciv.org\/blog\/?p=70"},"modified":"2020-09-23T15:19:42","modified_gmt":"2020-09-23T14:19:42","slug":"debian-migration-to-nftables","status":"publish","type":"post","link":"https:\/\/www.xciv.org\/blog\/2020\/09\/23\/debian-migration-to-nftables\/","title":{"rendered":"Debian migration to nftables"},"content":{"rendered":"\n<p>If you have upgraded to Debian 10 buster you will know (if you have read the <a href=\"https:\/\/www.debian.org\/releases\/buster\/releasenotes\">release notes<\/a>) that Debian has now migrated to the nftables filtering framework.<\/p>\n\n\n\n<p>See <em>2.2.6.&nbsp;Network filtering based on nftables framework by default<\/em><\/p>\n\n\n\n<p>What is not covered is how you do this and what it really means.<\/p>\n\n\n\n<p>The release notes say &#8220;<em>nftables provides a full replacement for iptables<\/em>&#8221; and this is almost true but not quite and I&#8217;ll come on to that at the end.<\/p>\n\n\n\n<p>First off, it should be noted that what we&#8217;re actually really doing is changing  our filtering ruleset from being defined in iptables format to being defined in nftables format.<\/p>\n\n\n\n<p>To convert our existing iptables ruleset to nftables we first need to save a copy of our iptables rulesets:<\/p>\n\n\n\n<p><code>iptables-save &gt; iptables-active.txt<br>ip6tables-save &gt; iptables6-active.txt<\/code><\/p>\n\n\n\n<p>Once we have these we can convert them to nftables:<\/p>\n\n\n\n<p><code>iptables-restore-translate -f iptables-active.txt &gt; nftables-active.txt<br>ip6tables-restore-translate -f iptables6-active.txt &gt; nftables6-active.txt<\/code><\/p>\n\n\n\n<p>You can use these auto translated rulesets, or&#8230;<\/p>\n\n\n\n<p>Now comes a big change, nftables is dual stack v4\/v6 capable so you can merge a lot of your rules into single statements rather than have two completely separate sets of rules.<\/p>\n\n\n\n<p>However, the new functionality can&#8217;t cope with a completely combined ruleset if you are doing more complex filtering, simply because IPv4 and IPv6 work differently.<\/p>\n\n\n\n<p>That said, I have managed to condense two completely separate rulesets down to one ruleset with three duplicate rules in one file. This is definitely easier to manage.<\/p>\n\n\n\n<p>The new rulesets live in the <code>\/etc\/nftables.conf<\/code> file and this is an executable \u2014 it&#8217;s actually a script to perform an atomic update, that is, when you run it the rules are parsed and if there are any errors the whole ruleset update is rejected.<\/p>\n\n\n\n<p>This is a useful change as it means that you can&#8217;t apply half a ruleset if you have a typo or syntax error. Either the rules install in whole or they don&#8217;t.<\/p>\n\n\n\n<p>On my system I moved the stock empty rules file to <code>\/etc\/nftables.conf.clear<\/code> to retain a quick fallback script to clear the whole ruleset if ever needed.<\/p>\n\n\n\n<p>If you are using <code>iptables-persistent<\/code> to install your old iptables rulesets you should now remove this package (or your alternative startup method) and reboot.<\/p>\n\n\n\n<p>Once you&#8217;ve confirmed that the iptables rules are no longer loaded from startup you can run <code>\/etc\/nftables.conf<\/code> to load your new nftables ruleset.<\/p>\n\n\n\n<p>(if you aren&#8217;t 100% sure about your new nftables ruleset it might be an idea to run a <code>sleep 30; \/etc\/nftables.conf.clear<\/code> in a screen session to automatically clear the rules to prevent you being locked out)<\/p>\n\n\n\n<p>Once this is all working you can use systemd to load the nftables rules at boot:<\/p>\n\n\n\n<p><code>systemctl enable nftables.service<\/code><\/p>\n\n\n\n<p>Finally there is a proper built-in method of installing filtering rules at boot! You have to wonder why that has taken so long.<\/p>\n\n\n\n<p>At this point having migrated to nftables it&#8217;s tempting to remove the iptables package and you can do so, but there is a problem. As soon as you do this apt will start telling you that none of the nftables packages are needed and that they can be removed with apt-get autoremove.<\/p>\n\n\n\n<p>This is why this &#8216;migration&#8217; to iptables is not quite how it seems, you do need to retain the iptables package if only for one reason.. to keep the nftables packages installed.<\/p>\n\n\n\n<p>One side effect of retaining the iptables package is you can end up with an empty ruleset in nftables that is not used.<\/p>\n\n\n\n<p><code># nft list tables<br>table inet Firewall<br>table ip filter<\/code><\/p>\n\n\n\n<p>This all seems slightly strange. Intentional? Oversight? I don&#8217;t know but my limited testing shows that nftables works fine without the iptables package, it&#8217;s just a risk that you&#8217;ll end up losing all your nftables packages through apt-get autoremove if you don&#8217;t retain the iptables package.<\/p>\n\n\n\n<p>Aside from that nft seems to work well, for me the ruleset syntax is better and easier to manage.<\/p>\n\n\n\n<p>I&#8217;ve included an example v4\/v6 combined ruleset below.<\/p>\n\n\n\n<p><code> #!\/usr\/sbin\/nft -f<br> <br> # Define intefaces<br> define LAN_EXT = eth0<br> <br> # Flush everything<br> flush ruleset<br> <br> # Defaults<br> add table inet xciv<br> add chain inet xciv OUTPUT { type filter hook output priority 0; policy accept; }<br> add chain inet xciv INPUT { type filter hook input priority 0; policy drop; }<br> add chain inet xciv FORWARD { type filter hook forward priority 0; policy drop; }<br> <br> # Don't filter loopback interface<br> add rule inet xciv INPUT iifname \"lo\" counter accept<br> <br> # Allow all ICMP incoming<br> add rule inet xciv INPUT iifname $LAN_EXT ip protocol icmp counter accept<br> <br> # Allow incoming connections (DNS)<br> add rule inet xciv INPUT iifname $LAN_EXT udp dport { 53 } counter accept<br> add rule inet xciv INPUT iifname $LAN_EXT tcp dport { 53 } counter accept<br> <br> # Allow incoming connections (HTTP\/SSL)<br> add rule inet xciv INPUT iifname $LAN_EXT tcp dport { 80 , 443 } counter accept<br> <br> # Allow incoming connections (SMTP\/SSL)<br> add rule inet xciv INPUT iifname $LAN_EXT tcp dport { 25, 587 } counter accept<br> <br> # Allow incoming established traffic (stateful inspection)<br> add rule inet xciv INPUT iifname $LAN_EXT ct state related,established counter accept<br> <br> # Block all other IPv4 traffic (send rejects rather than drop)<br> add rule inet xciv INPUT iifname $LAN_EXT ip protocol udp counter reject with icmp type host-prohibited<br> add rule inet xciv INPUT iifname $LAN_EXT ip protocol tcp counter reject with tcp reset<br> <br> # IPv6, allow ICMP incoming and reject other ports<br> add rule inet xciv INPUT iifname $LAN_EXT ip6 nexthdr ipv6-icmp counter accept<br> add rule inet xciv INPUT iifname $LAN_EXT ip6 nexthdr udp counter reject with icmpv6 type admin-prohibited<br> add rule inet xciv INPUT iifname $LAN_EXT ip6 nexthdr tcp counter reject with tcp reset <\/code><\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you have upgraded to Debian 10 buster you will know (if you have read the release notes) that Debian has now migrated to the nftables filtering framework. See 2.2.6.&nbsp;Network filtering based on nftables framework by default What is not covered is how you do this and what it really means. The release notes say [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":73,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"twitterCardType":"","cardImageID":0,"cardImage":"","cardTitle":"","cardDesc":"If you have upgraded to Debian 10 buster you will know (if you have read the release notes) that Debian has now migrated to the nftables filtering framework.","cardImageAlt":"","cardPlayer":"","cardPlayerWidth":0,"cardPlayerHeight":0,"cardPlayerStream":"","cardPlayerCodec":"","footnotes":""},"categories":[7,19,18,11,3],"tags":[4,22,21,20,6],"class_list":["post-70","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-computing","category-internet","category-security","category-software","category-technology","tag-computing","tag-internet","tag-security","tag-software","tag-technology"],"_links":{"self":[{"href":"https:\/\/www.xciv.org\/blog\/wp-json\/wp\/v2\/posts\/70","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.xciv.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.xciv.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.xciv.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.xciv.org\/blog\/wp-json\/wp\/v2\/comments?post=70"}],"version-history":[{"count":4,"href":"https:\/\/www.xciv.org\/blog\/wp-json\/wp\/v2\/posts\/70\/revisions"}],"predecessor-version":[{"id":75,"href":"https:\/\/www.xciv.org\/blog\/wp-json\/wp\/v2\/posts\/70\/revisions\/75"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.xciv.org\/blog\/wp-json\/wp\/v2\/media\/73"}],"wp:attachment":[{"href":"https:\/\/www.xciv.org\/blog\/wp-json\/wp\/v2\/media?parent=70"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.xciv.org\/blog\/wp-json\/wp\/v2\/categories?post=70"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.xciv.org\/blog\/wp-json\/wp\/v2\/tags?post=70"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}