"""Publish client links for every external node, using its public DNS name.""" import base64 import json import urllib.error import urllib.parse import urllib.request API = "https://kubernetes.default.svc" NAMESPACE = open("/var/run/secrets/kubernetes.io/serviceaccount/namespace", encoding="utf-8").read().strip() TOKEN = open("/var/run/secrets/kubernetes.io/serviceaccount/token", encoding="utf-8").read().strip() CA = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" def request(method, path, body=None): import ssl data = json.dumps(body).encode() if body is not None else None req = urllib.request.Request( API + path, data=data, method=method, headers={ "Authorization": "Bearer " + TOKEN, "Content-Type": "application/json", }, ) with urllib.request.urlopen(req, context=ssl.create_default_context(cafile=CA), timeout=15) as response: return json.load(response) def publish(name, links): path = f"/api/v1/namespaces/{NAMESPACE}/secrets" data = {node: base64.b64encode(link.encode()).decode() for node, link in links.items()} try: current = request("GET", f"{path}/{name}") except urllib.error.HTTPError as error: if error.code != 404: raise request("POST", path, {"apiVersion": "v1", "kind": "Secret", "metadata": {"name": name}, "type": "Opaque", "data": data}) return if current.get("data", {}) == data: return # PUT replaces the data map, removing links for nodes that are no longer external. request("PUT", f"{path}/{name}", { "apiVersion": "v1", "kind": "Secret", "metadata": {"name": name, "resourceVersion": current["metadata"]["resourceVersion"]}, "type": "Opaque", "data": data, }) secret = open("/config/SECRET", encoding="utf-8").read().strip() if len(secret) != 32 or any(char not in "0123456789abcdefABCDEF" for char in secret): raise ValueError("Vaultwarden Secret must be 32 hexadecimal characters") selector = urllib.parse.quote("homelab.hexor.cy/exposure=external", safe="") nodes = request("GET", f"/api/v1/nodes?labelSelector={selector}")["items"] if not nodes: raise ValueError("No external nodes found") classic = {} tls = {} for node in nodes: name = node["metadata"]["name"] # DNS is maintained outside the cluster; no public IP needs to be stored on a Node. host = f"{name}.hexor.cy" classic[name] = f"tg://proxy?server={host}&port=30443&secret={secret}" tls[name] = f"tg://proxy?server={host}&port=30444&secret=ee{secret}79612e7275" publish("mtproxy-links", classic) publish("telemt-links", tls) print(f"Published MTProxy links for {len(nodes)} external nodes")