{"record":{"id":"78369ff10ffe8bd1","repo":"Billionmail/BillionMail","slug":"dns-automated-resolution-failed-clientid-clients","errorCode":null,"errorMessage":"DNS automated resolution failed: ClientID, ClientSecret or TenantID is empty in AzureDNS configuration file","messagePattern":"DNS automated resolution failed: ClientID, ClientSecret or TenantID is empty in AzureDNS configuration file","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/acme/acme.go","lineNumber":242,"sourceCode":"\t}\n\n\terr = client.Challenge.SetDNS01Provider(p)\n\tif err != nil {\n\t\treturn errors.New(public.LangCtx(ctx, \"DNS verification setup failed: {}\", err.Error()))\n\t}\n\n\treturn nil\n}\n\n/**\n * @description: Configure DNS verification via Azure DNS\n * @param {*lego.Client} client Client\n * @param {map[string]string} keyConfig Configuration information\n * @return error Error information\n */\nfunc SetDnsAzuredns(ctx context.Context, client *lego.Client, keyConfig map[string]string) error {\n\tif keyConfig == nil || keyConfig[\"ClientID\"] == \"\" || keyConfig[\"ClientSecret\"] == \"\" || keyConfig[\"TenantID\"] == \"\" {\n\t\treturn errors.New(public.LangCtx(ctx, \"DNS automated resolution failed: ClientID, ClientSecret or TenantID is empty in AzureDNS configuration file\"))\n\t}\n\n\tcfg := azuredns.NewDefaultConfig()\n\tcfg.ClientID = keyConfig[\"ClientID\"]\n\tcfg.ClientSecret = keyConfig[\"ClientSecret\"]\n\tcfg.TenantID = keyConfig[\"TenantID\"]\n\n\tp, err := azuredns.NewDNSProviderConfig(cfg)\n\tif err != nil {\n\t\treturn errors.New(public.LangCtx(ctx, \"DNS provider initialization failed: {}\", err.Error()))\n\t}\n\n\terr = client.Challenge.SetDNS01Provider(p)\n\tif err != nil {\n\t\treturn errors.New(public.LangCtx(ctx, \"DNS verification setup failed: {}\", err.Error()))\n\t}\n\n\treturn nil","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/acme/acme.go#L224-L260","documentation":"SetDnsAzuredns pre-validates its keyConfig map before touching the lego Azure DNS provider. If keyConfig is nil or any of ClientID, ClientSecret, or TenantID is an empty string, it fails fast because azuredns.NewDNSProviderConfig cannot authenticate to Azure without all three (a service-principal credential set).","triggerScenarios":"ApplySSLWithExistingServer with vtype=\"dns\" and dnsProvider=\"azuredns\" where the token map lacks ClientID, ClientSecret, or TenantID, or is entirely nil.","commonSituations":"Users supply an Azure connection string or subscription ID instead of a service principal; only two of the three fields were entered in the UI; the tenant ID was omitted because it was confused with the subscription ID; the config file failed to parse so the map is nil.","solutions":["Set ClientID, ClientSecret, and TenantID to a valid Azure App Registration (service principal) with DNS Zone Contributor rights on the zone.","Check that the config file/JSON keys are named exactly ClientID, ClientSecret, TenantID (case-sensitive map lookups).","Verify the secret is the App Registration client secret, not a certificate or connection string.","If unsure, use the Azure portal: Entra ID → App registrations → copy Application (client) ID, Directory (tenant) ID, and create a new client secret."],"exampleFix":"// before\nkeyConfig := map[string]string{\"ClientID\": id, \"ClientSecret\": secret} // TenantID missing\nerr := SetDnsAzuredns(ctx, client, keyConfig)\n// after\nkeyConfig := map[string]string{\"ClientID\": id, \"ClientSecret\": secret, \"TenantID\": tenantID}\nerr := SetDnsAzuredns(ctx, client, keyConfig)","handlingStrategy":"validation","validationCode":"func azureDNSConfigReady(kc map[string]string) bool {\n    if kc == nil {\n        return false\n    }\n    guid := regexp.MustCompile(`^[0-9a-fA-F-]{36}$`)\n    return kc[\"ClientSecret\"] != \"\" && guid.MatchString(kc[\"ClientID\"]) && guid.MatchString(kc[\"TenantID\"])\n}","typeGuard":"func hasAzureDNSKeys(kc map[string]string) bool {\n    for _, k := range []string{\"ClientID\", \"ClientSecret\", \"TenantID\"} {\n        if kc == nil || strings.TrimSpace(kc[k]) == \"\" {\n            return false\n        }\n    }\n    return true\n}","tryCatchPattern":"if err := SetDnsAzuredns(ctx, client, tokens); err != nil {\n    if strings.Contains(err.Error(), \"TenantID\") {\n        return fmt.Errorf(\"Azure service principal incomplete: %w\", err)\n    }\n    return err\n}","preventionTips":["Collect all three service-principal fields (ClientID, ClientSecret, TenantID) as required inputs in the UI.","Validate GUID format for ClientID/TenantID before submission.","Name config keys exactly as the map lookups expect (case-sensitive).","Grant the service principal DNS Zone Contributor role on the target zone at setup time."],"tags":["go","acme","dns","azure","missing-credentials"],"backgroundTag":"missing-env-var","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}