diff --git a/modules/cloudflare-dns/client.ts b/modules/cloudflare-dns/client.ts index 3c1d270..725e042 100644 --- a/modules/cloudflare-dns/client.ts +++ b/modules/cloudflare-dns/client.ts @@ -23,14 +23,19 @@ export class CloudflareClient { ) {} static fromEnv(env: NodeJS.ProcessEnv = process.env): CloudflareClient { + // Which zone, domain and ingress are a mesh's own facts, not this module's — so they are + // settings, merged into a config file the mesh manages (novox/hq ADR 0051), read here. The + // token is the one secret and stays an own-secret. Env is honoured as a fallback for a + // hand-run instance, but the deployed path is the config file settings fill. + const config = readConfig(env.MESH_CLOUDFLARE_CONFIG_FILE); const token = env.MESH_CLOUDFLARE_TOKEN ?? readSecret(env.MESH_CLOUDFLARE_TOKEN_FILE); - const zoneId = env.MESH_CLOUDFLARE_ZONE_ID; - const domain = env.MESH_PUBLIC_DOMAIN; - const ingress = env.MESH_PUBLIC_INGRESS; + const zoneId = config.zone ?? env.MESH_CLOUDFLARE_ZONE_ID; + const domain = config.domain ?? env.MESH_PUBLIC_DOMAIN; + const ingress = config.ingress ?? env.MESH_PUBLIC_INGRESS; if (!token || !zoneId || !domain || !ingress) { throw new Error( - "cloudflare-dns needs MESH_CLOUDFLARE_TOKEN (or _FILE), MESH_CLOUDFLARE_ZONE_ID, " + - "MESH_PUBLIC_DOMAIN and MESH_PUBLIC_INGRESS — it cannot register a name without them", + "cloudflare-dns is not configured — set its zone, domain and ingress in settings (and the " + + "token as its own-secret); until then it registers nothing", ); } return new CloudflareClient(token, zoneId, domain, ingress); @@ -103,3 +108,20 @@ function readSecret(path: string | undefined): string | undefined { return undefined; } } + +interface Config { + zone?: string; + domain?: string; + ingress?: string; +} + +/** The settings-managed config file (a JSON document the mesh merges settings into). Absent or + * unparseable yields an empty config, which fromEnv then reports as unconfigured. */ +function readConfig(path: string | undefined): Config { + if (!path) return {}; + try { + return JSON.parse(readFileSync(path, "utf8")) as Config; + } catch { + return {}; + } +} diff --git a/modules/cloudflare-dns/module.json b/modules/cloudflare-dns/module.json index 58e4806..afaaaf1 100644 --- a/modules/cloudflare-dns/module.json +++ b/modules/cloudflare-dns/module.json @@ -37,6 +37,14 @@ "path": "/var/lib/cloudflare-dns/grants", "mode": "0700" }, + { + "id": "config", + "type": "file", + "path": "/var/lib/cloudflare-dns/config.json", + "merge": "json", + "content": "{}", + "mode": "0600" + }, { "id": "provisioner", "type": "container", @@ -47,11 +55,10 @@ "GRANTS": "/grants", "MESH_CLOUDFLARE_TOKEN_FILE": "/run/secrets/token", "MESH_BROKER_FILE": "/run/secrets/broker", - "MESH_CLOUDFLARE_ZONE_ID": "", - "MESH_PUBLIC_DOMAIN": "", - "MESH_PUBLIC_INGRESS": "" + "MESH_CLOUDFLARE_CONFIG_FILE": "/run/config/config.json" }, "volumes": [ + "/var/lib/cloudflare-dns/config.json:/run/config/config.json:ro", "/var/lib/cloudflare-dns/grants:/grants", "/var/lib/cloudflare-dns/token:/run/secrets/token:ro", "/var/lib/cloudflare-dns/broker:/run/secrets/broker:ro"