pr_01m47d24b0e6n91zwymwxg0vpx/scripts/cloudflare-setup.py

82 lines3,116 bytesCodeBlame
1"""Makes what Deployments needs that `wrangler login` cannot: a proxied
2wildcard DNS record on the apps' zone, and an API token for the deployments
3service (Workers Scripts: Edit, Account Analytics: Read).
4
5Run by scripts/setup-deployments.sh with CLOUDFLARE_EMAIL and
6CLOUDFLARE_API_KEY (a Global API Key) set. Prints only ids and outcomes,
7never the key or the new token. Skips what exists.
8"""
9import json
10import os
11import sys
12import urllib.error
13import urllib.request
14
15ACCOUNT = os.environ.get("CLOUDFLARE_ACCOUNT_ID") or "1e6f2cffa3f445920836e8ebe446bb58"
16EMAIL = os.environ.get("CLOUDFLARE_EMAIL", "")
17KEY = os.environ.get("CLOUDFLARE_API_KEY", "")
18ZONE = os.environ.get("G1T_APPS_ZONE", "g1t.page")
19TOKEN_FILE = os.environ["TOKEN_FILE"]
20API = "https://api.cloudflare.com/client/v4"
21
22if not KEY or not EMAIL:
23 sys.exit("CLOUDFLARE_EMAIL and CLOUDFLARE_API_KEY must be set")
24
25
26def call(method, path, body=None):
27 request = urllib.request.Request(
28 API + path,
29 method=method,
30 data=json.dumps(body).encode() if body is not None else None,
31 headers={
32 "X-Auth-Email": EMAIL,
33 "X-Auth-Key": KEY,
34 "Content-Type": "application/json",
35 # Cloudflare refuses Python's default user agent.
36 "User-Agent": "g1t-setup",
37 },
38 )
39 try:
40 return json.load(urllib.request.urlopen(request))
41 except urllib.error.HTTPError as error:
42 return json.loads(error.read() or b"{}") | {"http": error.code}
43
44
45zones = call("GET", f"/zones?name={ZONE}")
46if not zones.get("result"):
47 sys.exit(f"zone {ZONE} not found: {zones.get('errors')}")
48zone = zones["result"][0]["id"]
49
50records = call("GET", f"/zones/{zone}/dns_records?name=*.{ZONE}")
51if records.get("result"):
52 print(f"*.{ZONE}: record exists")
53else:
54 made = call("POST", f"/zones/{zone}/dns_records", {
55 "type": "AAAA", "name": "*", "content": "100::", "proxied": True, "ttl": 1,
56 "comment": "g1t deployments: every app goes to the dispatch Worker",
57 })
58 print(f"*.{ZONE}:", "record created" if made.get("success") else made.get("errors"))
59
60if os.path.exists(TOKEN_FILE):
61 print("token: exists in .credentials; not making another")
62 sys.exit(0)
63
64groups = call("GET", "/user/tokens/permission_groups")
65wanted = {"Workers Scripts Write", "Account Analytics Read"}
66ids = [g["id"] for g in groups.get("result", []) if g["name"] in wanted]
67if len(ids) != len(wanted):
68 sys.exit("could not find the permission groups for the token")
69created = call("POST", "/user/tokens", {
70 "name": "g1t deployments service (Workers for Platforms uploads, analytics)",
71 "policies": [{
72 "effect": "allow",
73 "resources": {f"com.cloudflare.api.account.{ACCOUNT}": "*"},
74 "permission_groups": [{"id": i} for i in ids],
75 }],
76})
77if not created.get("success"):
78 sys.exit(f"token not created: {created.get('errors')}")
79os.makedirs(os.path.dirname(TOKEN_FILE), exist_ok=True)
80with open(TOKEN_FILE, "w", encoding="utf-8") as f:
81 f.write(created["result"]["value"] + "\n")
82print("token: created and saved to .credentials")