fix: zone resolution logic
This commit is contained in:
+35
-14
@@ -63,13 +63,14 @@ function isAcmeTagged(tags: Record<string, string> | undefined): boolean {
|
||||
|
||||
export class DnsChallengeManager {
|
||||
private readonly client: DnsManagementClient;
|
||||
private zoneMap: Map<string, string> | undefined; // zone name → resource group
|
||||
|
||||
constructor(credential: TokenCredential, private readonly config: Config) {
|
||||
this.client = new DnsManagementClient(credential, config.subscriptionId);
|
||||
}
|
||||
|
||||
async createTxtRecord(fqdn: string, value: string): Promise<void> {
|
||||
const { resourceGroup, zone, name } = this.parseFqdn(fqdn);
|
||||
const { resourceGroup, zone, name } = await this.resolveFqdn(fqdn);
|
||||
await this.client.recordSets.createOrUpdate(resourceGroup, zone, name, 'TXT', {
|
||||
ttl: this.config.dnsChallengeTtl,
|
||||
txtRecords: [{ value: [value] }],
|
||||
@@ -77,7 +78,7 @@ export class DnsChallengeManager {
|
||||
}
|
||||
|
||||
async deleteTxtRecord(fqdn: string): Promise<void> {
|
||||
const { resourceGroup, zone, name } = this.parseFqdn(fqdn);
|
||||
const { resourceGroup, zone, name } = await this.resolveFqdn(fqdn);
|
||||
try {
|
||||
await this.client.recordSets.delete(resourceGroup, zone, name, 'TXT');
|
||||
} catch {
|
||||
@@ -85,20 +86,40 @@ export class DnsChallengeManager {
|
||||
}
|
||||
}
|
||||
|
||||
private parseFqdn(fqdn: string): { resourceGroup: string; zone: string; name: string } {
|
||||
private async loadZoneMap(): Promise<Map<string, string>> {
|
||||
if (this.zoneMap) return this.zoneMap;
|
||||
|
||||
this.zoneMap = new Map();
|
||||
for (const rg of this.config.resourceGroups) {
|
||||
for (const zone of this.config.dnsZones ?? []) {
|
||||
if (fqdn.endsWith(`.${zone}`) || fqdn === zone) {
|
||||
const name = fqdn === zone ? '@' : fqdn.slice(0, -(zone.length + 1));
|
||||
return { resourceGroup: rg, zone, name };
|
||||
}
|
||||
for await (const zone of this.client.zones.listByResourceGroup(rg)) {
|
||||
if (!zone.name) continue;
|
||||
if (this.config.dnsZones && !this.config.dnsZones.includes(zone.name)) continue;
|
||||
this.zoneMap.set(zone.name, rg);
|
||||
}
|
||||
}
|
||||
// fallback: derive zone from fqdn by stripping first label
|
||||
const parts = fqdn.split('.');
|
||||
const zone = parts.slice(1).join('.');
|
||||
const name = parts[0];
|
||||
const rg = this.config.resourceGroups[0];
|
||||
return { resourceGroup: rg, zone, name };
|
||||
return this.zoneMap;
|
||||
}
|
||||
|
||||
private async resolveFqdn(fqdn: string): Promise<{ resourceGroup: string; zone: string; name: string }> {
|
||||
const zones = await this.loadZoneMap();
|
||||
|
||||
// longest-suffix match: find the most specific zone that is a suffix of fqdn
|
||||
let bestZone = '';
|
||||
for (const zoneName of zones.keys()) {
|
||||
if (
|
||||
(fqdn === zoneName || fqdn.endsWith(`.${zoneName}`)) &&
|
||||
zoneName.length > bestZone.length
|
||||
) {
|
||||
bestZone = zoneName;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bestZone) {
|
||||
throw new Error(`No Azure DNS zone found for FQDN: ${fqdn}`);
|
||||
}
|
||||
|
||||
const resourceGroup = zones.get(bestZone)!;
|
||||
const name = fqdn === bestZone ? '@' : fqdn.slice(0, -(bestZone.length + 1));
|
||||
return { resourceGroup, zone: bestZone, name };
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user