StackExchange / dnscontrol

Infrastructure as code for DNS!
https://dnscontrol.org/
MIT License
3.11k stars 396 forks source link

Changes are ignored when DnsProvider() is not defined #2973

Open devblackops opened 4 months ago

devblackops commented 4 months ago

Is your feature request related to a problem? Please describe.

A zone defined like the following (without a DnsProvider() defined) silently ignores that the TXT record should be created. The required changes are not shown in preview either.

var REG_NAMECOM = NewRegistrar("name.com");

D("example.com", REG_NAMECOM,
    NAMESERVER("ns1-09.azure-dns.com."),
    NAMESERVER("ns2-09.azure-dns.net."),
    NAMESERVER("ns3-09.azure-dns.org."),
    NAMESERVER("ns4-09.azure-dns.info."),
    TXT("@", "foo"),
}

When adding DnsProvider() the records are correctly added.

var REG_NAMECOM = NewRegistrar("name.com");
var azure = NewDnsProvider("azuredns")

D("example.com", REG_NAMECOM, DnsProvider(azure),
    TXT("@", "foo"),
}

Describe the solution you'd like A warning is shown if DnsProvider() is not provided so required changes are not suppressed.

lolifamily commented 4 months ago

interesting, how to add glue records?

tlimoncelli commented 4 months ago

Well, let's consider all the possibilities.

That gives us 6 combinations:

R:something D:none No warning needed. This is a normal "delegated domain" where we control the registrar, but someone else is controlling the zone.

R:none D:none No warning needed. This is an "inventory only" domain. It is listed in dnsconfig.js just so that "dnscontrol print-ir" lists it. This is done if you keep an inventory of domains that (for example) the company owns but other divisions manage.

R:none D:something No warning needed. This is a normal "third-party registrar." We control the zone records but someone else is controlling the registrar.

R:something D:something No warning needed. This is a normal domain. We control the registrar and the zone's records

R:something D:nil
This is the situation that @devblackops had. Because there was no DnsProvider(), no zone records were being updated. It is a legal combination, but it is confusing. Thus, it deserves a warning. Print: Warning: No DnsProvider() in domain example.com.

R:none D:nil
This combination doesn't make sense. Use the "inventory only" combination instead. Print: Warning: No DnsProvider() in domain example.com.

The only combinations that don't make sense are the last two. Both should get warnings. To turn off the warnings, add DnsProvider("NONE").

We can be "smart" by only displaying the warning if there are zone records.

To resolve this bug, we should print the warning if len(DomainConfig.DNSProviderNames) == 0 && len(DomainConfig.Records) != 0

cafferata commented 4 months ago

@tlimoncelli thanks for this clear explanation. 👏🏻

Certainly interesting! Because I have never thought about the situation R:none D:none (Include domain names in DNSControl for an overview.) before.

tlimoncelli commented 4 months ago

Yeah, the R:none D:none is something I recently "invented".

Our legal department periodically asks for a list of all the domains we own. I generally give them the output of dnscontrol print-ir | jq -r '.domains[].name' but then I always have to remember to manually add a couple more domains that aren't maintained by DNSControl.

I know what you're thinking: Tom, there are domains you don't maintain with DNSControl? How dare you???

Yeah, crazy huh? Well, it happens. For example, I can't maintain dnscontrol-azure.com using DNSControl because it is used in our integration tests. It has to be isolated from everything else or our CI/CD pipeline would clobber our production DNSControl pipeline.

Anyway...

A few months ago I realized I could define this macro:

var REG_THIRDPARTY = NewRegistrar("none");

function INVENTORY_ONLY(name) {
    D(name, REG_THIRDPARTY, NO_NS);
}

Now we can list those domains are listed in dnsconfig.js as:

INVENTORY_ONLY("dnscontrol-azure.com");
INVENTORY_ONLY("example.com");
INVENTORY_ONLY("example2.com");

Now when I run dnscontrol print-ir | jq -r '.domains[].name' I get the list I want.