TL;DR
获取Cloudflare Account ID、包含Account.Zero Trust
- https://www.icloud.com/shortcuts/8e625a57927b4079a4a682aab430d6aa
- https://kaiy.top/posts/update-Cloudflare-Gateway-IP-shortcuts/Update%20Cloudflare%20Gateway%20IP.shortcut
两个链接内容一致,站内链接权当备份。
根本没仔细测试过Apple的Shortcuts Setup能不能用的问题。根据我对Apple的认知,很可能会遇到变量导入的问题,尤其是涉及到有两个字符串需要转换为布尔值。如果遇到相关问题,建议直接把你的内容硬编码到快捷指令里,然后给我留个评论,谢谢~
(我相信都用着Cloudflare Zero Trust而且还能找到这里来的人应该不差这点能力的,吧。);-)
背景&介绍
Cloudflare Gateway是一款运行于DNS层或HTTP层的安全网关。其具有不错的可自定义程度。在基于DNS使用时,其提供IPv4/IPv6 :53 UDP、DoT、DoH几种接入方式。
在通过IPv4 :53 UDP接入其DNS服务时,由于IPv4地址非常稀缺,每个人分配到的接入点都将是一个相同的Anycast IP地址。因此需要在Cloudflare登记客户端IP地址以进行个性化配置。
很不幸,Cloudflare没有提供DDNS支持,而我的路由器又不支持DoT、DoH,更糟糕的是,我的ISP到现在都没有提供IPv6互联网……所以很长一段时间我都只能手动进行IP地址更新。
直到最近我突发奇想,决定通过Cloudflare API对Cloudflare Gateway绑定IP进行定期更新。
前提&准备
Cloudflare API Token
首先,为了使用Cloudflare API,我们需要一个至少包含Account.Zero Trust
Cloudflare Account ID
打开Cloudflare Zero Trust仪表板,登入账户后,在页面的URL中应该可以非常方便地看到你的Account ID,不做过多赘述。
Gateway Location信息
生成符合条件的API Token之后,我们需要获取Gateway中对应Location的ID。这一步有两种获取方法。
通过网页仪表板获取
打开Cloudflare Zero Trust仪表板,登入账户后,在边栏选择Gateway > Locations
,并选择或新建一个想要使用的位置,对其进行至少一次编辑(如名称、ECS支持、是否为默认等)。此时你需要记录该Location的名称。
然后在边栏中转到Logs > Admin
,查看对应的Update location
事件,在log的json中寻找关键字为id
的字符串。注意不是account_id
,也不是network
关键字下的id
。
通过API获取
执行
GET https://api.cloudflare.com/client/v4/accounts/:identifier/gateway/locations
Header: Authorization: Bearer :token
Header: Content-Type: application/json
即可获得你所有可用的Gateway Locations。在返回的json中寻找关键字为id
以及name
的字符串。如果你使用curl,则可以执行:
curl -X GET "https://api.cloudflare.com/client/v4/accounts/:identifier/gateway/locations" \
-H "Authorization: Bearer :token" \
-H "Content-Type: application/json"
这一步中的:identifier
是指你的Cloudflare Account ID,:token
是指你的API Token,下文同样。注意在替换为你的个人内容时不要保留:
,例如,如果你的Account ID是example123456
,你应该使用https://api.cloudflare.com/client/v4/accounts/example123456/gateway/locations
而非https://api.cloudflare.com/client/v4/accounts/:example123456/gateway/locations
。
编写快捷指令
这一步建议在macOS中进行,因为iOS上的快捷指令对HTTP请求的配置界面很奇怪。我用着并不是很明白。如果你没有macOS设备,可以使用前文中已编写完毕的快捷指令~~,或者硬着头皮上~~。
由于作者使用的是英文版操作系统,可能一些翻译不是非常准确,敬请谅解。
主要流程为:
获取当前IP地址:外部,IPv4
获取URL内容:
https://api.cloudflare.com/client/v4/accounts/:identifier/gateway/locations/:uuid
方法为PUT
Header:
Content-Type: application/json
Authorization: Bearer :token
请求正文格式为json,包含:
networks,类型为数组/阵列(Array),包含:
一个字典(Dictionary),包含:
network,类型为字符串/文本(Text),值为:ip/32
name,类型为字符串,值为:name
client_default,类型为布尔(Boolean),值为:client_default
ecs_support,类型为布尔,值为:ecs_support
此处:identifier
和:token
的定义与上文(#通过API获取)一致,不再赘述。:uuid
指需要更新的Location ID。:ip
指你在快捷指令的第一步中获取的外部IPv4地址。:name
指你希望将此Location重命名为的名称。若不欲重命名,填写为原来的名称即可。:client_default
指你是否希望此Location成为默认选项(目前我尚不知道此选项的作用)。注意,如果你希望将此项目的值设为False
,你需要保证你有一个另外的Location作为默认值,否则其值必须为True
。:ecs_support
指你是否希望此Location的DNS服务启用ECS,建议设为True
来提高性能。
Cloudflare API Documentation给出的样例请求正文格式为:
{"name":"Austin Office Location","networks":["192.0.2.1"],"client_default":"false"}
这是不对的。如果按照此方式进行请求,我们将得到一个错误,消息为json: cannot unmarshal string into Go struct field LocationRequest.networks of type api.NetworkRecordJSON
以及json: cannot unmarshal string into Go struct field LocationRequest.client_default of type bool
。我不知道Cloudflare为什么会在一个示例里出现两处错误。正确的样例请求正文格式应为:
{"name":"Austin Office Location","networks":[{"network": "192.0.2.1/24"}],"client_default":false}
此处我也遇到了问题。搜索后参考了Cloudflare Community里的一篇文章解决了问题。十分感谢。
至此,可以直接通过Apple平台上的快捷指令完成对Cloudflare Gateway绑定IP的更新了。后话就是建议添加自动化获得更加体验了。