2

To get and renew a Letsencrypt certificate, I need to open the http port 80 while certbot is running, and close it afterwards. (There is no normal web service in this server).

With iptables I used these commands in the letsencrypt "/etc/letsencrypt/renewal-hooks/pre" and ".../post" scripts:

iptables -I INPUT -p tcp --dport 80 -j ACCEPT -m comment --comment "Allow HTTP for certbot"

and

iptables -D INPUT -p tcp --dport 80 -j ACCEPT -m comment --comment "Allow HTTP for certbot"

I can use iptables-translate with the first -I(nsert) rule to get the equivalent nft command:

nft insert rule ip filter INPUT tcp dport 80 counter accept comment \"Allow HTTP for certbot\"

But with the -D(elete) command, I just get

Translation not implemented

So what would be the best way to implement this with nftables?

Maybe I could also add and then remove an entire special table for that with nft add table ... and nft delete table ... ? But how to make sure that packets are not dropped anyway by my other table wich has policy drop?

2 Answers 2

2

To delete a rule, we need to know it's "handle". This is shown when using the -a option in

nft -a list chain filter input

So in this particular case where it's the port 80 which needs to be opened and then closed again, I use the following scripts in the letsencrypt "renewal-hooks" directory:

In /etc/letsencrypt/renewal-hooks/pre/fw-certbot-open

#!/bin/bash

# Open firewall to let certbot renew certificates

me=$(basename "$0")

logger -t "$me" "Opening port 80 for certbot"

## Reverse order since we do inserts
nft insert rule ip filter input              tcp dport 80 counter                                accept comment \"Allow HTTP for certbot\"
nft insert rule ip filter input ct state new tcp dport 80 log prefix \"nft:ok-certbot \" group 0 accept comment \"Allow and log HTTP for certbot\"

And in "/etc/letsencrypt/renewal-hooks/post/fw-certbot-close":

#!/bin/bash

# Removing firewall rules created for certbot renew certificates

me=$(basename "$0")

logger -t "$me" "Closing port 80 opened for certbot"

## Remove port 80 accept rules
for h in $(nft -a list chain filter input \
           | awk '/dport 80 .* accept .* # handle [0-9]+/ {print $NF}')
do
    nft delete rule filter input handle $h
done

This seems to work. I still wonder if there would be an even simpler way to do it, without having to parse the nft output with awk to get the handle.

2
  • 1
    You don't even need to filter the whole dump: use nft -e -a the first time: -e will echo back the rule and its handle (because of -a) to memorize for later.
    – A.B
    Dec 19, 2022 at 14:53
  • @A.B: Nice tip about -e. If adding and removing the rule(s) in the same script, that would indeed make it much simpler.
    – mivk
    Dec 22, 2022 at 21:32
2

The answer by mivk will do exactly what you asked.

Another approach which may be easier to manage is to use a chain that contains temporary rules and flush it after it is no longer needed:

# nft add chain ip filter temporary_web
# nft insert rule ip filter INPUT tcp dport 80 counter jump temporary_web comment \"Allow HTTP for certbot\"

Then you will be able to run the following before certbot:

# nft insert rule ip filter temporary_web counter accept

And after certbot runs you can clear the chain by

# nft flush chain ip filter temporary_web 

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .