Skip to content

Commit 86016b8

Browse files
committed
feat: add cloudflare dns adoption hook for tunnel bindings
1 parent cd63847 commit 86016b8

2 files changed

Lines changed: 107 additions & 0 deletions

File tree

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
---
2+
apiVersion: batch/v1
3+
kind: Job
4+
metadata:
5+
name: cloudflare-dns-adoption
6+
namespace: cloudflare-operator-system
7+
annotations:
8+
argocd.argoproj.io/hook: PostSync
9+
argocd.argoproj.io/hook-delete-policy: HookSucceeded
10+
argocd.argoproj.io/sync-wave: "1"
11+
ignore-check.kube-linter.io/unset-memory-requirements: "No limits on single-node cluster"
12+
spec:
13+
ttlSecondsAfterFinished: 300
14+
backoffLimit: 2
15+
template:
16+
spec:
17+
restartPolicy: Never
18+
securityContext:
19+
runAsNonRoot: true
20+
runAsUser: 65532
21+
seccompProfile:
22+
type: RuntimeDefault
23+
containers:
24+
- name: adopt-dns
25+
image: docker.io/library/python:3.12-alpine
26+
securityContext:
27+
allowPrivilegeEscalation: false
28+
readOnlyRootFilesystem: true
29+
capabilities:
30+
drop:
31+
- ALL
32+
resources:
33+
requests:
34+
cpu: 50m
35+
memory: 64Mi
36+
volumeMounts:
37+
- name: tmp
38+
mountPath: /tmp
39+
env:
40+
- name: CF_API_TOKEN
41+
valueFrom:
42+
secretKeyRef:
43+
name: cloudflare-api-credentials
44+
key: CLOUDFLARE_API_TOKEN
45+
- name: CF_DOMAIN
46+
value: makeitwork.cloud
47+
command:
48+
- /bin/sh
49+
- -c
50+
- |
51+
set -eu
52+
python - <<'PY'
53+
import json
54+
import os
55+
import urllib.parse
56+
import urllib.request
57+
58+
token = os.environ["CF_API_TOKEN"]
59+
domain = os.environ["CF_DOMAIN"]
60+
hosts = ["argocd", "grafana", "status", "ansible"]
61+
62+
def cf_request(method, path, params=None):
63+
url = "https://api.cloudflare.com/client/v4" + path
64+
if params:
65+
url += "?" + urllib.parse.urlencode(params)
66+
req = urllib.request.Request(
67+
url,
68+
method=method,
69+
headers={
70+
"Authorization": f"Bearer {token}",
71+
"Content-Type": "application/json",
72+
},
73+
)
74+
with urllib.request.urlopen(req, timeout=30) as resp:
75+
return json.loads(resp.read().decode("utf-8"))
76+
77+
zone_resp = cf_request("GET", "/zones", {"name": domain, "per_page": 1})
78+
zone = zone_resp.get("result", [])
79+
if not zone:
80+
raise SystemExit(f"zone not found: {domain}")
81+
zone_id = zone[0]["id"]
82+
83+
for host in hosts:
84+
fqdn = f"{host}.{domain}"
85+
recs = cf_request(
86+
"GET",
87+
f"/zones/{zone_id}/dns_records",
88+
{"name": fqdn, "per_page": 100},
89+
).get("result", [])
90+
91+
if not recs:
92+
print(f"no records to adopt for {fqdn}")
93+
continue
94+
95+
for rec in recs:
96+
rec_id = rec["id"]
97+
rec_type = rec.get("type", "")
98+
rec_content = rec.get("content", "")
99+
print(f"deleting {rec_type} {fqdn} -> {rec_content}")
100+
cf_request("DELETE", f"/zones/{zone_id}/dns_records/{rec_id}")
101+
102+
print("cloudflare dns adoption complete")
103+
PY
104+
volumes:
105+
- name: tmp
106+
emptyDir: {}

operators/cloudflare/kustomization.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ resources:
66
- https://github.com/adyanth/cloudflare-operator.git/config/default?ref=v0.13.1
77
# ClusterTunnel CR (cloudflared deployment created by operator)
88
- cluster-tunnel.yaml
9+
- dns-adoption-job.yaml
910
generators:
1011
- ksops-cloudflare-secrets.yaml
1112
images:

0 commit comments

Comments
 (0)