When adding/renewing domains via Cloudflare DNS I'm getting the following error.
Error determining zone_id: #### Cannot use the access token from location: [ IPv6 Address ]. Please confirm that you have supplied valid Cloudflare API credentials. (Did you enter a valid Cloudflare Token?)
This is because I've enabled IP restriction on my Cloudflare token but only have a static IPv4 address and Certbot is calling the Cloudflare API via IPv6.
How can I force Certbot to call the Cloudflare API via IPv4?
When configuring a Cloudflare API token you can limit it's access to one or more specific IP addresses. I have a dedicated IPv4 address but my IPv6 address is not static. Therefore I would like to use use my IPv4 address for the IP address filter and force Certbot to only call the Cloudflare API on the IPv4 address.
So, I looked at the certbot-dns-cloudflare code and it's using Cloudflare's own API library implementation to connect to the API. While that is also open source and you could modify it, it seems like a big nuisance.
I think I would suggest using the netns feature on Linux, which allows you to run a program in a different network environment than other programs on the same system. It is related to containerization but it can be used manually and only affects the program's view of the network configuration.
You can run sudo ip netns add my-no-ipv6-netns (just once per boot) and then sudo ip netns exec my-no-ipv6-netns COMMAND where the COMMAND can be any command, which will run in its own independent copy of the system network configuration. The COMMAND can be commands to manipulate the network configuration by apparently, for example, deleting IPv6 addresses so that the netns has no IPv6 connectivity at all. Then you can do the sudo ip netns exec my-no-ipv6-netns certbot ... to run Certbot in this environment.
I guess you would also need to ensure that your renewals run in the same netns environment with a netns exec. You could make a shell script that wraps the certbot execution with this netns, and then make the renewal jobs point to that instead of the real certbot.
Thanks @schoen, from the sound of it this isn't possible to achieve with Certbot (or certbot-dns-cloudflare). I'll look into netns. My other thought was to see if I could block IPv6 resolution to api.cloudflare.com at the DNS level.
@schoen Sounds like a hassle, isn't the following possible?
@PHLAK Is it perhaps possible to list api.cloudflare.com (and perhaps dash.cloudflare.com if needed) in /etc/hosts? And of course only the IPv4 addresses. Of course this would mean the entire process could fail if Cloudflare decides to change the IP addresses of the host(s), but hopefully that doesn't occur often?
Yeah, there are alternative solutions but none of them are ideal.
For the record, the ideal solution (for me anyway) would be having a configuration option (e.g. dns_cloudflare_ip_version=4) we could define in /etc/letsencrypt/cloudflare.ini that would force the request to use a specific IP version. Second best option would be a command flag (e.g. --dns-cloudflare-ipv4). These would allow overriding only Certbot Cloudflare requests without having to make a system-level or network-wide change.
Is it possible to spin up an IPv4 only response DNS server?
[that way the IPv4 address would stay current]
Or exploit local DNS cache to contain only IPv4 addresses for that FQDN...
Like: dig A api.cloudflare.com certbot renew
[but something that actually works - LOL]
Hm, but that isn't selective for Certbot only. Prefer IPv4 over IPv6 sounds like a regression to me, worth not looking into.
@PHLAK Another question: you say your IPv4 is static, but your IPv6 is dynamic. HOW dynamic is it actually? E.g., my ISP routes an entire /48 range to my CPE router, so my computers on the internal network can choose out of 1208925819614629174706176 different IP addresses if I wanted to. Isn't it possible you can add a range to Cloudflares IP restrictions? It would make sense and it would also make sense you have your own "static" IPv6 range for your internet connection.
Hm, looking at my own Cloudflare dashboard at my tokens, it says:
Client IP Address Filtering
Select IP addresses or ranges of IP addresses to filter.
And when I add my /48 (in the form of 2001:db8:ef01::/48) it works nicely